Index: trunk/src/com/drew/metadata/Directory.java
===================================================================
--- trunk/src/com/drew/metadata/Directory.java	(revision 6127)
+++ trunk/src/com/drew/metadata/Directory.java	(revision 8132)
@@ -1,4 +1,4 @@
 /*
- * Copyright 2002-2012 Drew Noakes
+ * Copyright 2002-2015 Drew Noakes
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,6 @@
  * More information about this project is available at:
  *
- *    http://drewnoakes.com/code/exif/
- *    http://code.google.com/p/metadata-extractor/
+ *    https://drewnoakes.com/code/exif/
+ *    https://github.com/drewnoakes/metadata-extractor
  */
 package com.drew.metadata;
@@ -37,10 +37,8 @@
  * data types.
  *
- * @author Drew Noakes http://drewnoakes.com
+ * @author Drew Noakes https://drewnoakes.com
  */
 public abstract class Directory
 {
-    // TODO get Array methods need to return cloned data, to maintain this directory's integrity
-
     /** Map of values hashed by type identifiers. */
     @NotNull
@@ -104,5 +102,5 @@
     public Collection<Tag> getTags()
     {
-        return _definedTagList;
+        return Collections.unmodifiableCollection(_definedTagList);
     }
 
@@ -158,5 +156,5 @@
     public Iterable<String> getErrors()
     {
-        return _errorList;
+        return Collections.unmodifiableCollection(_errorList);
     }
 
@@ -414,5 +412,7 @@
             return null;
 
-        if (o instanceof String) {
+        if (o instanceof Number) {
+            return ((Number)o).intValue();
+        } else if (o instanceof String) {
             try {
                 return Integer.parseInt((String)o);
@@ -428,6 +428,4 @@
                 return (int)val;
             }
-        } else if (o instanceof Number) {
-            return ((Number)o).intValue();
         } else if (o instanceof Rational[]) {
             Rational[] rationals = (Rational[])o;
@@ -498,4 +496,6 @@
         if (o == null)
             return null;
+        if (o instanceof int[])
+            return (int[])o;
         if (o instanceof Rational[]) {
             Rational[] rationals = (Rational[])o;
@@ -506,12 +506,17 @@
             return ints;
         }
-        if (o instanceof int[])
-            return (int[])o;
+        if (o instanceof short[]) {
+            short[] shorts = (short[])o;
+            int[] ints = new int[shorts.length];
+            for (int i = 0; i < shorts.length; i++) {
+                ints[i] = shorts[i];
+            }
+            return ints;
+        }
         if (o instanceof byte[]) {
             byte[] bytes = (byte[])o;
             int[] ints = new int[bytes.length];
             for (int i = 0; i < bytes.length; i++) {
-                byte b = bytes[i];
-                ints[i] = b;
+                ints[i] = bytes[i];
             }
             return ints;
@@ -527,5 +532,5 @@
         if (o instanceof Integer)
             return new int[] { (Integer)o };
-        
+
         return null;
     }
@@ -560,4 +565,11 @@
             }
             return bytes;
+        } else if (o instanceof short[]) {
+            short[] shorts = (short[])o;
+            byte[] bytes = new byte[shorts.length];
+            for (int i = 0; i < shorts.length; i++) {
+                bytes[i] = (byte)shorts[i];
+            }
+            return bytes;
         } else if (o instanceof CharSequence) {
             CharSequence str = (CharSequence)o;
@@ -703,5 +715,5 @@
     /**
      * Returns the specified tag's value as a java.util.Date.  If the value is unset or cannot be converted, <code>null</code> is returned.
-     * <p/>
+     * <p>
      * If the underlying value is a {@link String}, then attempts will be made to parse the string as though it is in
      * the current {@link TimeZone}.  If the {@link TimeZone} is known, call the overload that accepts one as an argument.
@@ -712,8 +724,8 @@
         return getDate(tagType, null);
     }
-    
+
     /**
      * Returns the specified tag's value as a java.util.Date.  If the value is unset or cannot be converted, <code>null</code> is returned.
-     * <p/>
+     * <p>
      * If the underlying value is a {@link String}, then attempts will be made to parse the string as though it is in
      * the {@link TimeZone} represented by the {@code timeZone} parameter (if it is non-null).  Note that this parameter
@@ -818,4 +830,5 @@
             boolean isLongArray = componentType.getName().equals("long");
             boolean isByteArray = componentType.getName().equals("byte");
+            boolean isShortArray = componentType.getName().equals("short");
             StringBuilder string = new StringBuilder();
             for (int i = 0; i < arrayLength; i++) {
@@ -826,4 +839,6 @@
                 else if (isIntArray)
                     string.append(Array.getInt(o, i));
+                else if (isShortArray)
+                    string.append(Array.getShort(o, i));
                 else if (isLongArray)
                     string.append(Array.getLong(o, i));
@@ -896,4 +911,15 @@
 
     /**
+     * Gets whether the specified tag is known by the directory and has a name.
+     *
+     * @param tagType the tag type identifier
+     * @return whether this directory has a name for the specified tag
+     */
+    public boolean hasTagName(int tagType)
+    {
+        return getTagNameMap().containsKey(tagType);
+    }
+
+    /**
      * Provides a description of a tag's value using the descriptor set by
      * <code>setDescriptor(Descriptor)</code>.
@@ -908,3 +934,14 @@
         return _descriptor.getDescription(tagType);
     }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s Directory (%d %s)",
+            getName(),
+            _tagMap.size(),
+            _tagMap.size() == 1
+                ? "tag"
+                : "tags");
+    }
 }
