Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/drew/metadata/Directory.java


1   /*
2    * Created by dnoakes on 25-Nov-2002 20:30:39 using IntelliJ IDEA.
3    */
4   package com.drew.metadata;
5   
6   import com.drew.lang.Rational;
7   
8   import java.lang.reflect.Array;
9   import java.text.DateFormat;
10  import java.util.*;
11  import java.io.Serializable;
12  
13  /**
14   * Base class for all Metadata directory types with supporting methods for setting and
15   * getting tag values.
16   */
17  public abstract class Directory implements Serializable
18  {
19      /**
20       * Map of values hashed by type identifiers.
21       */
22      protected final HashMap _tagMap;
23  
24      /**
25       * The descriptor used to interperet tag values.
26       */
27      protected TagDescriptor _descriptor;
28  
29      /**
30       * A convenient list holding tag values in the order in which they were stored.
31       * This is used for creation of an iterator, and for counting the number of
32       * defined tags.
33       */
34      protected final List _definedTagList;
35  
36      private List _errorList;
37  
38  // ABSTRACT METHODS
39  
40      /**
41       * Provides the name of the directory, for display purposes.  E.g. <code>Exif</code>
42       * @return the name of the directory
43       */
44      public abstract String getName();
45  
46      /**
47       * Provides the map of tag names, hashed by tag type identifier.
48       * @return the map of tag names
49       */
50      protected abstract HashMap getTagNameMap();
51  
52  // CONSTRUCTORS
53  
54      /**
55       * Creates a new Directory.
56       */
57      public Directory()
58      {
59          _tagMap = new HashMap();
60          _definedTagList = new ArrayList();
61      }
62  
63  // VARIOUS METHODS
64  
65      /**
66       * Indicates whether the specified tag type has been set.
67       * @param tagType the tag type to check for
68       * @return true if a value exists for the specified tag type, false if not
69       */
70      public boolean containsTag(int tagType)
71      {
72          return _tagMap.containsKey(new Integer(tagType));
73      }
74  
75      /**
76       * Returns an Iterator of Tag instances that have been set in this Directory.
77       * @return an Iterator of Tag instances
78       */
79      public Iterator getTagIterator()
80      {
81          return _definedTagList.iterator();
82      }
83  
84      /**
85       * Returns the number of tags set in this Directory.
86       * @return the number of tags set in this Directory
87       */
88      public int getTagCount()
89      {
90          return _definedTagList.size();
91      }
92  
93      /**
94       * Sets the descriptor used to interperet tag values.
95       * @param descriptor the descriptor used to interperet tag values
96       */
97      public void setDescriptor(TagDescriptor descriptor)
98      {
99          if (descriptor == null) {
100             throw new NullPointerException("cannot set a null descriptor");
101         }
102         _descriptor = descriptor;
103     }
104 
105     public void addError(String message)
106     {
107         if (_errorList==null) {
108             _errorList = new ArrayList();
109         }
110         _errorList.add(message);
111     }
112 
113     public boolean hasErrors()
114     {
115         return (_errorList!=null && _errorList.size() > 0);
116     }
117 
118     public Iterator getErrors()
119     {
120         return _errorList.iterator();
121     }
122 
123     public int getErrorCount()
124     {
125         return _errorList.size();
126     }
127 
128 // TAG SETTERS
129 
130     /**
131      * Sets an int value for the specified tag.
132      * @param tagType the tag's value as an int
133      * @param value the value for the specified tag as an int
134      */
135     public void setInt(int tagType, int value)
136     {
137         addObject(tagType, new Integer(value));
138     }
139 
140     /**
141      * Sets a double value for the specified tag.
142      * @param tagType the tag's value as an int
143      * @param value the value for the specified tag as a double
144      */
145     public void setDouble(int tagType, double value)
146     {
147         addObject(tagType, new Double(value));
148     }
149 
150     /**
151      * Sets a float value for the specified tag.
152      * @param tagType the tag's value as an int
153      * @param value the value for the specified tag as a float
154      */
155     public void setFloat(int tagType, float value)
156     {
157         addObject(tagType, new Float(value));
158     }
159 
160     /**
161      * Sets an int value for the specified tag.
162      * @param tagType the tag's value as an int
163      * @param value the value for the specified tag as a String
164      */
165     public void setString(int tagType, String value)
166     {
167         addObject(tagType, value);
168     }
169 
170     /**
171      * Sets an int value for the specified tag.
172      * @param tagType the tag's value as an int
173      * @param value the value for the specified tag as a boolean
174      */
175     public void setBoolean(int tagType, boolean value)
176     {
177         addObject(tagType, new Boolean(value));
178     }
179 
180     /**
181      * Sets a long value for the specified tag.
182      * @param tagType the tag's value as an int
183      * @param value the value for the specified tag as a long
184      */
185     public void setLong(int tagType, long value)
186     {
187         addObject(tagType, new Long(value));
188     }
189 
190     /**
191      * Sets a java.util.Date value for the specified tag.
192      * @param tagType the tag's value as an int
193      * @param value the value for the specified tag as a java.util.Date
194      */
195     public void setDate(int tagType, java.util.Date value)
196     {
197         addObject(tagType, value);
198     }
199 
200     /**
201      * Sets a Rational value for the specified tag.
202      * @param tagType the tag's value as an int
203      * @param rational rational number
204      */
205     public void setRational(int tagType, Rational rational)
206     {
207         addObject(tagType, rational);
208     }
209 
210     /**
211      * Sets a Rational array for the specified tag.
212      * @param tagType the tag identifier
213      * @param rationals the Rational array to store
214      */
215     public void setRationalArray(int tagType, Rational[] rationals)
216     {
217         addObjectArray(tagType, rationals);
218     }
219 
220     /**
221      * Sets an int array for the specified tag.
222      * @param tagType the tag identifier
223      * @param ints the int array to store
224      */
225     public void setIntArray(int tagType, int[] ints)
226     {
227         addObjectArray(tagType, ints);
228     }
229 
230     /**
231      * Sets a byte array for the specified tag.
232      * @param tagType the tag identifier
233      * @param bytes the byte array to store
234      */
235     public void setByteArray(int tagType, byte[] bytes)
236     {
237         addObjectArray(tagType, bytes);
238     }
239 
240     /**
241      * Sets a String array for the specified tag.
242      * @param tagType the tag identifier
243      * @param strings the String array to store
244      */
245     public void setStringArray(int tagType, String[] strings)
246     {
247         addObjectArray(tagType, strings);
248     }
249 
250     /**
251      * Private helper method, containing common functionality for all 'add'
252      * methods.
253      * @param tagType the tag's value as an int
254      * @param value the value for the specified tag
255      * @throws NullPointerException if value is <code>null</code>
256      */
257     private void addObject(int tagType, Object value)
258     {
259         if (value == null) {
260             throw new NullPointerException("cannot set a null object");
261         }
262         Integer key = new Integer(tagType);
263         if (!_tagMap.containsKey(key)) {
264             _definedTagList.add(new Tag(tagType, this));
265         }
266         _tagMap.put(key, value);
267     }
268 
269     /**
270      * Private helper method, containing common functionality for all 'add...Array'
271      * methods.
272      * @param tagType the tag's value as an int
273      * @param array the array of values for the specified tag
274      */
275     private void addObjectArray(int tagType, Object array)
276     {
277         // for now, we don't do anything special -- this method might be a candidate for removal once the dust settles
278         addObject(tagType, array);
279     }
280 
281 // TAG GETTERS
282 
283     /**
284      * Returns the specified tag's value as an int, if possible.
285      */
286     public int getInt(int tagType) throws MetadataException
287     {
288         Object o = getObject(tagType);
289         if (o == null) {
290             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
291         } else if (o instanceof String) {
292             try {
293                 return Integer.parseInt((String)o);
294             } catch (NumberFormatException nfe) {
295                 // convert the char array to an int
296                 String s = (String)o;
297                 int val = 0;
298                 for (int i = s.length() - 1; i >= 0; i--) {
299                     val += s.charAt(i) << (i * 8);
300                 }
301                 return val;
302             }
303         } else if (o instanceof Number) {
304             return ((Number)o).intValue();
305         }
306         throw new MetadataException("Requested tag cannot be cast to int");
307     }
308 
309     /**
310      * Gets the specified tag's value as a String array, if possible.  Only supported
311      * where the tag is set as String[], String, int[], byte[] or Rational[].
312      * @param tagType the tag identifier
313      * @return the tag's value as an array of Strings
314      * @throws MetadataException if the tag has not been set or cannot be represented
315      *         as a String[]
316      */
317     public String[] getStringArray(int tagType) throws MetadataException
318     {
319         Object o = getObject(tagType);
320         if (o == null) {
321             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
322         } else if (o instanceof String[]) {
323             return (String[])o;
324         } else if (o instanceof String) {
325             String[] strings = {(String)o};
326             return strings;
327         } else if (o instanceof int[]) {
328             int[] ints = (int[])o;
329             String[] strings = new String[ints.length];
330             for (int i = 0; i < strings.length; i++) {
331                 strings[i] = Integer.toString(ints[i]);
332             }
333             return strings;
334         } else if (o instanceof byte[]) {
335             byte[] bytes = (byte[])o;
336             String[] strings = new String[bytes.length];
337             for (int i = 0; i < strings.length; i++) {
338                 strings[i] = Byte.toString(bytes[i]);
339             }
340             return strings;
341         } else if (o instanceof Rational[]) {
342             Rational[] rationals = (Rational[])o;
343             String[] strings = new String[rationals.length];
344             for (int i = 0; i < strings.length; i++) {
345                 strings[i] = rationals[i].toSimpleString(false);
346             }
347             return strings;
348         }
349         throw new MetadataException("Requested tag cannot be cast to String array (" + o.getClass().toString() + ")");
350     }
351 
352     /**
353      * Gets the specified tag's value as an int array, if possible.  Only supported
354      * where the tag is set as String, int[], byte[] or Rational[].
355      * @param tagType the tag identifier
356      * @return the tag's value as an int array
357      * @throws MetadataException if the tag has not been set, or cannot be converted to
358      *         an int array
359      */
360     public int[] getIntArray(int tagType) throws MetadataException
361     {
362         Object o = getObject(tagType);
363         if (o == null) {
364             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
365         } else if (o instanceof Rational[]) {
366             Rational[] rationals = (Rational[])o;
367             int[] ints = new int[rationals.length];
368             for (int i = 0; i < ints.length; i++) {
369                 ints[i] = rationals[i].intValue();
370             }
371             return ints;
372         } else if (o instanceof int[]) {
373             return (int[])o;
374         } else if (o instanceof byte[]) {
375             byte[] bytes = (byte[])o;
376             int[] ints = new int[bytes.length];
377             for (int i = 0; i < bytes.length; i++) {
378                 byte b = bytes[i];
379                 ints[i] = b;
380             }
381             return ints;
382         } else if (o instanceof String) {
383             String str = (String)o;
384             int[] ints = new int[str.length()];
385             for (int i = 0; i < str.length(); i++) {
386                 ints[i] = str.charAt(i);
387             }
388             return ints;
389         }
390         throw new MetadataException("Requested tag cannot be cast to int array (" + o.getClass().toString() + ")");
391     }
392 
393     /**
394      * Gets the specified tag's value as an byte array, if possible.  Only supported
395      * where the tag is set as String, int[], byte[] or Rational[].
396      * @param tagType the tag identifier
397      * @return the tag's value as a byte array
398      * @throws MetadataException if the tag has not been set, or cannot be converted to
399      *         a byte array
400      */
401     public byte[] getByteArray(int tagType) throws MetadataException
402     {
403         Object o = getObject(tagType);
404         if (o == null) {
405             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
406         } else if (o instanceof Rational[]) {
407             Rational[] rationals = (Rational[])o;
408             byte[] bytes = new byte[rationals.length];
409             for (int i = 0; i < bytes.length; i++) {
410                 bytes[i] = rationals[i].byteValue();
411             }
412             return bytes;
413         } else if (o instanceof byte[]) {
414             return (byte[])o;
415         } else if (o instanceof int[]) {
416             int[] ints = (int[])o;
417             byte[] bytes = new byte[ints.length];
418             for (int i = 0; i < ints.length; i++) {
419                 bytes[i] = (byte)ints[i];
420             }
421             return bytes;
422         } else if (o instanceof String) {
423             String str = (String)o;
424             byte[] bytes = new byte[str.length()];
425             for (int i = 0; i < str.length(); i++) {
426                 bytes[i] = (byte)str.charAt(i);
427             }
428             return bytes;
429         }
430         throw new MetadataException("Requested tag cannot be cast to byte array (" + o.getClass().toString() + ")");
431     }
432 
433     /**
434      * Returns the specified tag's value as a double, if possible.
435      */
436     public double getDouble(int tagType) throws MetadataException
437     {
438         Object o = getObject(tagType);
439         if (o == null) {
440             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
441         } else if (o instanceof String) {
442             try {
443                 return Double.parseDouble((String)o);
444             } catch (NumberFormatException nfe) {
445                 throw new MetadataException("unable to parse string " + o + " as a double", nfe);
446             }
447         } else if (o instanceof Number) {
448             return ((Number)o).doubleValue();
449         }
450         throw new MetadataException("Requested tag cannot be cast to double");
451     }
452 
453     /**
454      * Returns the specified tag's value as a float, if possible.
455      */
456     public float getFloat(int tagType) throws MetadataException
457     {
458         Object o = getObject(tagType);
459         if (o == null) {
460             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
461         } else if (o instanceof String) {
462             try {
463                 return Float.parseFloat((String)o);
464             } catch (NumberFormatException nfe) {
465                 throw new MetadataException("unable to parse string " + o + " as a float", nfe);
466             }
467         } else if (o instanceof Number) {
468             return ((Number)o).floatValue();
469         }
470         throw new MetadataException("Requested tag cannot be cast to float");
471     }
472 
473     /**
474      * Returns the specified tag's value as a long, if possible.
475      */
476     public long getLong(int tagType) throws MetadataException
477     {
478         Object o = getObject(tagType);
479         if (o == null) {
480             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
481         } else if (o instanceof String) {
482             try {
483                 return Long.parseLong((String)o);
484             } catch (NumberFormatException nfe) {
485                 throw new MetadataException("unable to parse string " + o + " as a long", nfe);
486             }
487         } else if (o instanceof Number) {
488             return ((Number)o).longValue();
489         }
490         throw new MetadataException("Requested tag cannot be cast to long");
491     }
492 
493     /**
494      * Returns the specified tag's value as a boolean, if possible.
495      */
496     public boolean getBoolean(int tagType) throws MetadataException
497     {
498         Object o = getObject(tagType);
499         if (o == null) {
500             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
501         } else if (o instanceof Boolean) {
502             return ((Boolean)o).booleanValue();
503         } else if (o instanceof String) {
504             try {
505                 return Boolean.getBoolean((String)o);
506             } catch (NumberFormatException nfe) {
507                 throw new MetadataException("unable to parse string " + o + " as a boolean", nfe);
508             }
509         } else if (o instanceof Number) {
510             return (((Number)o).doubleValue() != 0);
511         }
512         throw new MetadataException("Requested tag cannot be cast to boolean");
513     }
514 
515     /**
516      * Returns the specified tag's value as a java.util.Date, if possible.
517      */
518     public java.util.Date getDate(int tagType) throws MetadataException
519     {
520         Object o = getObject(tagType);
521         if (o == null) {
522             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
523         } else if (o instanceof java.util.Date) {
524             return (java.util.Date)o;
525         } else if (o instanceof String) {
526             String datePatterns[] = {
527                 "yyyy:MM:dd hh:mm:ss",
528                 "yyyy:MM:dd hh:mm",
529                 "yyyy-MM-dd hh:mm:ss",
530                 "yyyy-MM-dd hh:mm"}; // Try these patterns. Add new to make this method even smarter
531             String dateString = (String)o;
532             for (int i = 0; i < datePatterns.length; i++) {
533                 try {
534                     DateFormat parser = new java.text.SimpleDateFormat(datePatterns[i]);
535                     return parser.parse(dateString);
536                 } catch (java.text.ParseException ex) {
537                     // simply try the next pattern
538                 }
539             }
540         }
541         throw new MetadataException("Requested tag cannot be cast to java.util.Date");
542     }
543 
544     /**
545      * Returns the specified tag's value as a Rational, if possible.
546      */
547     public Rational getRational(int tagType) throws MetadataException
548     {
549         Object o = getObject(tagType);
550         if (o == null) {
551             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
552         } else if (o instanceof Rational) {
553             return (Rational)o;
554         }
555         throw new MetadataException("Requested tag cannot be cast to Rational");
556     }
557 
558     public Rational[] getRationalArray(int tagType) throws MetadataException
559     {
560         Object o = getObject(tagType);
561         if (o == null) {
562             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
563         } else if (o instanceof Rational[]) {
564             return (Rational[])o;
565         }
566         throw new MetadataException("Requested tag cannot be cast to Rational array (" + o.getClass().toString() + ")");
567     }
568 
569     /**
570      * Returns the specified tag's value as a String.  In many cases, more
571      * presentable values will be obtained from getDescription(int).
572      * @return the String reprensentation of the tag's value, or
573      *         <code>null</code> if the tag hasn't been defined.
574      */
575     public String getString(int tagType)
576     {
577         // TODO handle types other than Rational[], Object[] and int[] here...
578         Object o = getObject(tagType);
579         if (o == null) {
580             return null;
581         } else if (o instanceof Rational) {
582             return ((Rational)o).toSimpleString(true);
583         } else if (o.getClass().isArray()) {
584             int arrayLength = Array.getLength(o);
585             // determine if this is an array of objects i.e. [Lcom.drew.blah
586             boolean isObjectArray = o.getClass().toString().startsWith("class [L");
587             StringBuffer sbuffer = new StringBuffer();
588             for (int i = 0; i < arrayLength; i++) {
589                 if (i != 0) {
590                     sbuffer.append(' ');
591                 }
592                 if (isObjectArray) {
593                     sbuffer.append(Array.get(o, i).toString());
594                 } else {
595                     sbuffer.append(Array.getInt(o, i));
596                 }
597             }
598             return sbuffer.toString();
599         } else {
600             return o.toString();
601         }
602     }
603 
604     /**
605      * Returns the object hashed for the particular tag type specified, if available.
606      * @param tagType the tag type identifier
607      * @return the tag's value as an Object if available, else null
608      */
609     public Object getObject(int tagType)
610     {
611         return _tagMap.get(new Integer(tagType));
612     }
613 
614 // OTHER METHODS
615 
616     /**
617      * Returns the name of a specified tag as a String.
618      * @param tagType the tag type identifier
619      * @return the tag's name as a String
620      */
621     public String getTagName(int tagType)
622     {
623         Integer key = new Integer(tagType);
624         HashMap nameMap = getTagNameMap();
625         if (!nameMap.containsKey(key)) {
626             String hex = Integer.toHexString(tagType);
627             while (hex.length() < 4) {
628                 hex = "0" + hex;
629             }
630             return "Unknown tag (0x" + hex + ")";
631         }
632         return (String)nameMap.get(key);
633     }
634 
635     /**
636      * Provides a description of a tag's value using the descriptor set by
637      * <code>setDescriptor(Descriptor)</code>.
638      * @param tagType the tag type identifier
639      * @return the tag value's description as a String
640      * @throws MetadataException if a descriptor hasn't been set, or if an error
641      * occurs during calculation of the description within the Descriptor
642      */
643     public String getDescription(int tagType) throws MetadataException
644     {
645         if (_descriptor == null) {
646             throw new MetadataException("a descriptor must be set using setDescriptor(...) before descriptions can be provided");
647         }
648         return _descriptor.getDescription(tagType);
649     }
650 }