Changeset 6127 in josm for trunk/src/com/drew/metadata/Directory.java
- Timestamp:
- 2013-08-09T18:05:11+02:00 (13 years ago)
- File:
-
- 1 edited
-
trunk/src/com/drew/metadata/Directory.java (modified) (15 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/com/drew/metadata/Directory.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 25-Nov-2002 20:30:39 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata; 18 22 19 23 import com.drew.lang.Rational; 20 21 import java.io.Serializable; 24 import com.drew.lang.annotations.NotNull; 25 import com.drew.lang.annotations.Nullable; 26 import com.drew.lang.annotations.SuppressWarnings; 27 28 import java.io.UnsupportedEncodingException; 22 29 import java.lang.reflect.Array; 23 30 import java.text.DateFormat; 24 import java.util.ArrayList; 25 import java.util.HashMap; 26 import java.util.Iterator; 27 import java.util.List; 31 import java.text.ParseException; 32 import java.text.SimpleDateFormat; 33 import java.util.*; 28 34 29 35 /** 30 * Base class for all Metadata directory types with supporting methods for setting and 31 * getting tag values. 36 * Abstract base class for all directory implementations, having methods for getting and setting tag values of various 37 * data types. 38 * 39 * @author Drew Noakes http://drewnoakes.com 32 40 */ 33 public abstract class Directory implements Serializable41 public abstract class Directory 34 42 { 35 /** 36 * Map of values hashed by type identifiers. 37 */ 38 protected final HashMap _tagMap; 39 40 /** 41 * The descriptor used to interperet tag values. 42 */ 43 protected TagDescriptor _descriptor; 43 // TODO get Array methods need to return cloned data, to maintain this directory's integrity 44 45 /** Map of values hashed by type identifiers. */ 46 @NotNull 47 protected final Map<Integer, Object> _tagMap = new HashMap<Integer, Object>(); 44 48 45 49 /** … … 48 52 * defined tags. 49 53 */ 50 protected final List _definedTagList; 51 52 private List _errorList; 54 @NotNull 55 protected final Collection<Tag> _definedTagList = new ArrayList<Tag>(); 56 57 @NotNull 58 private final Collection<String> _errorList = new ArrayList<String>(4); 59 60 /** The descriptor used to interpret tag values. */ 61 protected TagDescriptor _descriptor; 53 62 54 63 // ABSTRACT METHODS … … 56 65 /** 57 66 * Provides the name of the directory, for display purposes. E.g. <code>Exif</code> 67 * 58 68 * @return the name of the directory 59 69 */ 70 @NotNull 60 71 public abstract String getName(); 61 72 62 73 /** 63 74 * Provides the map of tag names, hashed by tag type identifier. 75 * 64 76 * @return the map of tag names 65 77 */ 66 protected abstract HashMap getTagNameMap(); 67 68 // CONSTRUCTORS 69 70 /** 71 * Creates a new Directory. 72 */ 73 public Directory() 74 { 75 _tagMap = new HashMap(); 76 _definedTagList = new ArrayList(); 77 } 78 @NotNull 79 protected abstract HashMap<Integer, String> getTagNameMap(); 80 81 protected Directory() 82 {} 78 83 79 84 // VARIOUS METHODS … … 81 86 /** 82 87 * Indicates whether the specified tag type has been set. 88 * 83 89 * @param tagType the tag type to check for 84 90 * @return true if a value exists for the specified tag type, false if not 85 91 */ 92 @java.lang.SuppressWarnings({ "UnnecessaryBoxing" }) 86 93 public boolean containsTag(int tagType) 87 94 { 88 return _tagMap.containsKey( newInteger(tagType));95 return _tagMap.containsKey(Integer.valueOf(tagType)); 89 96 } 90 97 91 98 /** 92 99 * Returns an Iterator of Tag instances that have been set in this Directory. 100 * 93 101 * @return an Iterator of Tag instances 94 102 */ 95 public Iterator getTagIterator() 96 { 97 return _definedTagList.iterator(); 103 @NotNull 104 public Collection<Tag> getTags() 105 { 106 return _definedTagList; 98 107 } 99 108 100 109 /** 101 110 * Returns the number of tags set in this Directory. 111 * 102 112 * @return the number of tags set in this Directory 103 113 */ … … 108 118 109 119 /** 110 * Sets the descriptor used to interperet tag values. 111 * @param descriptor the descriptor used to interperet tag values 112 */ 113 public void setDescriptor(TagDescriptor descriptor) 114 { 115 if (descriptor==null) { 120 * Sets the descriptor used to interpret tag values. 121 * 122 * @param descriptor the descriptor used to interpret tag values 123 */ 124 @java.lang.SuppressWarnings({ "ConstantConditions" }) 125 public void setDescriptor(@NotNull TagDescriptor descriptor) 126 { 127 if (descriptor == null) 116 128 throw new NullPointerException("cannot set a null descriptor"); 117 }118 129 _descriptor = descriptor; 119 130 } 120 131 121 public void addError(String message) 122 { 123 if (_errorList==null) { 124 _errorList = new ArrayList(); 125 } 132 /** 133 * Registers an error message with this directory. 134 * 135 * @param message an error message. 136 */ 137 public void addError(@NotNull String message) 138 { 126 139 _errorList.add(message); 127 140 } 128 141 142 /** 143 * Gets a value indicating whether this directory has any error messages. 144 * 145 * @return true if the directory contains errors, otherwise false 146 */ 129 147 public boolean hasErrors() 130 148 { 131 return (_errorList!=null && _errorList.size()>0); 132 } 133 134 public Iterator getErrors() 135 { 136 return _errorList.iterator(); 137 } 138 149 return _errorList.size() > 0; 150 } 151 152 /** 153 * Used to iterate over any error messages contained in this directory. 154 * 155 * @return an iterable collection of error message strings. 156 */ 157 @NotNull 158 public Iterable<String> getErrors() 159 { 160 return _errorList; 161 } 162 163 /** Returns the count of error messages in this directory. */ 139 164 public int getErrorCount() 140 165 { … … 145 170 146 171 /** 147 * Sets an int value for the specified tag. 172 * Sets an <code>int</code> value for the specified tag. 173 * 148 174 * @param tagType the tag's value as an int 149 * @param value the value for the specified tag as an int 175 * @param value the value for the specified tag as an int 150 176 */ 151 177 public void setInt(int tagType, int value) 152 178 { 153 setObject(tagType, new Integer(value)); 154 } 155 156 /** 157 * Sets a double value for the specified tag. 179 setObject(tagType, value); 180 } 181 182 /** 183 * Sets an <code>int[]</code> (array) for the specified tag. 184 * 185 * @param tagType the tag identifier 186 * @param ints the int array to store 187 */ 188 public void setIntArray(int tagType, @NotNull int[] ints) 189 { 190 setObjectArray(tagType, ints); 191 } 192 193 /** 194 * Sets a <code>float</code> value for the specified tag. 195 * 158 196 * @param tagType the tag's value as an int 159 * @param value the value for the specified tag as a double 197 * @param value the value for the specified tag as a float 198 */ 199 public void setFloat(int tagType, float value) 200 { 201 setObject(tagType, value); 202 } 203 204 /** 205 * Sets a <code>float[]</code> (array) for the specified tag. 206 * 207 * @param tagType the tag identifier 208 * @param floats the float array to store 209 */ 210 public void setFloatArray(int tagType, @NotNull float[] floats) 211 { 212 setObjectArray(tagType, floats); 213 } 214 215 /** 216 * Sets a <code>double</code> value for the specified tag. 217 * 218 * @param tagType the tag's value as an int 219 * @param value the value for the specified tag as a double 160 220 */ 161 221 public void setDouble(int tagType, double value) 162 222 { 163 setObject(tagType, new Double(value)); 164 } 165 166 /** 167 * Sets a float value for the specified tag. 223 setObject(tagType, value); 224 } 225 226 /** 227 * Sets a <code>double[]</code> (array) for the specified tag. 228 * 229 * @param tagType the tag identifier 230 * @param doubles the double array to store 231 */ 232 public void setDoubleArray(int tagType, @NotNull double[] doubles) 233 { 234 setObjectArray(tagType, doubles); 235 } 236 237 /** 238 * Sets a <code>String</code> value for the specified tag. 239 * 168 240 * @param tagType the tag's value as an int 169 * @param value the value for the specified tag as a float 170 */ 171 public void setFloat(int tagType, float value) 172 { 173 setObject(tagType, new Float(value)); 174 } 175 176 /** 177 * Sets an int value for the specified tag. 178 * @param tagType the tag's value as an int 179 * @param value the value for the specified tag as a String 180 */ 181 public void setString(int tagType, String value) 182 { 241 * @param value the value for the specified tag as a String 242 */ 243 @java.lang.SuppressWarnings({ "ConstantConditions" }) 244 public void setString(int tagType, @NotNull String value) 245 { 246 if (value == null) 247 throw new NullPointerException("cannot set a null String"); 183 248 setObject(tagType, value); 184 249 } 185 250 186 251 /** 187 * Sets an int value for the specified tag. 188 * @param tagType the tag's value as an int 189 * @param value the value for the specified tag as a boolean 190 */ 191 public void setBoolean(int tagType, boolean value) 192 { 193 setObject(tagType, new Boolean(value)); 194 } 195 196 /** 197 * Sets a long value for the specified tag. 198 * @param tagType the tag's value as an int 199 * @param value the value for the specified tag as a long 200 */ 201 public void setLong(int tagType, long value) 202 { 203 setObject(tagType, new Long(value)); 204 } 205 206 /** 207 * Sets a java.util.Date value for the specified tag. 208 * @param tagType the tag's value as an int 209 * @param value the value for the specified tag as a java.util.Date 210 */ 211 public void setDate(int tagType, java.util.Date value) 212 { 213 setObject(tagType, value); 214 } 215 216 /** 217 * Sets a Rational value for the specified tag. 218 * @param tagType the tag's value as an int 219 * @param rational rational number 220 */ 221 public void setRational(int tagType, Rational rational) 222 { 223 setObject(tagType, rational); 224 } 225 226 /** 227 * Sets a Rational array for the specified tag. 228 * @param tagType the tag identifier 229 * @param rationals the Rational array to store 230 */ 231 public void setRationalArray(int tagType, Rational[] rationals) 232 { 233 setObjectArray(tagType, rationals); 234 } 235 236 /** 237 * Sets an int array for the specified tag. 238 * @param tagType the tag identifier 239 * @param ints the int array to store 240 */ 241 public void setIntArray(int tagType, int[] ints) 242 { 243 setObjectArray(tagType, ints); 244 } 245 246 /** 247 * Sets a byte array for the specified tag. 248 * @param tagType the tag identifier 249 * @param bytes the byte array to store 250 */ 251 public void setByteArray(int tagType, byte[] bytes) 252 { 253 setObjectArray(tagType, bytes); 254 } 255 256 /** 257 * Sets a String array for the specified tag. 252 * Sets a <code>String[]</code> (array) for the specified tag. 253 * 258 254 * @param tagType the tag identifier 259 255 * @param strings the String array to store 260 256 */ 261 public void setStringArray(int tagType, String[] strings) 257 public void setStringArray(int tagType, @NotNull String[] strings) 262 258 { 263 259 setObjectArray(tagType, strings); … … 265 261 266 262 /** 267 * Private helper method, containing common functionality for all 'add'268 * methods.263 * Sets a <code>boolean</code> value for the specified tag. 264 * 269 265 * @param tagType the tag's value as an int 270 * @param value the value for the specified tag 266 * @param value the value for the specified tag as a boolean 267 */ 268 public void setBoolean(int tagType, boolean value) 269 { 270 setObject(tagType, value); 271 } 272 273 /** 274 * Sets a <code>long</code> value for the specified tag. 275 * 276 * @param tagType the tag's value as an int 277 * @param value the value for the specified tag as a long 278 */ 279 public void setLong(int tagType, long value) 280 { 281 setObject(tagType, value); 282 } 283 284 /** 285 * Sets a <code>java.util.Date</code> value for the specified tag. 286 * 287 * @param tagType the tag's value as an int 288 * @param value the value for the specified tag as a java.util.Date 289 */ 290 public void setDate(int tagType, @NotNull java.util.Date value) 291 { 292 setObject(tagType, value); 293 } 294 295 /** 296 * Sets a <code>Rational</code> value for the specified tag. 297 * 298 * @param tagType the tag's value as an int 299 * @param rational rational number 300 */ 301 public void setRational(int tagType, @NotNull Rational rational) 302 { 303 setObject(tagType, rational); 304 } 305 306 /** 307 * Sets a <code>Rational[]</code> (array) for the specified tag. 308 * 309 * @param tagType the tag identifier 310 * @param rationals the Rational array to store 311 */ 312 public void setRationalArray(int tagType, @NotNull Rational[] rationals) 313 { 314 setObjectArray(tagType, rationals); 315 } 316 317 /** 318 * Sets a <code>byte[]</code> (array) for the specified tag. 319 * 320 * @param tagType the tag identifier 321 * @param bytes the byte array to store 322 */ 323 public void setByteArray(int tagType, @NotNull byte[] bytes) 324 { 325 setObjectArray(tagType, bytes); 326 } 327 328 /** 329 * Sets a <code>Object</code> for the specified tag. 330 * 331 * @param tagType the tag's value as an int 332 * @param value the value for the specified tag 271 333 * @throws NullPointerException if value is <code>null</code> 272 334 */ 273 public void setObject(int tagType, Object value) 274 { 275 if (value==null) { 335 @java.lang.SuppressWarnings( { "ConstantConditions", "UnnecessaryBoxing" }) 336 public void setObject(int tagType, @NotNull Object value) 337 { 338 if (value == null) 276 339 throw new NullPointerException("cannot set a null object"); 277 } 278 279 Integer key = new Integer(tagType); 280 if (!_tagMap.containsKey(key)) { 340 341 if (!_tagMap.containsKey(Integer.valueOf(tagType))) { 281 342 _definedTagList.add(new Tag(tagType, this)); 282 343 } 283 _tagMap.put(key, value); 284 } 285 286 /** 287 * Private helper method, containing common functionality for all 'add...Array' 288 * methods. 344 // else { 345 // final Object oldValue = _tagMap.get(tagType); 346 // if (!oldValue.equals(value)) 347 // addError(String.format("Overwritten tag 0x%s (%s). Old=%s, New=%s", Integer.toHexString(tagType), getTagName(tagType), oldValue, value)); 348 // } 349 _tagMap.put(tagType, value); 350 } 351 352 /** 353 * Sets an array <code>Object</code> for the specified tag. 354 * 289 355 * @param tagType the tag's value as an int 290 * @param array the array of values for the specified tag 291 */ 292 public void setObjectArray(int tagType, Object array) 356 * @param array the array of values for the specified tag 357 */ 358 public void setObjectArray(int tagType, @NotNull Object array) 293 359 { 294 360 // for now, we don't do anything special -- this method might be a candidate for removal once the dust settles … … 299 365 300 366 /** 301 * Returns the specified tag's value as an int, if possible. 367 * Returns the specified tag's value as an int, if possible. Every attempt to represent the tag's value as an int 368 * is taken. Here is a list of the action taken depending upon the tag's original type: 369 * <ul> 370 * <li> int - Return unchanged. 371 * <li> Number - Return an int value (real numbers are truncated). 372 * <li> Rational - Truncate any fractional part and returns remaining int. 373 * <li> String - Attempt to parse string as an int. If this fails, convert the char[] to an int (using shifts and OR). 374 * <li> Rational[] - Return int value of first item in array. 375 * <li> byte[] - Return int value of first item in array. 376 * <li> int[] - Return int value of first item in array. 377 * </ul> 378 * 379 * @throws MetadataException if no value exists for tagType or if it cannot be converted to an int. 302 380 */ 303 381 public int getInt(int tagType) throws MetadataException 304 382 { 305 Object o = getObject(tagType); 306 if (o==null) { 307 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 308 } else if (o instanceof String) { 383 Integer integer = getInteger(tagType); 384 if (integer!=null) 385 return integer; 386 387 Object o = getObject(tagType); 388 if (o == null) 389 throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first"); 390 throw new MetadataException("Tag '" + tagType + "' cannot be converted to int. It is of type '" + o.getClass() + "'."); 391 } 392 393 /** 394 * Returns the specified tag's value as an Integer, if possible. Every attempt to represent the tag's value as an 395 * Integer is taken. Here is a list of the action taken depending upon the tag's original type: 396 * <ul> 397 * <li> int - Return unchanged 398 * <li> Number - Return an int value (real numbers are truncated) 399 * <li> Rational - Truncate any fractional part and returns remaining int 400 * <li> String - Attempt to parse string as an int. If this fails, convert the char[] to an int (using shifts and OR) 401 * <li> Rational[] - Return int value of first item in array if length > 0 402 * <li> byte[] - Return int value of first item in array if length > 0 403 * <li> int[] - Return int value of first item in array if length > 0 404 * </ul> 405 * 406 * If the value is not found or cannot be converted to int, <code>null</code> is returned. 407 */ 408 @Nullable 409 public Integer getInteger(int tagType) 410 { 411 Object o = getObject(tagType); 412 413 if (o == null) 414 return null; 415 416 if (o instanceof String) { 309 417 try { 310 418 return Integer.parseInt((String)o); … … 314 422 byte[] bytes = s.getBytes(); 315 423 long val = 0; 316 for ( int i = 0; i < bytes.length; i++) {424 for (byte aByte : bytes) { 317 425 val = val << 8; 318 val += bytes[i];426 val += (aByte & 0xff); 319 427 } 320 428 return (int)val; … … 324 432 } else if (o instanceof Rational[]) { 325 433 Rational[] rationals = (Rational[])o; 326 if (rationals.length ==1)434 if (rationals.length == 1) 327 435 return rationals[0].intValue(); 328 436 } else if (o instanceof byte[]) { 329 437 byte[] bytes = (byte[])o; 330 if (bytes.length ==1)331 return bytes[0]; 438 if (bytes.length == 1) 439 return (int)bytes[0]; 332 440 } else if (o instanceof int[]) { 333 441 int[] ints = (int[])o; 334 if (ints.length ==1)442 if (ints.length == 1) 335 443 return ints[0]; 336 444 } 337 throw new MetadataException("Tag '" + tagType + "' cannot be cast to int. It is of type '" + o.getClass() + "'."); 338 } 339 340 // TODO get Array methods need to return cloned data, to maintain this directory's integrity 445 return null; 446 } 341 447 342 448 /** 343 449 * Gets the specified tag's value as a String array, if possible. Only supported 344 450 * where the tag is set as String[], String, int[], byte[] or Rational[]. 451 * 345 452 * @param tagType the tag identifier 346 * @return the tag's value as an array of Strings 347 * @throws MetadataException if the tag has not been set or cannot be represented 348 * as a String[] 349 */ 350 public String[] getStringArray(int tagType) throws MetadataException 351 { 352 Object o = getObject(tagType); 353 if (o==null) { 354 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 355 } else if (o instanceof String[]) { 453 * @return the tag's value as an array of Strings. If the value is unset or cannot be converted, <code>null</code> is returned. 454 */ 455 @Nullable 456 public String[] getStringArray(int tagType) 457 { 458 Object o = getObject(tagType); 459 if (o == null) 460 return null; 461 if (o instanceof String[]) 356 462 return (String[])o; 357 } else if (o instanceof String) { 358 String[] strings = {(String)o}; 359 return strings; 360 } else if (o instanceof int[]) { 463 if (o instanceof String) 464 return new String[] { (String)o }; 465 if (o instanceof int[]) { 361 466 int[] ints = (int[])o; 362 467 String[] strings = new String[ints.length]; 363 for (int i = 0; i <strings.length; i++){468 for (int i = 0; i < strings.length; i++) 364 469 strings[i] = Integer.toString(ints[i]); 365 }366 470 return strings; 367 471 } else if (o instanceof byte[]) { 368 472 byte[] bytes = (byte[])o; 369 473 String[] strings = new String[bytes.length]; 370 for (int i = 0; i <strings.length; i++){474 for (int i = 0; i < strings.length; i++) 371 475 strings[i] = Byte.toString(bytes[i]); 372 }373 476 return strings; 374 477 } else if (o instanceof Rational[]) { 375 478 Rational[] rationals = (Rational[])o; 376 479 String[] strings = new String[rationals.length]; 377 for (int i = 0; i <strings.length; i++){480 for (int i = 0; i < strings.length; i++) 378 481 strings[i] = rationals[i].toSimpleString(false); 379 }380 482 return strings; 381 483 } 382 throw new MetadataException("Tag '" + tagType + "' cannot be cast to an String array. It is of type '" + o.getClass() + "'.");484 return null; 383 485 } 384 486 385 487 /** 386 488 * Gets the specified tag's value as an int array, if possible. Only supported 387 * where the tag is set as String, int[], byte[] or Rational[]. 489 * where the tag is set as String, Integer, int[], byte[] or Rational[]. 490 * 388 491 * @param tagType the tag identifier 389 492 * @return the tag's value as an int array 390 * @throws MetadataException if the tag has not been set, or cannot be converted to 391 * an int array 392 */ 393 public int[] getIntArray(int tagType) throws MetadataException 394 { 395 Object o = getObject(tagType); 396 if (o==null) { 397 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 398 } else if (o instanceof Rational[]) { 493 */ 494 @Nullable 495 public int[] getIntArray(int tagType) 496 { 497 Object o = getObject(tagType); 498 if (o == null) 499 return null; 500 if (o instanceof Rational[]) { 399 501 Rational[] rationals = (Rational[])o; 400 502 int[] ints = new int[rationals.length]; 401 for (int i = 0; i <ints.length; i++) {503 for (int i = 0; i < ints.length; i++) { 402 504 ints[i] = rationals[i].intValue(); 403 505 } 404 506 return ints; 405 } else if (o instanceof int[]) { 507 } 508 if (o instanceof int[]) 406 509 return (int[])o; 407 } elseif (o instanceof byte[]) {510 if (o instanceof byte[]) { 408 511 byte[] bytes = (byte[])o; 409 512 int[] ints = new int[bytes.length]; 410 for (int i = 0; i <bytes.length; i++) {513 for (int i = 0; i < bytes.length; i++) { 411 514 byte b = bytes[i]; 412 515 ints[i] = b; 413 516 } 414 517 return ints; 415 } else if (o instanceof String) { 416 String str = (String)o; 518 } 519 if (o instanceof CharSequence) { 520 CharSequence str = (CharSequence)o; 417 521 int[] ints = new int[str.length()]; 418 for (int i = 0; i <str.length(); i++) {522 for (int i = 0; i < str.length(); i++) { 419 523 ints[i] = str.charAt(i); 420 524 } 421 525 return ints; 422 526 } 423 throw new MetadataException("Tag '" + tagType + "' cannot be cast to an int array. It is of type '" + o.getClass() + "'."); 527 if (o instanceof Integer) 528 return new int[] { (Integer)o }; 529 530 return null; 424 531 } 425 532 426 533 /** 427 534 * Gets the specified tag's value as an byte array, if possible. Only supported 428 * where the tag is set as String, int[], byte[] or Rational[]. 535 * where the tag is set as String, Integer, int[], byte[] or Rational[]. 536 * 429 537 * @param tagType the tag identifier 430 538 * @return the tag's value as a byte array 431 * @throws MetadataException if the tag has not been set, or cannot be converted to 432 * a byte array 433 */ 434 public byte[] getByteArray(int tagType) throws MetadataException 435 { 436 Object o = getObject(tagType); 437 if (o==null) { 438 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 539 */ 540 @Nullable 541 public byte[] getByteArray(int tagType) 542 { 543 Object o = getObject(tagType); 544 if (o == null) { 545 return null; 439 546 } else if (o instanceof Rational[]) { 440 547 Rational[] rationals = (Rational[])o; 441 548 byte[] bytes = new byte[rationals.length]; 442 for (int i = 0; i <bytes.length; i++) {549 for (int i = 0; i < bytes.length; i++) { 443 550 bytes[i] = rationals[i].byteValue(); 444 551 } … … 449 556 int[] ints = (int[])o; 450 557 byte[] bytes = new byte[ints.length]; 451 for (int i = 0; i <ints.length; i++) {558 for (int i = 0; i < ints.length; i++) { 452 559 bytes[i] = (byte)ints[i]; 453 560 } 454 561 return bytes; 455 } else if (o instanceof String) {456 Stringstr = (String)o;562 } else if (o instanceof CharSequence) { 563 CharSequence str = (CharSequence)o; 457 564 byte[] bytes = new byte[str.length()]; 458 for (int i = 0; i <str.length(); i++) {565 for (int i = 0; i < str.length(); i++) { 459 566 bytes[i] = (byte)str.charAt(i); 460 567 } 461 568 return bytes; 462 569 } 463 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a byte array. It is of type '" + o.getClass() + "'."); 464 } 465 466 /** 467 * Returns the specified tag's value as a double, if possible. 468 */ 570 if (o instanceof Integer) 571 return new byte[] { ((Integer)o).byteValue() }; 572 573 return null; 574 } 575 576 /** Returns the specified tag's value as a double, if possible. */ 469 577 public double getDouble(int tagType) throws MetadataException 470 578 { 471 Object o = getObject(tagType); 472 if (o==null) { 473 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 474 } else if (o instanceof String) { 579 Double value = getDoubleObject(tagType); 580 if (value!=null) 581 return value; 582 Object o = getObject(tagType); 583 if (o == null) 584 throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first"); 585 throw new MetadataException("Tag '" + tagType + "' cannot be converted to a double. It is of type '" + o.getClass() + "'."); 586 } 587 /** Returns the specified tag's value as a Double. If the tag is not set or cannot be converted, <code>null</code> is returned. */ 588 @Nullable 589 public Double getDoubleObject(int tagType) 590 { 591 Object o = getObject(tagType); 592 if (o == null) 593 return null; 594 if (o instanceof String) { 475 595 try { 476 596 return Double.parseDouble((String)o); 477 597 } catch (NumberFormatException nfe) { 478 throw new MetadataException("unable to parse string " + o + " as a double", nfe); 479 } 480 } else if (o instanceof Number) { 598 return null; 599 } 600 } 601 if (o instanceof Number) 481 602 return ((Number)o).doubleValue(); 482 } 483 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a double. It is of type '" + o.getClass() + "'."); 484 } 485 486 /** 487 * Returns the specified tag's value as a float, if possible. 488 */ 603 604 return null; 605 } 606 607 /** Returns the specified tag's value as a float, if possible. */ 489 608 public float getFloat(int tagType) throws MetadataException 490 609 { 491 Object o = getObject(tagType); 492 if (o==null) { 493 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 494 } else if (o instanceof String) { 610 Float value = getFloatObject(tagType); 611 if (value!=null) 612 return value; 613 Object o = getObject(tagType); 614 if (o == null) 615 throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first"); 616 throw new MetadataException("Tag '" + tagType + "' cannot be converted to a float. It is of type '" + o.getClass() + "'."); 617 } 618 619 /** Returns the specified tag's value as a float. If the tag is not set or cannot be converted, <code>null</code> is returned. */ 620 @Nullable 621 public Float getFloatObject(int tagType) 622 { 623 Object o = getObject(tagType); 624 if (o == null) 625 return null; 626 if (o instanceof String) { 495 627 try { 496 628 return Float.parseFloat((String)o); 497 629 } catch (NumberFormatException nfe) { 498 throw new MetadataException("unable to parse string " + o + " as a float", nfe); 499 } 500 } else if (o instanceof Number) { 630 return null; 631 } 632 } 633 if (o instanceof Number) 501 634 return ((Number)o).floatValue(); 502 } 503 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a float. It is of type '" + o.getClass() + "'."); 504 } 505 506 /** 507 * Returns the specified tag's value as a long, if possible. 508 */ 635 return null; 636 } 637 638 /** Returns the specified tag's value as a long, if possible. */ 509 639 public long getLong(int tagType) throws MetadataException 510 640 { 511 Object o = getObject(tagType); 512 if (o==null) { 513 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 514 } else if (o instanceof String) { 641 Long value = getLongObject(tagType); 642 if (value!=null) 643 return value; 644 Object o = getObject(tagType); 645 if (o == null) 646 throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first"); 647 throw new MetadataException("Tag '" + tagType + "' cannot be converted to a long. It is of type '" + o.getClass() + "'."); 648 } 649 650 /** Returns the specified tag's value as a long. If the tag is not set or cannot be converted, <code>null</code> is returned. */ 651 @Nullable 652 public Long getLongObject(int tagType) 653 { 654 Object o = getObject(tagType); 655 if (o == null) 656 return null; 657 if (o instanceof String) { 515 658 try { 516 659 return Long.parseLong((String)o); 517 660 } catch (NumberFormatException nfe) { 518 throw new MetadataException("unable to parse string " + o + " as a long", nfe); 519 } 520 } else if (o instanceof Number) { 661 return null; 662 } 663 } 664 if (o instanceof Number) 521 665 return ((Number)o).longValue(); 522 } 523 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a long. It is of type '" + o.getClass() + "'."); 524 } 525 526 /** 527 * Returns the specified tag's value as a boolean, if possible. 528 */ 666 return null; 667 } 668 669 /** Returns the specified tag's value as a boolean, if possible. */ 529 670 public boolean getBoolean(int tagType) throws MetadataException 530 671 { 531 Object o = getObject(tagType); 532 if (o==null) { 533 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 534 } else if (o instanceof Boolean) { 535 return ((Boolean)o).booleanValue(); 536 } else if (o instanceof String) { 672 Boolean value = getBooleanObject(tagType); 673 if (value!=null) 674 return value; 675 Object o = getObject(tagType); 676 if (o == null) 677 throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first"); 678 throw new MetadataException("Tag '" + tagType + "' cannot be converted to a boolean. It is of type '" + o.getClass() + "'."); 679 } 680 681 /** Returns the specified tag's value as a boolean. If the tag is not set or cannot be converted, <code>null</code> is returned. */ 682 @Nullable 683 @SuppressWarnings(value = "NP_BOOLEAN_RETURN_NULL", justification = "keep API interface consistent") 684 public Boolean getBooleanObject(int tagType) 685 { 686 Object o = getObject(tagType); 687 if (o == null) 688 return null; 689 if (o instanceof Boolean) 690 return (Boolean)o; 691 if (o instanceof String) { 537 692 try { 538 693 return Boolean.getBoolean((String)o); 539 694 } catch (NumberFormatException nfe) { 540 throw new MetadataException("unable to parse string " + o + " as a boolean", nfe); 541 } 542 } else if (o instanceof Number) { 543 return (((Number)o).doubleValue()!=0); 544 } 545 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a boolean. It is of type '" + o.getClass() + "'."); 546 } 547 548 /** 549 * Returns the specified tag's value as a java.util.Date, if possible. 550 */ 551 public java.util.Date getDate(int tagType) throws MetadataException 552 { 553 Object o = getObject(tagType); 554 if (o==null) { 555 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 556 } else if (o instanceof java.util.Date) { 695 return null; 696 } 697 } 698 if (o instanceof Number) 699 return (((Number)o).doubleValue() != 0); 700 return null; 701 } 702 703 /** 704 * 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. 705 * <p/> 706 * If the underlying value is a {@link String}, then attempts will be made to parse the string as though it is in 707 * the current {@link TimeZone}. If the {@link TimeZone} is known, call the overload that accepts one as an argument. 708 */ 709 @Nullable 710 public java.util.Date getDate(int tagType) 711 { 712 return getDate(tagType, null); 713 } 714 715 /** 716 * 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. 717 * <p/> 718 * If the underlying value is a {@link String}, then attempts will be made to parse the string as though it is in 719 * the {@link TimeZone} represented by the {@code timeZone} parameter (if it is non-null). Note that this parameter 720 * is only considered if the underlying value is a string and parsing occurs, otherwise it has no effect. 721 */ 722 @Nullable 723 public java.util.Date getDate(int tagType, @Nullable TimeZone timeZone) 724 { 725 Object o = getObject(tagType); 726 727 if (o == null) 728 return null; 729 730 if (o instanceof java.util.Date) 557 731 return (java.util.Date)o; 558 } else if (o instanceof String) { 559 // add new dateformat strings to make this method even smarter560 // so far, this seems to cover all known date strings561 // (for example, AM and PM strings are not supported...)732 733 if (o instanceof String) { 734 // This seems to cover all known Exif date strings 735 // Note that " : : : : " is a valid date string according to the Exif spec (which means 'unknown date'): http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/datetimeoriginal.html 562 736 String datePatterns[] = { 563 "yyyy:MM:dd HH:mm:ss", 564 "yyyy:MM:dd HH:mm", 565 "yyyy-MM-dd HH:mm:ss", 566 "yyyy-MM-dd HH:mm"}; 737 "yyyy:MM:dd HH:mm:ss", 738 "yyyy:MM:dd HH:mm", 739 "yyyy-MM-dd HH:mm:ss", 740 "yyyy-MM-dd HH:mm", 741 "yyyy.MM.dd HH:mm:ss", 742 "yyyy.MM.dd HH:mm" }; 567 743 String dateString = (String)o; 568 for ( int i = 0; i<datePatterns.length; i++) {744 for (String datePattern : datePatterns) { 569 745 try { 570 DateFormat parser = new java.text.SimpleDateFormat(datePatterns[i]); 746 DateFormat parser = new SimpleDateFormat(datePattern); 747 if (timeZone != null) 748 parser.setTimeZone(timeZone); 571 749 return parser.parse(dateString); 572 } catch ( java.text.ParseException ex) {750 } catch (ParseException ex) { 573 751 // simply try the next pattern 574 752 } 575 753 } 576 754 } 577 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a java.util.Date. It is of type '" + o.getClass() + "'."); 578 } 579 580 /** 581 * Returns the specified tag's value as a Rational, if possible. 582 */ 583 public Rational getRational(int tagType) throws MetadataException 584 { 585 Object o = getObject(tagType); 586 if (o==null) { 587 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 588 } else if (o instanceof Rational) { 755 return null; 756 } 757 758 /** Returns the specified tag's value as a Rational. If the value is unset or cannot be converted, <code>null</code> is returned. */ 759 @Nullable 760 public Rational getRational(int tagType) 761 { 762 Object o = getObject(tagType); 763 764 if (o == null) 765 return null; 766 767 if (o instanceof Rational) 589 768 return (Rational)o; 590 } 591 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a Rational. It is of type '" + o.getClass() + "'."); 592 } 593 594 public Rational[] getRationalArray(int tagType) throws MetadataException 595 { 596 Object o = getObject(tagType); 597 if (o==null) { 598 throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); 599 } else if (o instanceof Rational[]) { 769 if (o instanceof Integer) 770 return new Rational((Integer)o, 1); 771 if (o instanceof Long) 772 return new Rational((Long)o, 1); 773 774 // NOTE not doing conversions for real number types 775 776 return null; 777 } 778 779 /** Returns the specified tag's value as an array of Rational. If the value is unset or cannot be converted, <code>null</code> is returned. */ 780 @Nullable 781 public Rational[] getRationalArray(int tagType) 782 { 783 Object o = getObject(tagType); 784 if (o == null) 785 return null; 786 787 if (o instanceof Rational[]) 600 788 return (Rational[])o; 601 } 602 throw new MetadataException("Tag '" + tagType + "' cannot be cast to a Rational array. It is of type '" + o.getClass() + "'.");789 790 return null; 603 791 } 604 792 … … 606 794 * Returns the specified tag's value as a String. This value is the 'raw' value. A more presentable decoding 607 795 * of this value may be obtained from the corresponding Descriptor. 608 * @return the String reprensentation of the tag's value, or 796 * 797 * @return the String representation of the tag's value, or 609 798 * <code>null</code> if the tag hasn't been defined. 610 799 */ 800 @Nullable 611 801 public String getString(int tagType) 612 802 { 613 803 Object o = getObject(tagType); 614 if (o ==null)804 if (o == null) 615 805 return null; 616 806 … … 618 808 return ((Rational)o).toSimpleString(true); 619 809 620 if (o.getClass().isArray()) 621 { 810 if (o.getClass().isArray()) { 622 811 // handle arrays of objects and primitives 623 812 int arrayLength = Array.getLength(o); 624 // determine if this is an array of objects i.e. [Lcom.drew.blah 625 boolean isObjectArray = o.getClass().toString().startsWith("class [L"); 626 StringBuffer sbuffer = new StringBuffer(); 627 for (int i = 0; i<arrayLength; i++) 628 { 629 if (i!=0) 630 sbuffer.append(' '); 813 final Class<?> componentType = o.getClass().getComponentType(); 814 boolean isObjectArray = Object.class.isAssignableFrom(componentType); 815 boolean isFloatArray = componentType.getName().equals("float"); 816 boolean isDoubleArray = componentType.getName().equals("double"); 817 boolean isIntArray = componentType.getName().equals("int"); 818 boolean isLongArray = componentType.getName().equals("long"); 819 boolean isByteArray = componentType.getName().equals("byte"); 820 StringBuilder string = new StringBuilder(); 821 for (int i = 0; i < arrayLength; i++) { 822 if (i != 0) 823 string.append(' '); 631 824 if (isObjectArray) 632 sbuffer.append(Array.get(o, i).toString()); 825 string.append(Array.get(o, i).toString()); 826 else if (isIntArray) 827 string.append(Array.getInt(o, i)); 828 else if (isLongArray) 829 string.append(Array.getLong(o, i)); 830 else if (isFloatArray) 831 string.append(Array.getFloat(o, i)); 832 else if (isDoubleArray) 833 string.append(Array.getDouble(o, i)); 834 else if (isByteArray) 835 string.append(Array.getByte(o, i)); 633 836 else 634 sbuffer.append(Array.getInt(o, i)); 635 } 636 return sbuffer.toString(); 637 } 638 837 addError("Unexpected array component type: " + componentType.getName()); 838 } 839 return string.toString(); 840 } 841 842 // Note that several cameras leave trailing spaces (Olympus, Nikon) but this library is intended to show 843 // the actual data within the file. It is not inconceivable that whitespace may be significant here, so we 844 // do not trim. Also, if support is added for writing data back to files, this may cause issues. 845 // We leave trimming to the presentation layer. 639 846 return o.toString(); 640 847 } 641 848 849 @Nullable 850 public String getString(int tagType, String charset) 851 { 852 byte[] bytes = getByteArray(tagType); 853 if (bytes==null) 854 return null; 855 try { 856 return new String(bytes, charset); 857 } catch (UnsupportedEncodingException e) { 858 return null; 859 } 860 } 861 642 862 /** 643 863 * Returns the object hashed for the particular tag type specified, if available. 864 * 644 865 * @param tagType the tag type identifier 645 * @return the tag's value as an Object if available, else null 646 */ 866 * @return the tag's value as an Object if available, else <code>null</code> 867 */ 868 @java.lang.SuppressWarnings({ "UnnecessaryBoxing" }) 869 @Nullable 647 870 public Object getObject(int tagType) 648 871 { 649 return _tagMap.get( newInteger(tagType));872 return _tagMap.get(Integer.valueOf(tagType)); 650 873 } 651 874 … … 654 877 /** 655 878 * Returns the name of a specified tag as a String. 879 * 656 880 * @param tagType the tag type identifier 657 881 * @return the tag's name as a String 658 882 */ 883 @NotNull 659 884 public String getTagName(int tagType) 660 885 { 661 Integer key = new Integer(tagType); 662 HashMap nameMap = getTagNameMap(); 663 if (!nameMap.containsKey(key)) { 886 HashMap<Integer, String> nameMap = getTagNameMap(); 887 if (!nameMap.containsKey(tagType)) { 664 888 String hex = Integer.toHexString(tagType); 665 while (hex.length() <4) {889 while (hex.length() < 4) { 666 890 hex = "0" + hex; 667 891 } 668 892 return "Unknown tag (0x" + hex + ")"; 669 893 } 670 return (String)nameMap.get(key);894 return nameMap.get(tagType); 671 895 } 672 896 … … 674 898 * Provides a description of a tag's value using the descriptor set by 675 899 * <code>setDescriptor(Descriptor)</code>. 900 * 676 901 * @param tagType the tag type identifier 677 902 * @return the tag value's description as a String 678 * @throws MetadataException if a descriptor hasn't been set, or if an error 679 * occurs during calculation of the description within the Descriptor 680 */ 681 public String getDescription(int tagType) throws MetadataException 682 { 683 if (_descriptor==null) { 684 throw new MetadataException("a descriptor must be set using setDescriptor(...) before descriptions can be provided"); 685 } 686 903 */ 904 @Nullable 905 public String getDescription(int tagType) 906 { 907 assert(_descriptor != null); 687 908 return _descriptor.getDescription(tagType); 688 909 }
Note:
See TracChangeset
for help on using the changeset viewer.
