OSDN Git Service

DO NOT MERGE) ExifInterface: Make saveAttributes throw an exception before change
[android-x86/frameworks-base.git] / media / java / android / media / ExifInterface.java
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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
17 package android.media;
18
19 import android.graphics.Bitmap;
20 import android.graphics.BitmapFactory;
21 import android.util.Log;
22 import android.util.Pair;
23
24 import libcore.io.IoUtils;
25 import libcore.io.Streams;
26
27 import java.io.BufferedInputStream;
28 import java.io.ByteArrayInputStream;
29 import java.io.DataInputStream;
30 import java.io.EOFException;
31 import java.io.File;
32 import java.io.FileDescriptor;
33 import java.io.FileInputStream;
34 import java.io.FileNotFoundException;
35 import java.io.FileOutputStream;
36 import java.io.FilterOutputStream;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.io.OutputStream;
40 import java.nio.ByteBuffer;
41 import java.nio.ByteOrder;
42 import java.nio.charset.Charset;
43 import java.text.ParsePosition;
44 import java.text.SimpleDateFormat;
45 import java.util.Arrays;
46 import java.util.Date;
47 import java.util.HashMap;
48 import java.util.HashSet;
49 import java.util.Map;
50 import java.util.Set;
51 import java.util.TimeZone;
52 import java.util.regex.Matcher;
53 import java.util.regex.Pattern;
54
55 /**
56  * This is a class for reading and writing Exif tags in a JPEG file.
57  */
58 public class ExifInterface {
59     private static final String TAG = "ExifInterface";
60     private static final boolean DEBUG = false;
61
62     // The Exif tag names
63     /** Type is String. @hide */
64     public static final String TAG_ARTIST = "Artist";
65     /** Type is int. @hide */
66     public static final String TAG_BITS_PER_SAMPLE = "BitsPerSample";
67     /** Type is int. @hide */
68     public static final String TAG_COMPRESSION = "Compression";
69     /** Type is String. @hide */
70     public static final String TAG_COPYRIGHT = "Copyright";
71     /** Type is String. */
72     public static final String TAG_DATETIME = "DateTime";
73     /** Type is String. @hide */
74     public static final String TAG_IMAGE_DESCRIPTION = "ImageDescription";
75     /** Type is int. */
76     public static final String TAG_IMAGE_LENGTH = "ImageLength";
77     /** Type is int. */
78     public static final String TAG_IMAGE_WIDTH = "ImageWidth";
79     /** Type is int. @hide */
80     public static final String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
81     /** Type is int. @hide */
82     public static final String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
83     /** Type is String. */
84     public static final String TAG_MAKE = "Make";
85     /** Type is String. */
86     public static final String TAG_MODEL = "Model";
87     /** Type is int. */
88     public static final String TAG_ORIENTATION = "Orientation";
89     /** Type is int. @hide */
90     public static final String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
91     /** Type is int. @hide */
92     public static final String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
93     /** Type is rational. @hide */
94     public static final String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
95     /** Type is rational. @hide */
96     public static final String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
97     /** Type is int. @hide */
98     public static final String TAG_RESOLUTION_UNIT = "ResolutionUnit";
99     /** Type is int. @hide */
100     public static final String TAG_ROWS_PER_STRIP = "RowsPerStrip";
101     /** Type is int. @hide */
102     public static final String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
103     /** Type is String. @hide */
104     public static final String TAG_SOFTWARE = "Software";
105     /** Type is int. @hide */
106     public static final String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
107     /** Type is int. @hide */
108     public static final String TAG_STRIP_OFFSETS = "StripOffsets";
109     /** Type is int. @hide */
110     public static final String TAG_TRANSFER_FUNCTION = "TransferFunction";
111     /** Type is rational. @hide */
112     public static final String TAG_WHITE_POINT = "WhitePoint";
113     /** Type is rational. @hide */
114     public static final String TAG_X_RESOLUTION = "XResolution";
115     /** Type is rational. @hide */
116     public static final String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
117     /** Type is int. @hide */
118     public static final String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
119     /** Type is int. @hide */
120     public static final String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
121     /** Type is rational. @hide */
122     public static final String TAG_Y_RESOLUTION = "YResolution";
123     /** Type is rational. @hide */
124     public static final String TAG_APERTURE_VALUE = "ApertureValue";
125     /** Type is rational. @hide */
126     public static final String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
127     /** Type is String. @hide */
128     public static final String TAG_CFA_PATTERN = "CFAPattern";
129     /** Type is int. @hide */
130     public static final String TAG_COLOR_SPACE = "ColorSpace";
131     /** Type is String. @hide */
132     public static final String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
133     /** Type is rational. @hide */
134     public static final String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
135     /** Type is int. @hide */
136     public static final String TAG_CONTRAST = "Contrast";
137     /** Type is int. @hide */
138     public static final String TAG_CUSTOM_RENDERED = "CustomRendered";
139     /** Type is String. */
140     public static final String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
141     /** Type is String. @hide */
142     public static final String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
143     /** Type is String. @hide */
144     public static final String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
145     /** Type is double. @hide */
146     public static final String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
147     /** Type is String. @hide */
148     public static final String TAG_EXIF_VERSION = "ExifVersion";
149     /** Type is double. @hide */
150     public static final String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
151     /** Type is rational. @hide */
152     public static final String TAG_EXPOSURE_INDEX = "ExposureIndex";
153     /** Type is int. @hide */
154     public static final String TAG_EXPOSURE_MODE = "ExposureMode";
155     /** Type is int. @hide */
156     public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
157     /** Type is double. */
158     public static final String TAG_EXPOSURE_TIME = "ExposureTime";
159     /** Type is double. */
160     public static final String TAG_APERTURE = "FNumber";
161     /** Type is String. @hide */
162     public static final String TAG_FILE_SOURCE = "FileSource";
163     /** Type is int. */
164     public static final String TAG_FLASH = "Flash";
165     /** Type is rational. @hide */
166     public static final String TAG_FLASH_ENERGY = "FlashEnergy";
167     /** Type is String. @hide */
168     public static final String TAG_FLASHPIX_VERSION = "FlashpixVersion";
169     /** Type is rational. */
170     public static final String TAG_FOCAL_LENGTH = "FocalLength";
171     /** Type is int. @hide */
172     public static final String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
173     /** Type is int. @hide */
174     public static final String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
175     /** Type is rational. @hide */
176     public static final String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
177     /** Type is rational. @hide */
178     public static final String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
179     /** Type is int. @hide */
180     public static final String TAG_GAIN_CONTROL = "GainControl";
181     /** Type is int. */
182     public static final String TAG_ISO = "ISOSpeedRatings";
183     /** Type is String. @hide */
184     public static final String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
185     /** Type is int. @hide */
186     public static final String TAG_LIGHT_SOURCE = "LightSource";
187     /** Type is String. @hide */
188     public static final String TAG_MAKER_NOTE = "MakerNote";
189     /** Type is rational. @hide */
190     public static final String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
191     /** Type is int. @hide */
192     public static final String TAG_METERING_MODE = "MeteringMode";
193     /** Type is String. @hide */
194     public static final String TAG_OECF = "OECF";
195     /** Type is int. @hide */
196     public static final String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
197     /** Type is int. @hide */
198     public static final String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
199     /** Type is String. @hide */
200     public static final String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
201     /** Type is int. @hide */
202     public static final String TAG_SATURATION = "Saturation";
203     /** Type is int. @hide */
204     public static final String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
205     /** Type is String. @hide */
206     public static final String TAG_SCENE_TYPE = "SceneType";
207     /** Type is int. @hide */
208     public static final String TAG_SENSING_METHOD = "SensingMethod";
209     /** Type is int. @hide */
210     public static final String TAG_SHARPNESS = "Sharpness";
211     /** Type is rational. @hide */
212     public static final String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
213     /** Type is String. @hide */
214     public static final String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
215     /** Type is String. @hide */
216     public static final String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
217     /** Type is String. */
218     public static final String TAG_SUBSEC_TIME = "SubSecTime";
219     /** Type is String. */
220     public static final String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
221     /** Type is String. */
222     public static final String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
223     /** Type is int. @hide */
224     public static final String TAG_SUBJECT_AREA = "SubjectArea";
225     /** Type is double. @hide */
226     public static final String TAG_SUBJECT_DISTANCE = "SubjectDistance";
227     /** Type is int. @hide */
228     public static final String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
229     /** Type is int. @hide */
230     public static final String TAG_SUBJECT_LOCATION = "SubjectLocation";
231     /** Type is String. @hide */
232     public static final String TAG_USER_COMMENT = "UserComment";
233     /** Type is int. */
234     public static final String TAG_WHITE_BALANCE = "WhiteBalance";
235     /**
236      * The altitude (in meters) based on the reference in TAG_GPS_ALTITUDE_REF.
237      * Type is rational.
238      */
239     public static final String TAG_GPS_ALTITUDE = "GPSAltitude";
240     /**
241      * 0 if the altitude is above sea level. 1 if the altitude is below sea
242      * level. Type is int.
243      */
244     public static final String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
245     /** Type is String. @hide */
246     public static final String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
247     /** Type is rational. @hide */
248     public static final String TAG_GPS_DOP = "GPSDOP";
249     /** Type is String. */
250     public static final String TAG_GPS_DATESTAMP = "GPSDateStamp";
251     /** Type is rational. @hide */
252     public static final String TAG_GPS_DEST_BEARING = "GPSDestBearing";
253     /** Type is String. @hide */
254     public static final String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
255     /** Type is rational. @hide */
256     public static final String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
257     /** Type is String. @hide */
258     public static final String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
259     /** Type is rational. @hide */
260     public static final String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
261     /** Type is String. @hide */
262     public static final String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
263     /** Type is rational. @hide */
264     public static final String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
265     /** Type is String. @hide */
266     public static final String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
267     /** Type is int. @hide */
268     public static final String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
269     /** Type is rational. @hide */
270     public static final String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
271     /** Type is String. @hide */
272     public static final String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
273     /** Type is rational. Format is "num1/denom1,num2/denom2,num3/denom3". */
274     public static final String TAG_GPS_LATITUDE = "GPSLatitude";
275     /** Type is String. */
276     public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
277     /** Type is rational. Format is "num1/denom1,num2/denom2,num3/denom3". */
278     public static final String TAG_GPS_LONGITUDE = "GPSLongitude";
279     /** Type is String. */
280     public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
281     /** Type is String. @hide */
282     public static final String TAG_GPS_MAP_DATUM = "GPSMapDatum";
283     /** Type is String. @hide */
284     public static final String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
285     /** Type is String. Name of GPS processing method used for location finding. */
286     public static final String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
287     /** Type is String. @hide */
288     public static final String TAG_GPS_SATELLITES = "GPSSatellites";
289     /** Type is rational. @hide */
290     public static final String TAG_GPS_SPEED = "GPSSpeed";
291     /** Type is String. @hide */
292     public static final String TAG_GPS_SPEED_REF = "GPSSpeedRef";
293     /** Type is String. @hide */
294     public static final String TAG_GPS_STATUS = "GPSStatus";
295     /** Type is String. Format is "hh:mm:ss". */
296     public static final String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
297     /** Type is rational. @hide */
298     public static final String TAG_GPS_TRACK = "GPSTrack";
299     /** Type is String. @hide */
300     public static final String TAG_GPS_TRACK_REF = "GPSTrackRef";
301     /** Type is String. @hide */
302     public static final String TAG_GPS_VERSION_ID = "GPSVersionID";
303     /** Type is String. @hide */
304     public static final String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
305     /** Type is int. @hide */
306     public static final String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
307     /** Type is int. @hide */
308     public static final String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
309
310     // Private tags used for pointing the other IFD offset. The types of the following tags are int.
311     private static final String TAG_EXIF_IFD_POINTER = "ExifIFDPointer";
312     private static final String TAG_GPS_INFO_IFD_POINTER = "GPSInfoIFDPointer";
313     private static final String TAG_INTEROPERABILITY_IFD_POINTER = "InteroperabilityIFDPointer";
314
315     // Private tags used for thumbnail information.
316     private static final String TAG_HAS_THUMBNAIL = "HasThumbnail";
317     private static final String TAG_THUMBNAIL_OFFSET = "ThumbnailOffset";
318     private static final String TAG_THUMBNAIL_LENGTH = "ThumbnailLength";
319     private static final String TAG_THUMBNAIL_DATA = "ThumbnailData";
320
321     // Constants used for the Orientation Exif tag.
322     public static final int ORIENTATION_UNDEFINED = 0;
323     public static final int ORIENTATION_NORMAL = 1;
324     public static final int ORIENTATION_FLIP_HORIZONTAL = 2;  // left right reversed mirror
325     public static final int ORIENTATION_ROTATE_180 = 3;
326     public static final int ORIENTATION_FLIP_VERTICAL = 4;  // upside down mirror
327     // flipped about top-left <--> bottom-right axis
328     public static final int ORIENTATION_TRANSPOSE = 5;
329     public static final int ORIENTATION_ROTATE_90 = 6;  // rotate 90 cw to right it
330     // flipped about top-right <--> bottom-left axis
331     public static final int ORIENTATION_TRANSVERSE = 7;
332     public static final int ORIENTATION_ROTATE_270 = 8;  // rotate 270 to right it
333
334     // Constants used for white balance
335     public static final int WHITEBALANCE_AUTO = 0;
336     public static final int WHITEBALANCE_MANUAL = 1;
337
338     private static SimpleDateFormat sFormatter;
339
340     // See Exchangeable image file format for digital still cameras: Exif version 2.2.
341     // The following values are for parsing EXIF data area. There are tag groups in EXIF data area.
342     // They are called "Image File Directory". They have multiple data formats to cover various
343     // image metadata from GPS longitude to camera model name.
344
345     // Types of Exif byte alignments (see JEITA CP-3451 page 10)
346     private static final short BYTE_ALIGN_II = 0x4949;  // II: Intel order
347     private static final short BYTE_ALIGN_MM = 0x4d4d;  // MM: Motorola order
348
349     // Formats for the value in IFD entry (See TIFF 6.0 spec Types page 15).
350     private static final int IFD_FORMAT_BYTE = 1;
351     private static final int IFD_FORMAT_STRING = 2;
352     private static final int IFD_FORMAT_USHORT = 3;
353     private static final int IFD_FORMAT_ULONG = 4;
354     private static final int IFD_FORMAT_URATIONAL = 5;
355     private static final int IFD_FORMAT_SBYTE = 6;
356     private static final int IFD_FORMAT_UNDEFINED = 7;
357     private static final int IFD_FORMAT_SSHORT = 8;
358     private static final int IFD_FORMAT_SLONG = 9;
359     private static final int IFD_FORMAT_SRATIONAL = 10;
360     private static final int IFD_FORMAT_SINGLE = 11;
361     private static final int IFD_FORMAT_DOUBLE = 12;
362     // Names for the data formats for debugging purpose.
363     private static final String[] IFD_FORMAT_NAMES = new String[] {
364             "", "BYTE", "STRING", "USHORT", "ULONG", "URATIONAL", "SBYTE", "UNDEFINED", "SSHORT",
365             "SLONG", "SRATIONAL", "SINGLE", "DOUBLE"
366     };
367     // Sizes of the components of each IFD value format
368     private static final int[] IFD_FORMAT_BYTES_PER_FORMAT = new int[] {
369             0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8
370     };
371     private static final byte[] EXIF_ASCII_PREFIX = new byte[] {
372             0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0
373     };
374
375     // A class for indicating EXIF rational type.
376     private static class Rational {
377         public final long numerator;
378         public final long denominator;
379
380         private Rational(long numerator, long denominator) {
381             // Handle erroneous case
382             if (denominator == 0) {
383                 this.numerator = 0;
384                 this.denominator = 1;
385                 return;
386             }
387             this.numerator = numerator;
388             this.denominator = denominator;
389         }
390
391         @Override
392         public String toString() {
393             return numerator + "/" + denominator;
394         }
395
396         public double calculate() {
397             return (double) numerator / denominator;
398         }
399     }
400
401     // A class for indicating EXIF attribute.
402     private static class ExifAttribute {
403         public final int format;
404         public final int numberOfComponents;
405         public final byte[] bytes;
406
407         private ExifAttribute(int format, int numberOfComponents, byte[] bytes) {
408             this.format = format;
409             this.numberOfComponents = numberOfComponents;
410             this.bytes = bytes;
411         }
412
413         public static ExifAttribute createUShort(int[] values, ByteOrder byteOrder) {
414             final ByteBuffer buffer = ByteBuffer.wrap(
415                     new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_USHORT] * values.length]);
416             buffer.order(byteOrder);
417             for (int value : values) {
418                 buffer.putShort((short) value);
419             }
420             return new ExifAttribute(IFD_FORMAT_USHORT, values.length, buffer.array());
421         }
422
423         public static ExifAttribute createUShort(int value, ByteOrder byteOrder) {
424             return createUShort(new int[] {value}, byteOrder);
425         }
426
427         public static ExifAttribute createULong(long[] values, ByteOrder byteOrder) {
428             final ByteBuffer buffer = ByteBuffer.wrap(
429                     new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_ULONG] * values.length]);
430             buffer.order(byteOrder);
431             for (long value : values) {
432                 buffer.putInt((int) value);
433             }
434             return new ExifAttribute(IFD_FORMAT_ULONG, values.length, buffer.array());
435         }
436
437         public static ExifAttribute createULong(long value, ByteOrder byteOrder) {
438             return createULong(new long[] {value}, byteOrder);
439         }
440
441         public static ExifAttribute createSLong(int[] values, ByteOrder byteOrder) {
442             final ByteBuffer buffer = ByteBuffer.wrap(
443                     new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_SLONG] * values.length]);
444             buffer.order(byteOrder);
445             for (int value : values) {
446                 buffer.putInt(value);
447             }
448             return new ExifAttribute(IFD_FORMAT_SLONG, values.length, buffer.array());
449         }
450
451         public static ExifAttribute createSLong(int value, ByteOrder byteOrder) {
452             return createSLong(new int[] {value}, byteOrder);
453         }
454
455         public static ExifAttribute createByte(String value) {
456             // Exception for GPSAltitudeRef tag
457             if (value.length() == 1 && value.charAt(0) >= '0' && value.charAt(0) <= '1') {
458                 final byte[] bytes = new byte[] { (byte) (value.charAt(0) - '0') };
459                 return new ExifAttribute(IFD_FORMAT_BYTE, bytes.length, bytes);
460             }
461             final byte[] ascii = value.getBytes(ASCII);
462             return new ExifAttribute(IFD_FORMAT_BYTE, ascii.length, ascii);
463         }
464
465         public static ExifAttribute createString(String value) {
466             final byte[] ascii = (value + '\0').getBytes(ASCII);
467             return new ExifAttribute(IFD_FORMAT_STRING, ascii.length, ascii);
468         }
469
470         public static ExifAttribute createURational(Rational[] values, ByteOrder byteOrder) {
471             final ByteBuffer buffer = ByteBuffer.wrap(
472                     new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_URATIONAL] * values.length]);
473             buffer.order(byteOrder);
474             for (Rational value : values) {
475                 buffer.putInt((int) value.numerator);
476                 buffer.putInt((int) value.denominator);
477             }
478             return new ExifAttribute(IFD_FORMAT_URATIONAL, values.length, buffer.array());
479         }
480
481         public static ExifAttribute createURational(Rational value, ByteOrder byteOrder) {
482             return createURational(new Rational[] {value}, byteOrder);
483         }
484
485         public static ExifAttribute createSRational(Rational[] values, ByteOrder byteOrder) {
486             final ByteBuffer buffer = ByteBuffer.wrap(
487                     new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_SRATIONAL] * values.length]);
488             buffer.order(byteOrder);
489             for (Rational value : values) {
490                 buffer.putInt((int) value.numerator);
491                 buffer.putInt((int) value.denominator);
492             }
493             return new ExifAttribute(IFD_FORMAT_SRATIONAL, values.length, buffer.array());
494         }
495
496         public static ExifAttribute createSRational(Rational value, ByteOrder byteOrder) {
497             return createSRational(new Rational[] {value}, byteOrder);
498         }
499
500         public static ExifAttribute createDouble(double[] values, ByteOrder byteOrder) {
501             final ByteBuffer buffer = ByteBuffer.wrap(
502                     new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_DOUBLE] * values.length]);
503             buffer.order(byteOrder);
504             for (double value : values) {
505                 buffer.putDouble(value);
506             }
507             return new ExifAttribute(IFD_FORMAT_DOUBLE, values.length, buffer.array());
508         }
509
510         public static ExifAttribute createDouble(double value, ByteOrder byteOrder) {
511             return createDouble(new double[] {value}, byteOrder);
512         }
513
514         @Override
515         public String toString() {
516             return "(" + IFD_FORMAT_NAMES[format] + ", data length:" + bytes.length + ")";
517         }
518
519         private Object getValue(ByteOrder byteOrder) {
520             try {
521                 ByteOrderAwarenessDataInputStream inputStream =
522                         new ByteOrderAwarenessDataInputStream(bytes);
523                 inputStream.setByteOrder(byteOrder);
524                 switch (format) {
525                     case IFD_FORMAT_BYTE:
526                     case IFD_FORMAT_SBYTE: {
527                         // Exception for GPSAltitudeRef tag
528                         if (bytes.length == 1 && bytes[0] >= 0 && bytes[0] <= 1) {
529                             return new String(new char[] { (char) (bytes[0] + '0') });
530                         }
531                         return new String(bytes, ASCII);
532                     }
533                     case IFD_FORMAT_UNDEFINED:
534                     case IFD_FORMAT_STRING: {
535                         int index = 0;
536                         if (numberOfComponents >= EXIF_ASCII_PREFIX.length) {
537                             boolean same = true;
538                             for (int i = 0; i < EXIF_ASCII_PREFIX.length; ++i) {
539                                 if (bytes[i] != EXIF_ASCII_PREFIX[i]) {
540                                     same = false;
541                                     break;
542                                 }
543                             }
544                             if (same) {
545                                 index = EXIF_ASCII_PREFIX.length;
546                             }
547                         }
548
549                         StringBuilder stringBuilder = new StringBuilder();
550                         while (index < numberOfComponents) {
551                             int ch = bytes[index];
552                             if (ch == 0) {
553                                 break;
554                             }
555                             if (ch >= 32) {
556                                 stringBuilder.append((char) ch);
557                             } else {
558                                 stringBuilder.append('?');
559                             }
560                             ++index;
561                         }
562                         return stringBuilder.toString();
563                     }
564                     case IFD_FORMAT_USHORT: {
565                         final int[] values = new int[numberOfComponents];
566                         for (int i = 0; i < numberOfComponents; ++i) {
567                             values[i] = inputStream.readUnsignedShort();
568                         }
569                         return values;
570                     }
571                     case IFD_FORMAT_ULONG: {
572                         final long[] values = new long[numberOfComponents];
573                         for (int i = 0; i < numberOfComponents; ++i) {
574                             values[i] = inputStream.readUnsignedInt();
575                         }
576                         return values;
577                     }
578                     case IFD_FORMAT_URATIONAL: {
579                         final Rational[] values = new Rational[numberOfComponents];
580                         for (int i = 0; i < numberOfComponents; ++i) {
581                             final long numerator = inputStream.readUnsignedInt();
582                             final long denominator = inputStream.readUnsignedInt();
583                             values[i] = new Rational(numerator, denominator);
584                         }
585                         return values;
586                     }
587                     case IFD_FORMAT_SSHORT: {
588                         final int[] values = new int[numberOfComponents];
589                         for (int i = 0; i < numberOfComponents; ++i) {
590                             values[i] = inputStream.readShort();
591                         }
592                         return values;
593                     }
594                     case IFD_FORMAT_SLONG: {
595                         final int[] values = new int[numberOfComponents];
596                         for (int i = 0; i < numberOfComponents; ++i) {
597                             values[i] = inputStream.readInt();
598                         }
599                         return values;
600                     }
601                     case IFD_FORMAT_SRATIONAL: {
602                         final Rational[] values = new Rational[numberOfComponents];
603                         for (int i = 0; i < numberOfComponents; ++i) {
604                             final long numerator = inputStream.readInt();
605                             final long denominator = inputStream.readInt();
606                             values[i] = new Rational(numerator, denominator);
607                         }
608                         return values;
609                     }
610                     case IFD_FORMAT_SINGLE: {
611                         final double[] values = new double[numberOfComponents];
612                         for (int i = 0; i < numberOfComponents; ++i) {
613                             values[i] = inputStream.readFloat();
614                         }
615                         return values;
616                     }
617                     case IFD_FORMAT_DOUBLE: {
618                         final double[] values = new double[numberOfComponents];
619                         for (int i = 0; i < numberOfComponents; ++i) {
620                             values[i] = inputStream.readDouble();
621                         }
622                         return values;
623                     }
624                     default:
625                         return null;
626                 }
627             } catch (IOException e) {
628                 Log.w(TAG, "IOException occurred during reading a value", e);
629                 return null;
630             }
631         }
632
633         public double getDoubleValue(ByteOrder byteOrder) {
634             Object value = getValue(byteOrder);
635             if (value == null) {
636                 throw new NumberFormatException("NULL can't be converted to a double value");
637             }
638             if (value instanceof String) {
639                 return Double.parseDouble((String) value);
640             }
641             if (value instanceof long[]) {
642                 long[] array = (long[]) value;
643                 if (array.length == 1) {
644                     return array[0];
645                 }
646                 throw new NumberFormatException("There are more than one component");
647             }
648             if (value instanceof int[]) {
649                 int[] array = (int[]) value;
650                 if (array.length == 1) {
651                     return array[0];
652                 }
653                 throw new NumberFormatException("There are more than one component");
654             }
655             if (value instanceof double[]) {
656                 double[] array = (double[]) value;
657                 if (array.length == 1) {
658                     return array[0];
659                 }
660                 throw new NumberFormatException("There are more than one component");
661             }
662             if (value instanceof Rational[]) {
663                 Rational[] array = (Rational[]) value;
664                 if (array.length == 1) {
665                     return array[0].calculate();
666                 }
667                 throw new NumberFormatException("There are more than one component");
668             }
669             throw new NumberFormatException("Couldn't find a double value");
670         }
671
672         public int getIntValue(ByteOrder byteOrder) {
673             Object value = getValue(byteOrder);
674             if (value == null) {
675                 throw new NumberFormatException("NULL can't be converted to a integer value");
676             }
677             if (value instanceof String) {
678                 return Integer.parseInt((String) value);
679             }
680             if (value instanceof long[]) {
681                 long[] array = (long[]) value;
682                 if (array.length == 1) {
683                     return (int) array[0];
684                 }
685                 throw new NumberFormatException("There are more than one component");
686             }
687             if (value instanceof int[]) {
688                 int[] array = (int[]) value;
689                 if (array.length == 1) {
690                     return array[0];
691                 }
692                 throw new NumberFormatException("There are more than one component");
693             }
694             throw new NumberFormatException("Couldn't find a integer value");
695         }
696
697         public String getStringValue(ByteOrder byteOrder) {
698             Object value = getValue(byteOrder);
699             if (value == null) {
700                 return null;
701             }
702             if (value instanceof String) {
703                 return (String) value;
704             }
705
706             final StringBuilder stringBuilder = new StringBuilder();
707             if (value instanceof long[]) {
708                 long[] array = (long[]) value;
709                 for (int i = 0; i < array.length; ++i) {
710                     stringBuilder.append(array[i]);
711                     if (i + 1 != array.length) {
712                         stringBuilder.append(",");
713                     }
714                 }
715                 return stringBuilder.toString();
716             }
717             if (value instanceof int[]) {
718                 int[] array = (int[]) value;
719                 for (int i = 0; i < array.length; ++i) {
720                     stringBuilder.append(array[i]);
721                     if (i + 1 != array.length) {
722                         stringBuilder.append(",");
723                     }
724                 }
725                 return stringBuilder.toString();
726             }
727             if (value instanceof double[]) {
728                 double[] array = (double[]) value;
729                 for (int i = 0; i < array.length; ++i) {
730                     stringBuilder.append(array[i]);
731                     if (i + 1 != array.length) {
732                         stringBuilder.append(",");
733                     }
734                 }
735                 return stringBuilder.toString();
736             }
737             if (value instanceof Rational[]) {
738                 Rational[] array = (Rational[]) value;
739                 for (int i = 0; i < array.length; ++i) {
740                     stringBuilder.append(array[i].numerator);
741                     stringBuilder.append('/');
742                     stringBuilder.append(array[i].denominator);
743                     if (i + 1 != array.length) {
744                         stringBuilder.append(",");
745                     }
746                 }
747                 return stringBuilder.toString();
748             }
749             return null;
750         }
751
752         public int size() {
753             return IFD_FORMAT_BYTES_PER_FORMAT[format] * numberOfComponents;
754         }
755     }
756
757     // A class for indicating EXIF tag.
758     private static class ExifTag {
759         public final int number;
760         public final String name;
761         public final int primaryFormat;
762         public final int secondaryFormat;
763
764         private ExifTag(String name, int number, int format) {
765             this.name = name;
766             this.number = number;
767             this.primaryFormat = format;
768             this.secondaryFormat = -1;
769         }
770
771         private ExifTag(String name, int number, int primaryFormat, int secondaryFormat) {
772             this.name = name;
773             this.number = number;
774             this.primaryFormat = primaryFormat;
775             this.secondaryFormat = secondaryFormat;
776         }
777     }
778
779     // Primary image IFD TIFF tags (See JEITA CP-3451 Table 14. page 54).
780     private static final ExifTag[] IFD_TIFF_TAGS = new ExifTag[] {
781             new ExifTag(TAG_IMAGE_WIDTH, 256, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
782             new ExifTag(TAG_IMAGE_LENGTH, 257, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
783             new ExifTag(TAG_BITS_PER_SAMPLE, 258, IFD_FORMAT_USHORT),
784             new ExifTag(TAG_COMPRESSION, 259, IFD_FORMAT_USHORT),
785             new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262, IFD_FORMAT_USHORT),
786             new ExifTag(TAG_IMAGE_DESCRIPTION, 270, IFD_FORMAT_STRING),
787             new ExifTag(TAG_MAKE, 271, IFD_FORMAT_STRING),
788             new ExifTag(TAG_MODEL, 272, IFD_FORMAT_STRING),
789             new ExifTag(TAG_STRIP_OFFSETS, 273, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
790             new ExifTag(TAG_ORIENTATION, 274, IFD_FORMAT_USHORT),
791             new ExifTag(TAG_SAMPLES_PER_PIXEL, 277, IFD_FORMAT_USHORT),
792             new ExifTag(TAG_ROWS_PER_STRIP, 278, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
793             new ExifTag(TAG_STRIP_BYTE_COUNTS, 279, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
794             new ExifTag(TAG_X_RESOLUTION, 282, IFD_FORMAT_URATIONAL),
795             new ExifTag(TAG_Y_RESOLUTION, 283, IFD_FORMAT_URATIONAL),
796             new ExifTag(TAG_PLANAR_CONFIGURATION, 284, IFD_FORMAT_USHORT),
797             new ExifTag(TAG_RESOLUTION_UNIT, 296, IFD_FORMAT_USHORT),
798             new ExifTag(TAG_TRANSFER_FUNCTION, 301, IFD_FORMAT_USHORT),
799             new ExifTag(TAG_SOFTWARE, 305, IFD_FORMAT_STRING),
800             new ExifTag(TAG_DATETIME, 306, IFD_FORMAT_STRING),
801             new ExifTag(TAG_ARTIST, 315, IFD_FORMAT_STRING),
802             new ExifTag(TAG_WHITE_POINT, 318, IFD_FORMAT_URATIONAL),
803             new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319, IFD_FORMAT_URATIONAL),
804             new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG),
805             new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG),
806             new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529, IFD_FORMAT_URATIONAL),
807             new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530, IFD_FORMAT_USHORT),
808             new ExifTag(TAG_Y_CB_CR_POSITIONING, 531, IFD_FORMAT_USHORT),
809             new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL),
810             new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING),
811             new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
812             new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG),
813     };
814
815     // Primary image IFD Exif Private tags (See JEITA CP-3451 Table 15. page 55).
816     private static final ExifTag[] IFD_EXIF_TAGS = new ExifTag[] {
817             new ExifTag(TAG_EXPOSURE_TIME, 33434, IFD_FORMAT_URATIONAL),
818             new ExifTag(TAG_APERTURE, 33437, IFD_FORMAT_URATIONAL),
819             new ExifTag(TAG_EXPOSURE_PROGRAM, 34850, IFD_FORMAT_USHORT),
820             new ExifTag(TAG_SPECTRAL_SENSITIVITY, 34852, IFD_FORMAT_STRING),
821             new ExifTag(TAG_ISO, 34855, IFD_FORMAT_USHORT),
822             new ExifTag(TAG_OECF, 34856, IFD_FORMAT_UNDEFINED),
823             new ExifTag(TAG_EXIF_VERSION, 36864, IFD_FORMAT_STRING),
824             new ExifTag(TAG_DATETIME_ORIGINAL, 36867, IFD_FORMAT_STRING),
825             new ExifTag(TAG_DATETIME_DIGITIZED, 36868, IFD_FORMAT_STRING),
826             new ExifTag(TAG_COMPONENTS_CONFIGURATION, 37121, IFD_FORMAT_UNDEFINED),
827             new ExifTag(TAG_COMPRESSED_BITS_PER_PIXEL, 37122, IFD_FORMAT_URATIONAL),
828             new ExifTag(TAG_SHUTTER_SPEED_VALUE, 37377, IFD_FORMAT_SRATIONAL),
829             new ExifTag(TAG_APERTURE_VALUE, 37378, IFD_FORMAT_URATIONAL),
830             new ExifTag(TAG_BRIGHTNESS_VALUE, 37379, IFD_FORMAT_SRATIONAL),
831             new ExifTag(TAG_EXPOSURE_BIAS_VALUE, 37380, IFD_FORMAT_SRATIONAL),
832             new ExifTag(TAG_MAX_APERTURE_VALUE, 37381, IFD_FORMAT_URATIONAL),
833             new ExifTag(TAG_SUBJECT_DISTANCE, 37382, IFD_FORMAT_URATIONAL),
834             new ExifTag(TAG_METERING_MODE, 37383, IFD_FORMAT_USHORT),
835             new ExifTag(TAG_LIGHT_SOURCE, 37384, IFD_FORMAT_USHORT),
836             new ExifTag(TAG_FLASH, 37385, IFD_FORMAT_USHORT),
837             new ExifTag(TAG_FOCAL_LENGTH, 37386, IFD_FORMAT_URATIONAL),
838             new ExifTag(TAG_SUBJECT_AREA, 37396, IFD_FORMAT_USHORT),
839             new ExifTag(TAG_MAKER_NOTE, 37500, IFD_FORMAT_UNDEFINED),
840             new ExifTag(TAG_USER_COMMENT, 37510, IFD_FORMAT_UNDEFINED),
841             new ExifTag(TAG_SUBSEC_TIME, 37520, IFD_FORMAT_STRING),
842             new ExifTag(TAG_SUBSEC_TIME_ORIG, 37521, IFD_FORMAT_STRING),
843             new ExifTag(TAG_SUBSEC_TIME_DIG, 37522, IFD_FORMAT_STRING),
844             new ExifTag(TAG_FLASHPIX_VERSION, 40960, IFD_FORMAT_UNDEFINED),
845             new ExifTag(TAG_COLOR_SPACE, 40961, IFD_FORMAT_USHORT),
846             new ExifTag(TAG_PIXEL_X_DIMENSION, 40962, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
847             new ExifTag(TAG_PIXEL_Y_DIMENSION, 40963, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
848             new ExifTag(TAG_RELATED_SOUND_FILE, 40964, IFD_FORMAT_STRING),
849             new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965, IFD_FORMAT_ULONG),
850             new ExifTag(TAG_FLASH_ENERGY, 41483, IFD_FORMAT_URATIONAL),
851             new ExifTag(TAG_SPATIAL_FREQUENCY_RESPONSE, 41484, IFD_FORMAT_UNDEFINED),
852             new ExifTag(TAG_FOCAL_PLANE_X_RESOLUTION, 41486, IFD_FORMAT_URATIONAL),
853             new ExifTag(TAG_FOCAL_PLANE_Y_RESOLUTION, 41487, IFD_FORMAT_URATIONAL),
854             new ExifTag(TAG_FOCAL_PLANE_RESOLUTION_UNIT, 41488, IFD_FORMAT_USHORT),
855             new ExifTag(TAG_SUBJECT_LOCATION, 41492, IFD_FORMAT_USHORT),
856             new ExifTag(TAG_EXPOSURE_INDEX, 41493, IFD_FORMAT_URATIONAL),
857             new ExifTag(TAG_SENSING_METHOD, 41495, IFD_FORMAT_USHORT),
858             new ExifTag(TAG_FILE_SOURCE, 41728, IFD_FORMAT_UNDEFINED),
859             new ExifTag(TAG_SCENE_TYPE, 41729, IFD_FORMAT_UNDEFINED),
860             new ExifTag(TAG_CFA_PATTERN, 41730, IFD_FORMAT_UNDEFINED),
861             new ExifTag(TAG_CUSTOM_RENDERED, 41985, IFD_FORMAT_USHORT),
862             new ExifTag(TAG_EXPOSURE_MODE, 41986, IFD_FORMAT_USHORT),
863             new ExifTag(TAG_WHITE_BALANCE, 41987, IFD_FORMAT_USHORT),
864             new ExifTag(TAG_DIGITAL_ZOOM_RATIO, 41988, IFD_FORMAT_URATIONAL),
865             new ExifTag(TAG_FOCAL_LENGTH_IN_35MM_FILM, 41989, IFD_FORMAT_USHORT),
866             new ExifTag(TAG_SCENE_CAPTURE_TYPE, 41990, IFD_FORMAT_USHORT),
867             new ExifTag(TAG_GAIN_CONTROL, 41991, IFD_FORMAT_USHORT),
868             new ExifTag(TAG_CONTRAST, 41992, IFD_FORMAT_USHORT),
869             new ExifTag(TAG_SATURATION, 41993, IFD_FORMAT_USHORT),
870             new ExifTag(TAG_SHARPNESS, 41994, IFD_FORMAT_USHORT),
871             new ExifTag(TAG_DEVICE_SETTING_DESCRIPTION, 41995, IFD_FORMAT_UNDEFINED),
872             new ExifTag(TAG_SUBJECT_DISTANCE_RANGE, 41996, IFD_FORMAT_USHORT),
873             new ExifTag(TAG_IMAGE_UNIQUE_ID, 42016, IFD_FORMAT_STRING),
874     };
875
876     // Primary image IFD GPS Info tags (See JEITA CP-3451 Table 16. page 56).
877     private static final ExifTag[] IFD_GPS_TAGS = new ExifTag[] {
878             new ExifTag(TAG_GPS_VERSION_ID, 0, IFD_FORMAT_BYTE),
879             new ExifTag(TAG_GPS_LATITUDE_REF, 1, IFD_FORMAT_STRING),
880             new ExifTag(TAG_GPS_LATITUDE, 2, IFD_FORMAT_URATIONAL),
881             new ExifTag(TAG_GPS_LONGITUDE_REF, 3, IFD_FORMAT_STRING),
882             new ExifTag(TAG_GPS_LONGITUDE, 4, IFD_FORMAT_URATIONAL),
883             new ExifTag(TAG_GPS_ALTITUDE_REF, 5, IFD_FORMAT_BYTE),
884             new ExifTag(TAG_GPS_ALTITUDE, 6, IFD_FORMAT_URATIONAL),
885             new ExifTag(TAG_GPS_TIMESTAMP, 7, IFD_FORMAT_URATIONAL),
886             new ExifTag(TAG_GPS_SATELLITES, 8, IFD_FORMAT_STRING),
887             new ExifTag(TAG_GPS_STATUS, 9, IFD_FORMAT_STRING),
888             new ExifTag(TAG_GPS_MEASURE_MODE, 10, IFD_FORMAT_STRING),
889             new ExifTag(TAG_GPS_DOP, 11, IFD_FORMAT_URATIONAL),
890             new ExifTag(TAG_GPS_SPEED_REF, 12, IFD_FORMAT_STRING),
891             new ExifTag(TAG_GPS_SPEED, 13, IFD_FORMAT_URATIONAL),
892             new ExifTag(TAG_GPS_TRACK_REF, 14, IFD_FORMAT_STRING),
893             new ExifTag(TAG_GPS_TRACK, 15, IFD_FORMAT_URATIONAL),
894             new ExifTag(TAG_GPS_IMG_DIRECTION_REF, 16, IFD_FORMAT_STRING),
895             new ExifTag(TAG_GPS_IMG_DIRECTION, 17, IFD_FORMAT_URATIONAL),
896             new ExifTag(TAG_GPS_MAP_DATUM, 18, IFD_FORMAT_STRING),
897             new ExifTag(TAG_GPS_DEST_LATITUDE_REF, 19, IFD_FORMAT_STRING),
898             new ExifTag(TAG_GPS_DEST_LATITUDE, 20, IFD_FORMAT_URATIONAL),
899             new ExifTag(TAG_GPS_DEST_LONGITUDE_REF, 21, IFD_FORMAT_STRING),
900             new ExifTag(TAG_GPS_DEST_LONGITUDE, 22, IFD_FORMAT_URATIONAL),
901             new ExifTag(TAG_GPS_DEST_BEARING_REF, 23, IFD_FORMAT_STRING),
902             new ExifTag(TAG_GPS_DEST_BEARING, 24, IFD_FORMAT_URATIONAL),
903             new ExifTag(TAG_GPS_DEST_DISTANCE_REF, 25, IFD_FORMAT_STRING),
904             new ExifTag(TAG_GPS_DEST_DISTANCE, 26, IFD_FORMAT_URATIONAL),
905             new ExifTag(TAG_GPS_PROCESSING_METHOD, 27, IFD_FORMAT_UNDEFINED),
906             new ExifTag(TAG_GPS_AREA_INFORMATION, 28, IFD_FORMAT_UNDEFINED),
907             new ExifTag(TAG_GPS_DATESTAMP, 29, IFD_FORMAT_STRING),
908             new ExifTag(TAG_GPS_DIFFERENTIAL, 30, IFD_FORMAT_USHORT),
909     };
910     // Primary image IFD Interoperability tag (See JEITA CP-3451 Table 17. page 56).
911     private static final ExifTag[] IFD_INTEROPERABILITY_TAGS = new ExifTag[] {
912             new ExifTag(TAG_INTEROPERABILITY_INDEX, 1, IFD_FORMAT_STRING),
913     };
914     // IFD Thumbnail tags (See JEITA CP-3451 Table 18. page 57).
915     private static final ExifTag[] IFD_THUMBNAIL_TAGS = new ExifTag[] {
916             new ExifTag(TAG_THUMBNAIL_IMAGE_WIDTH, 256, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
917             new ExifTag(TAG_THUMBNAIL_IMAGE_LENGTH, 257, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
918             new ExifTag(TAG_BITS_PER_SAMPLE, 258, IFD_FORMAT_USHORT),
919             new ExifTag(TAG_COMPRESSION, 259, IFD_FORMAT_USHORT),
920             new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262, IFD_FORMAT_USHORT),
921             new ExifTag(TAG_IMAGE_DESCRIPTION, 270, IFD_FORMAT_STRING),
922             new ExifTag(TAG_MAKE, 271, IFD_FORMAT_STRING),
923             new ExifTag(TAG_MODEL, 272, IFD_FORMAT_STRING),
924             new ExifTag(TAG_STRIP_OFFSETS, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
925             new ExifTag(TAG_ORIENTATION, 274, IFD_FORMAT_USHORT),
926             new ExifTag(TAG_SAMPLES_PER_PIXEL, 277, IFD_FORMAT_USHORT),
927             new ExifTag(TAG_ROWS_PER_STRIP, 278, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
928             new ExifTag(TAG_STRIP_BYTE_COUNTS, 279, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
929             new ExifTag(TAG_X_RESOLUTION, 282, IFD_FORMAT_URATIONAL),
930             new ExifTag(TAG_Y_RESOLUTION, 283, IFD_FORMAT_URATIONAL),
931             new ExifTag(TAG_PLANAR_CONFIGURATION, 284, IFD_FORMAT_USHORT),
932             new ExifTag(TAG_RESOLUTION_UNIT, 296, IFD_FORMAT_USHORT),
933             new ExifTag(TAG_TRANSFER_FUNCTION, 301, IFD_FORMAT_USHORT),
934             new ExifTag(TAG_SOFTWARE, 305, IFD_FORMAT_STRING),
935             new ExifTag(TAG_DATETIME, 306, IFD_FORMAT_STRING),
936             new ExifTag(TAG_ARTIST, 315, IFD_FORMAT_STRING),
937             new ExifTag(TAG_WHITE_POINT, 318, IFD_FORMAT_URATIONAL),
938             new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319, IFD_FORMAT_URATIONAL),
939             new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG),
940             new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG),
941             new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529, IFD_FORMAT_URATIONAL),
942             new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530, IFD_FORMAT_USHORT),
943             new ExifTag(TAG_Y_CB_CR_POSITIONING, 531, IFD_FORMAT_USHORT),
944             new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL),
945             new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING),
946             new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
947             new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG),
948     };
949
950     // See JEITA CP-3451 Figure 5. page 9.
951     // The following values are used for indicating pointers to the other Image File Directorys.
952
953     // Indices of Exif Ifd tag groups
954     private static final int IFD_TIFF_HINT = 0;
955     private static final int IFD_EXIF_HINT = 1;
956     private static final int IFD_GPS_HINT = 2;
957     private static final int IFD_INTEROPERABILITY_HINT = 3;
958     private static final int IFD_THUMBNAIL_HINT = 4;
959     // List of Exif tag groups
960     private static final ExifTag[][] EXIF_TAGS = new ExifTag[][] {
961             IFD_TIFF_TAGS, IFD_EXIF_TAGS, IFD_GPS_TAGS, IFD_INTEROPERABILITY_TAGS,
962             IFD_THUMBNAIL_TAGS
963     };
964     // List of tags for pointing to the other image file directory offset.
965     private static final ExifTag[] IFD_POINTER_TAGS = new ExifTag[] {
966             new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
967             new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG),
968             new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965, IFD_FORMAT_ULONG),
969     };
970     // List of indices of the indicated tag groups according to the IFD_POINTER_TAGS
971     private static final int[] IFD_POINTER_TAG_HINTS = new int[] {
972             IFD_EXIF_HINT, IFD_GPS_HINT, IFD_INTEROPERABILITY_HINT
973     };
974     // Tags for indicating the thumbnail offset and length
975     private static final ExifTag JPEG_INTERCHANGE_FORMAT_TAG =
976             new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG);
977     private static final ExifTag JPEG_INTERCHANGE_FORMAT_LENGTH_TAG =
978             new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG);
979
980     // Mappings from tag number to tag name and each item represents one IFD tag group.
981     private static final HashMap[] sExifTagMapsForReading = new HashMap[EXIF_TAGS.length];
982     // Mappings from tag name to tag number and each item represents one IFD tag group.
983     private static final HashMap[] sExifTagMapsForWriting = new HashMap[EXIF_TAGS.length];
984     private static final HashSet<String> sTagSetForCompatibility = new HashSet<>(Arrays.asList(
985             TAG_APERTURE, TAG_DIGITAL_ZOOM_RATIO, TAG_EXPOSURE_TIME, TAG_SUBJECT_DISTANCE,
986             TAG_GPS_TIMESTAMP));
987
988     // See JPEG File Interchange Format Version 1.02.
989     // The following values are defined for handling JPEG streams. In this implementation, we are
990     // not only getting information from EXIF but also from some JPEG special segments such as
991     // MARKER_COM for user comment and MARKER_SOFx for image width and height.
992
993     private static final Charset ASCII = Charset.forName("US-ASCII");
994     // Identifier for EXIF APP1 segment in JPEG
995     private static final byte[] IDENTIFIER_EXIF_APP1 = "Exif\0\0".getBytes(ASCII);
996     // JPEG segment markers, that each marker consumes two bytes beginning with 0xff and ending with
997     // the indicator. There is no SOF4, SOF8, SOF16 markers in JPEG and SOFx markers indicates start
998     // of frame(baseline DCT) and the image size info exists in its beginning part.
999     private static final byte MARKER = (byte) 0xff;
1000     private static final byte MARKER_SOI = (byte) 0xd8;
1001     private static final byte MARKER_SOF0 = (byte) 0xc0;
1002     private static final byte MARKER_SOF1 = (byte) 0xc1;
1003     private static final byte MARKER_SOF2 = (byte) 0xc2;
1004     private static final byte MARKER_SOF3 = (byte) 0xc3;
1005     private static final byte MARKER_SOF5 = (byte) 0xc5;
1006     private static final byte MARKER_SOF6 = (byte) 0xc6;
1007     private static final byte MARKER_SOF7 = (byte) 0xc7;
1008     private static final byte MARKER_SOF9 = (byte) 0xc9;
1009     private static final byte MARKER_SOF10 = (byte) 0xca;
1010     private static final byte MARKER_SOF11 = (byte) 0xcb;
1011     private static final byte MARKER_SOF13 = (byte) 0xcd;
1012     private static final byte MARKER_SOF14 = (byte) 0xce;
1013     private static final byte MARKER_SOF15 = (byte) 0xcf;
1014     private static final byte MARKER_SOS = (byte) 0xda;
1015     private static final byte MARKER_APP1 = (byte) 0xe1;
1016     private static final byte MARKER_COM = (byte) 0xfe;
1017     private static final byte MARKER_EOI = (byte) 0xd9;
1018
1019     static {
1020         sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
1021         sFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
1022
1023         // Build up the hash tables to look up Exif tags for reading Exif tags.
1024         for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
1025             sExifTagMapsForReading[hint] = new HashMap();
1026             sExifTagMapsForWriting[hint] = new HashMap();
1027             for (ExifTag tag : EXIF_TAGS[hint]) {
1028                 sExifTagMapsForReading[hint].put(tag.number, tag);
1029                 sExifTagMapsForWriting[hint].put(tag.name, tag);
1030             }
1031         }
1032     }
1033
1034     private final String mFilename;
1035     private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length];
1036     private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
1037     private boolean mHasThumbnail;
1038     // The following values used for indicating a thumbnail position.
1039     private int mThumbnailOffset;
1040     private int mThumbnailLength;
1041     private byte[] mThumbnailBytes;
1042     private boolean mIsSupportedFile;
1043
1044     // Pattern to check non zero timestamp
1045     private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*");
1046     // Pattern to check gps timestamp
1047     private static final Pattern sGpsTimestampPattern =
1048             Pattern.compile("^([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$");
1049
1050     /**
1051      * Reads Exif tags from the specified image file.
1052      */
1053     public ExifInterface(String filename) throws IOException {
1054         if (filename == null) {
1055             throw new IllegalArgumentException("filename cannot be null");
1056         }
1057         mFilename = filename;
1058         loadAttributes();
1059     }
1060
1061
1062     /**
1063      * Returns the EXIF attribute of the specified tag or {@code null} if there is no such tag in
1064      * the image file.
1065      *
1066      * @param tag the name of the tag.
1067      */
1068     private ExifAttribute getExifAttribute(String tag) {
1069         // Retrieves all tag groups. The value from primary image tag group has a higher priority
1070         // than the value from the thumbnail tag group if there are more than one candidates.
1071         for (int i = 0; i < EXIF_TAGS.length; ++i) {
1072             Object value = mAttributes[i].get(tag);
1073             if (value != null) {
1074                 return (ExifAttribute) value;
1075             }
1076         }
1077         return null;
1078     }
1079
1080     /**
1081      * Returns the value of the specified tag or {@code null} if there
1082      * is no such tag in the image file.
1083      *
1084      * @param tag the name of the tag.
1085      */
1086     public String getAttribute(String tag) {
1087         ExifAttribute attribute = getExifAttribute(tag);
1088         if (attribute != null) {
1089             if (!sTagSetForCompatibility.contains(tag)) {
1090                 return attribute.getStringValue(mExifByteOrder);
1091             }
1092             if (tag.equals(TAG_GPS_TIMESTAMP)) {
1093                 // Convert the rational values to the custom formats for backwards compatibility.
1094                 if (attribute.format != IFD_FORMAT_URATIONAL
1095                         && attribute.format != IFD_FORMAT_SRATIONAL) {
1096                     return null;
1097                 }
1098                 Rational[] array = (Rational[]) attribute.getValue(mExifByteOrder);
1099                 if (array.length != 3) {
1100                     return null;
1101                 }
1102                 return String.format("%02d:%02d:%02d",
1103                         (int) ((float) array[0].numerator / array[0].denominator),
1104                         (int) ((float) array[1].numerator / array[1].denominator),
1105                         (int) ((float) array[2].numerator / array[2].denominator));
1106             }
1107             try {
1108                 return Double.toString(attribute.getDoubleValue(mExifByteOrder));
1109             } catch (NumberFormatException e) {
1110                 return null;
1111             }
1112         }
1113         return null;
1114     }
1115
1116     /**
1117      * Returns the integer value of the specified tag. If there is no such tag
1118      * in the image file or the value cannot be parsed as integer, return
1119      * <var>defaultValue</var>.
1120      *
1121      * @param tag the name of the tag.
1122      * @param defaultValue the value to return if the tag is not available.
1123      */
1124     public int getAttributeInt(String tag, int defaultValue) {
1125         ExifAttribute exifAttribute = getExifAttribute(tag);
1126         if (exifAttribute == null) {
1127             return defaultValue;
1128         }
1129
1130         try {
1131             return exifAttribute.getIntValue(mExifByteOrder);
1132         } catch (NumberFormatException e) {
1133             return defaultValue;
1134         }
1135     }
1136
1137     /**
1138      * Returns the double value of the tag that is specified as rational or contains a
1139      * double-formatted value. If there is no such tag in the image file or the value cannot be
1140      * parsed as double, return <var>defaultValue</var>.
1141      *
1142      * @param tag the name of the tag.
1143      * @param defaultValue the value to return if the tag is not available.
1144      */
1145     public double getAttributeDouble(String tag, double defaultValue) {
1146         ExifAttribute exifAttribute = getExifAttribute(tag);
1147         if (exifAttribute == null) {
1148             return defaultValue;
1149         }
1150
1151         try {
1152             return exifAttribute.getDoubleValue(mExifByteOrder);
1153         } catch (NumberFormatException e) {
1154             return defaultValue;
1155         }
1156     }
1157
1158     /**
1159      * Set the value of the specified tag.
1160      *
1161      * @param tag the name of the tag.
1162      * @param value the value of the tag.
1163      */
1164     public void setAttribute(String tag, String value) {
1165         // Convert the given value to rational values for backwards compatibility.
1166         if (value != null && sTagSetForCompatibility.contains(tag)) {
1167             if (tag.equals(TAG_GPS_TIMESTAMP)) {
1168                 Matcher m = sGpsTimestampPattern.matcher(value);
1169                 if (!m.find()) {
1170                     Log.w(TAG, "Invalid value for " + tag + " : " + value);
1171                     return;
1172                 }
1173                 value = Integer.parseInt(m.group(1)) + "/1," + Integer.parseInt(m.group(2)) + "/1,"
1174                         + Integer.parseInt(m.group(3)) + "/1";
1175             } else {
1176                 try {
1177                     double doubleValue = Double.parseDouble(value);
1178                     value = (long) (doubleValue * 10000L) + "/10000";
1179                 } catch (NumberFormatException e) {
1180                     Log.w(TAG, "Invalid value for " + tag + " : " + value);
1181                     return;
1182                 }
1183             }
1184         }
1185
1186         for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
1187             if (i == IFD_THUMBNAIL_HINT && !mHasThumbnail) {
1188                 continue;
1189             }
1190             final Object obj = sExifTagMapsForWriting[i].get(tag);
1191             if (obj != null) {
1192                 if (value == null) {
1193                     mAttributes[i].remove(tag);
1194                     continue;
1195                 }
1196                 final ExifTag exifTag = (ExifTag) obj;
1197                 Pair<Integer, Integer> guess = guessDataFormat(value);
1198                 int dataFormat;
1199                 if (exifTag.primaryFormat == guess.first || exifTag.primaryFormat == guess.second) {
1200                     dataFormat = exifTag.primaryFormat;
1201                 } else if (exifTag.secondaryFormat != -1 && (exifTag.secondaryFormat == guess.first
1202                         || exifTag.secondaryFormat == guess.second)) {
1203                     dataFormat = exifTag.secondaryFormat;
1204                 } else if (exifTag.primaryFormat == IFD_FORMAT_BYTE
1205                         || exifTag.primaryFormat == IFD_FORMAT_UNDEFINED
1206                         || exifTag.primaryFormat == IFD_FORMAT_STRING) {
1207                     dataFormat = exifTag.primaryFormat;
1208                 } else {
1209                     Log.w(TAG, "Given tag (" + tag + ") value didn't match with one of expected "
1210                             + "formats: " + IFD_FORMAT_NAMES[exifTag.primaryFormat]
1211                             + (exifTag.secondaryFormat == -1 ? "" : ", "
1212                             + IFD_FORMAT_NAMES[exifTag.secondaryFormat]) + " (guess: "
1213                             + IFD_FORMAT_NAMES[guess.first] + (guess.second == -1 ? "" : ", "
1214                             + IFD_FORMAT_NAMES[guess.second]) + ")");
1215                     continue;
1216                 }
1217                 switch (dataFormat) {
1218                     case IFD_FORMAT_BYTE: {
1219                         mAttributes[i].put(tag, ExifAttribute.createByte(value));
1220                         break;
1221                     }
1222                     case IFD_FORMAT_UNDEFINED:
1223                     case IFD_FORMAT_STRING: {
1224                         mAttributes[i].put(tag, ExifAttribute.createString(value));
1225                         break;
1226                     }
1227                     case IFD_FORMAT_USHORT: {
1228                         final String[] values = value.split(",");
1229                         final int[] intArray = new int[values.length];
1230                         for (int j = 0; j < values.length; ++j) {
1231                             intArray[j] = Integer.parseInt(values[j]);
1232                         }
1233                         mAttributes[i].put(tag,
1234                                 ExifAttribute.createUShort(intArray, mExifByteOrder));
1235                         break;
1236                     }
1237                     case IFD_FORMAT_SLONG: {
1238                         final String[] values = value.split(",");
1239                         final int[] intArray = new int[values.length];
1240                         for (int j = 0; j < values.length; ++j) {
1241                             intArray[j] = Integer.parseInt(values[j]);
1242                         }
1243                         mAttributes[i].put(tag,
1244                                 ExifAttribute.createSLong(intArray, mExifByteOrder));
1245                         break;
1246                     }
1247                     case IFD_FORMAT_ULONG: {
1248                         final String[] values = value.split(",");
1249                         final long[] longArray = new long[values.length];
1250                         for (int j = 0; j < values.length; ++j) {
1251                             longArray[j] = Long.parseLong(values[j]);
1252                         }
1253                         mAttributes[i].put(tag,
1254                                 ExifAttribute.createULong(longArray, mExifByteOrder));
1255                         break;
1256                     }
1257                     case IFD_FORMAT_URATIONAL: {
1258                         final String[] values = value.split(",");
1259                         final Rational[] rationalArray = new Rational[values.length];
1260                         for (int j = 0; j < values.length; ++j) {
1261                             final String[] numbers = values[j].split("/");
1262                             rationalArray[j] = new Rational(Long.parseLong(numbers[0]),
1263                                     Long.parseLong(numbers[1]));
1264                         }
1265                         mAttributes[i].put(tag,
1266                                 ExifAttribute.createURational(rationalArray, mExifByteOrder));
1267                         break;
1268                     }
1269                     case IFD_FORMAT_SRATIONAL: {
1270                         final String[] values = value.split(",");
1271                         final Rational[] rationalArray = new Rational[values.length];
1272                         for (int j = 0; j < values.length; ++j) {
1273                             final String[] numbers = values[j].split("/");
1274                             rationalArray[j] = new Rational(Long.parseLong(numbers[0]),
1275                                     Long.parseLong(numbers[1]));
1276                         }
1277                         mAttributes[i].put(tag,
1278                                 ExifAttribute.createSRational(rationalArray, mExifByteOrder));
1279                         break;
1280                     }
1281                     case IFD_FORMAT_DOUBLE: {
1282                         final String[] values = value.split(",");
1283                         final double[] doubleArray = new double[values.length];
1284                         for (int j = 0; j < values.length; ++j) {
1285                             doubleArray[j] = Double.parseDouble(values[j]);
1286                         }
1287                         mAttributes[i].put(tag,
1288                                 ExifAttribute.createDouble(doubleArray, mExifByteOrder));
1289                         break;
1290                     }
1291                     default:
1292                         Log.w(TAG, "Data format isn't one of expected formats: " + dataFormat);
1293                         continue;
1294                 }
1295             }
1296         }
1297     }
1298
1299     /**
1300      * Update the values of the tags in the tag groups if any value for the tag already was stored.
1301      *
1302      * @param tag the name of the tag.
1303      * @param value the value of the tag in a form of {@link ExifAttribute}.
1304      * @return Returns {@code true} if updating is placed.
1305      */
1306     private boolean updateAttribute(String tag, ExifAttribute value) {
1307         boolean updated = false;
1308         for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
1309             if (mAttributes[i].containsKey(tag)) {
1310                 mAttributes[i].put(tag, value);
1311                 updated = true;
1312             }
1313         }
1314         return updated;
1315     }
1316
1317     /**
1318      * Remove any values of the specified tag.
1319      *
1320      * @param tag the name of the tag.
1321      */
1322     private void removeAttribute(String tag) {
1323         for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
1324             mAttributes[i].remove(tag);
1325         }
1326     }
1327
1328     /**
1329      * This function decides which parser to read the image data according to the given input stream
1330      * type and the content of the input stream. In each case, it reads the first three bytes to
1331      * determine whether the image data format is JPEG or not.
1332      */
1333     private void loadAttributes() throws IOException {
1334         // Initialize mAttributes.
1335         for (int i = 0; i < EXIF_TAGS.length; ++i) {
1336             mAttributes[i] = new HashMap();
1337         }
1338         try {
1339             InputStream in = new FileInputStream(mFilename);
1340             getJpegAttributes(in);
1341             mIsSupportedFile = true;
1342         } catch (IOException e) {
1343             // Ignore exceptions in order to keep the compatibility with the old versions of
1344             // ExifInterface.
1345             mIsSupportedFile = false;
1346             Log.w(TAG, "Invalid image.", e);
1347         } finally {
1348             addDefaultValuesForCompatibility();
1349             if (DEBUG) {
1350                 printAttributes();
1351             }
1352         }
1353     }
1354
1355     // Prints out attributes for debugging.
1356     private void printAttributes() {
1357         for (int i = 0; i < mAttributes.length; ++i) {
1358             Log.d(TAG, "The size of tag group[" + i + "]: " + mAttributes[i].size());
1359             for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
1360                 final ExifAttribute tagValue = (ExifAttribute) entry.getValue();
1361                 Log.d(TAG, "tagName: " + entry.getKey() + ", tagType: " + tagValue.toString()
1362                         + ", tagValue: '" + tagValue.getStringValue(mExifByteOrder) + "'");
1363             }
1364         }
1365     }
1366
1367     /**
1368      * Save the tag data into the original image file. This is expensive because it involves
1369      * copying all the data from one file to another and deleting the old file and renaming the
1370      * other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write
1371      * and make a single call rather than multiple calls for each attribute.
1372      */
1373     public void saveAttributes() throws IOException {
1374         if (!mIsSupportedFile) {
1375             throw new UnsupportedOperationException(
1376                     "ExifInterface only supports saving attributes on JPEG formats.");
1377         }
1378         // Keep the thumbnail in memory
1379         mThumbnailBytes = getThumbnail();
1380
1381         File tempFile = null;
1382         // Move the original file to temporary file.
1383         tempFile = new File(mFilename + ".tmp");
1384         File originalFile = new File(mFilename);
1385         if (!originalFile.renameTo(tempFile)) {
1386             throw new IOException("Could'nt rename to " + tempFile.getAbsolutePath());
1387         }
1388
1389         FileInputStream in = null;
1390         FileOutputStream out = null;
1391         try {
1392             // Save the new file.
1393             in = new FileInputStream(tempFile);
1394             out = new FileOutputStream(mFilename);
1395             saveJpegAttributes(in, out);
1396         } finally {
1397             IoUtils.closeQuietly(in);
1398             IoUtils.closeQuietly(out);
1399             tempFile.delete();
1400         }
1401
1402         // Discard the thumbnail in memory
1403         mThumbnailBytes = null;
1404     }
1405
1406     /**
1407      * Returns true if the image file has a thumbnail.
1408      */
1409     public boolean hasThumbnail() {
1410         return mHasThumbnail;
1411     }
1412
1413     /**
1414      * Returns the thumbnail inside the image file, or {@code null} if there is no thumbnail.
1415      * The returned data is in JPEG format and can be decoded using
1416      * {@link android.graphics.BitmapFactory#decodeByteArray(byte[],int,int)}
1417      */
1418     public byte[] getThumbnail() {
1419         if (!mHasThumbnail) {
1420             return null;
1421         }
1422         if (mThumbnailBytes != null) {
1423             return mThumbnailBytes;
1424         }
1425
1426         // Read the thumbnail.
1427         FileInputStream in = null;
1428         try {
1429             in = new FileInputStream(mFilename);
1430             if (in.skip(mThumbnailOffset) != mThumbnailOffset) {
1431                 throw new IOException("Corrupted image");
1432             }
1433             byte[] buffer = new byte[mThumbnailLength];
1434             if (in.read(buffer) != mThumbnailLength) {
1435                 throw new IOException("Corrupted image");
1436             }
1437             return buffer;
1438         } catch (IOException e) {
1439             // Couldn't get a thumbnail image.
1440         } finally {
1441             IoUtils.closeQuietly(in);
1442         }
1443         return null;
1444     }
1445
1446     /**
1447      * Returns the offset and length of thumbnail inside the image file, or
1448      * {@code null} if there is no thumbnail.
1449      *
1450      * @return two-element array, the offset in the first value, and length in
1451      *         the second, or {@code null} if no thumbnail was found.
1452      * @hide
1453      */
1454     public long[] getThumbnailRange() {
1455         if (!mHasThumbnail) {
1456             return null;
1457         }
1458
1459         long[] range = new long[2];
1460         range[0] = mThumbnailOffset;
1461         range[1] = mThumbnailLength;
1462
1463         return range;
1464     }
1465
1466     /**
1467      * Stores the latitude and longitude value in a float array. The first element is
1468      * the latitude, and the second element is the longitude. Returns false if the
1469      * Exif tags are not available.
1470      */
1471     public boolean getLatLong(float output[]) {
1472         String latValue = getAttribute(TAG_GPS_LATITUDE);
1473         String latRef = getAttribute(TAG_GPS_LATITUDE_REF);
1474         String lngValue = getAttribute(TAG_GPS_LONGITUDE);
1475         String lngRef = getAttribute(TAG_GPS_LONGITUDE_REF);
1476
1477         if (latValue != null && latRef != null && lngValue != null && lngRef != null) {
1478             try {
1479                 output[0] = convertRationalLatLonToFloat(latValue, latRef);
1480                 output[1] = convertRationalLatLonToFloat(lngValue, lngRef);
1481                 return true;
1482             } catch (IllegalArgumentException e) {
1483                 // if values are not parseable
1484             }
1485         }
1486
1487         return false;
1488     }
1489
1490     /**
1491      * Return the altitude in meters. If the exif tag does not exist, return
1492      * <var>defaultValue</var>.
1493      *
1494      * @param defaultValue the value to return if the tag is not available.
1495      */
1496     public double getAltitude(double defaultValue) {
1497         double altitude = getAttributeDouble(TAG_GPS_ALTITUDE, -1);
1498         int ref = getAttributeInt(TAG_GPS_ALTITUDE_REF, -1);
1499
1500         if (altitude >= 0 && ref >= 0) {
1501             return (altitude * ((ref == 1) ? -1 : 1));
1502         } else {
1503             return defaultValue;
1504         }
1505     }
1506
1507     /**
1508      * Returns number of milliseconds since Jan. 1, 1970, midnight local time.
1509      * Returns -1 if the date time information if not available.
1510      * @hide
1511      */
1512     public long getDateTime() {
1513         String dateTimeString = getAttribute(TAG_DATETIME);
1514         if (dateTimeString == null
1515                 || !sNonZeroTimePattern.matcher(dateTimeString).matches()) return -1;
1516
1517         ParsePosition pos = new ParsePosition(0);
1518         try {
1519             // The exif field is in local time. Parsing it as if it is UTC will yield time
1520             // since 1/1/1970 local time
1521             Date datetime = sFormatter.parse(dateTimeString, pos);
1522             if (datetime == null) return -1;
1523             long msecs = datetime.getTime();
1524
1525             String subSecs = getAttribute(TAG_SUBSEC_TIME);
1526             if (subSecs != null) {
1527                 try {
1528                     long sub = Long.valueOf(subSecs);
1529                     while (sub > 1000) {
1530                         sub /= 10;
1531                     }
1532                     msecs += sub;
1533                 } catch (NumberFormatException e) {
1534                     // Ignored
1535                 }
1536             }
1537             return msecs;
1538         } catch (IllegalArgumentException e) {
1539             return -1;
1540         }
1541     }
1542
1543     /**
1544      * Returns number of milliseconds since Jan. 1, 1970, midnight UTC.
1545      * Returns -1 if the date time information if not available.
1546      * @hide
1547      */
1548     public long getGpsDateTime() {
1549         String date = getAttribute(TAG_GPS_DATESTAMP);
1550         String time = getAttribute(TAG_GPS_TIMESTAMP);
1551         if (date == null || time == null
1552                 || (!sNonZeroTimePattern.matcher(date).matches()
1553                 && !sNonZeroTimePattern.matcher(time).matches())) {
1554             return -1;
1555         }
1556
1557         String dateTimeString = date + ' ' + time;
1558
1559         ParsePosition pos = new ParsePosition(0);
1560         try {
1561             Date datetime = sFormatter.parse(dateTimeString, pos);
1562             if (datetime == null) return -1;
1563             return datetime.getTime();
1564         } catch (IllegalArgumentException e) {
1565             return -1;
1566         }
1567     }
1568
1569     private static float convertRationalLatLonToFloat(String rationalString, String ref) {
1570         try {
1571             String [] parts = rationalString.split(",");
1572
1573             String [] pair;
1574             pair = parts[0].split("/");
1575             double degrees = Double.parseDouble(pair[0].trim())
1576                     / Double.parseDouble(pair[1].trim());
1577
1578             pair = parts[1].split("/");
1579             double minutes = Double.parseDouble(pair[0].trim())
1580                     / Double.parseDouble(pair[1].trim());
1581
1582             pair = parts[2].split("/");
1583             double seconds = Double.parseDouble(pair[0].trim())
1584                     / Double.parseDouble(pair[1].trim());
1585
1586             double result = degrees + (minutes / 60.0) + (seconds / 3600.0);
1587             if ((ref.equals("S") || ref.equals("W"))) {
1588                 return (float) -result;
1589             }
1590             return (float) result;
1591         } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
1592             // Not valid
1593             throw new IllegalArgumentException();
1594         }
1595     }
1596
1597     // Loads EXIF attributes from a JPEG input stream.
1598     private void getJpegAttributes(InputStream inputStream) throws IOException {
1599         // See JPEG File Interchange Format Specification page 5.
1600         if (DEBUG) {
1601             Log.d(TAG, "getJpegAttributes starting with: " + inputStream);
1602         }
1603         DataInputStream dataInputStream = new DataInputStream(inputStream);
1604         byte marker;
1605         int bytesRead = 0;
1606         if ((marker = dataInputStream.readByte()) != MARKER) {
1607             throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff));
1608         }
1609         ++bytesRead;
1610         if (dataInputStream.readByte() != MARKER_SOI) {
1611             throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff));
1612         }
1613         ++bytesRead;
1614         while (true) {
1615             marker = dataInputStream.readByte();
1616             if (marker != MARKER) {
1617                 throw new IOException("Invalid marker:" + Integer.toHexString(marker & 0xff));
1618             }
1619             ++bytesRead;
1620             marker = dataInputStream.readByte();
1621             if (DEBUG) {
1622                 Log.d(TAG, "Found JPEG segment indicator: " + Integer.toHexString(marker & 0xff));
1623             }
1624             ++bytesRead;
1625
1626             // EOI indicates the end of an image and in case of SOS, JPEG image stream starts and
1627             // the image data will terminate right after.
1628             if (marker == MARKER_EOI || marker == MARKER_SOS) {
1629                 break;
1630             }
1631             int length = dataInputStream.readUnsignedShort() - 2;
1632             bytesRead += 2;
1633             if (DEBUG) {
1634                 Log.d(TAG, "JPEG segment: " + Integer.toHexString(marker & 0xff) + " (length: "
1635                         + (length + 2) + ")");
1636             }
1637             if (length < 0) {
1638                 throw new IOException("Invalid length");
1639             }
1640             switch (marker) {
1641                 case MARKER_APP1: {
1642                     if (DEBUG) {
1643                         Log.d(TAG, "MARKER_APP1");
1644                     }
1645                     if (length < 6) {
1646                         // Skip if it's not an EXIF APP1 segment.
1647                         break;
1648                     }
1649                     byte[] identifier = new byte[6];
1650                     if (inputStream.read(identifier) != 6) {
1651                         throw new IOException("Invalid exif");
1652                     }
1653                     bytesRead += 6;
1654                     length -= 6;
1655                     if (!Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) {
1656                         // Skip if it's not an EXIF APP1 segment.
1657                         break;
1658                     }
1659                     if (length <= 0) {
1660                         throw new IOException("Invalid exif");
1661                     }
1662                     if (DEBUG) {
1663                         Log.d(TAG, "readExifSegment with a byte array (length: " + length + ")");
1664                     }
1665                     byte[] bytes = new byte[length];
1666                     if (dataInputStream.read(bytes) != length) {
1667                         throw new IOException("Invalid exif");
1668                     }
1669                     readExifSegment(bytes, bytesRead);
1670                     bytesRead += length;
1671                     length = 0;
1672                     break;
1673                 }
1674
1675                 case MARKER_COM: {
1676                     byte[] bytes = new byte[length];
1677                     if (dataInputStream.read(bytes) != length) {
1678                         throw new IOException("Invalid exif");
1679                     }
1680                     length = 0;
1681                     if (getAttribute(TAG_USER_COMMENT) == null) {
1682                         mAttributes[IFD_EXIF_HINT].put(TAG_USER_COMMENT, ExifAttribute.createString(
1683                                 new String(bytes, ASCII)));
1684                     }
1685                     break;
1686                 }
1687
1688                 case MARKER_SOF0:
1689                 case MARKER_SOF1:
1690                 case MARKER_SOF2:
1691                 case MARKER_SOF3:
1692                 case MARKER_SOF5:
1693                 case MARKER_SOF6:
1694                 case MARKER_SOF7:
1695                 case MARKER_SOF9:
1696                 case MARKER_SOF10:
1697                 case MARKER_SOF11:
1698                 case MARKER_SOF13:
1699                 case MARKER_SOF14:
1700                 case MARKER_SOF15: {
1701                     if (dataInputStream.skipBytes(1) != 1) {
1702                         throw new IOException("Invalid SOFx");
1703                     }
1704                     mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH, ExifAttribute.createULong(
1705                             dataInputStream.readUnsignedShort(), mExifByteOrder));
1706                     mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH, ExifAttribute.createULong(
1707                             dataInputStream.readUnsignedShort(), mExifByteOrder));
1708                     length -= 5;
1709                     break;
1710                 }
1711
1712                 default: {
1713                     break;
1714                 }
1715             }
1716             if (length < 0) {
1717                 throw new IOException("Invalid length");
1718             }
1719             if (dataInputStream.skipBytes(length) != length) {
1720                 throw new IOException("Invalid JPEG segment");
1721             }
1722             bytesRead += length;
1723         }
1724     }
1725
1726     // Stores a new JPEG image with EXIF attributes into a given output stream.
1727     private void saveJpegAttributes(InputStream inputStream, OutputStream outputStream)
1728             throws IOException {
1729         // See JPEG File Interchange Format Specification page 5.
1730         if (DEBUG) {
1731             Log.d(TAG, "saveJpegAttributes starting with (inputStream: " + inputStream
1732                     + ", outputStream: " + outputStream + ")");
1733         }
1734         DataInputStream dataInputStream = new DataInputStream(inputStream);
1735         ByteOrderAwarenessDataOutputStream dataOutputStream =
1736                 new ByteOrderAwarenessDataOutputStream(outputStream, ByteOrder.BIG_ENDIAN);
1737         if (dataInputStream.readByte() != MARKER) {
1738             throw new IOException("Invalid marker");
1739         }
1740         dataOutputStream.writeByte(MARKER);
1741         if (dataInputStream.readByte() != MARKER_SOI) {
1742             throw new IOException("Invalid marker");
1743         }
1744         dataOutputStream.writeByte(MARKER_SOI);
1745
1746         // Write EXIF APP1 segment
1747         dataOutputStream.writeByte(MARKER);
1748         dataOutputStream.writeByte(MARKER_APP1);
1749         writeExifSegment(dataOutputStream, 6);
1750
1751         byte[] bytes = new byte[4096];
1752
1753         while (true) {
1754             byte marker = dataInputStream.readByte();
1755             if (marker != MARKER) {
1756                 throw new IOException("Invalid marker");
1757             }
1758             marker = dataInputStream.readByte();
1759             switch (marker) {
1760                 case MARKER_APP1: {
1761                     int length = dataInputStream.readUnsignedShort() - 2;
1762                     if (length < 0) {
1763                         throw new IOException("Invalid length");
1764                     }
1765                     byte[] identifier = new byte[6];
1766                     if (length >= 6) {
1767                         if (dataInputStream.read(identifier) != 6) {
1768                             throw new IOException("Invalid exif");
1769                         }
1770                         if (Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) {
1771                             // Skip the original EXIF APP1 segment.
1772                             if (dataInputStream.skip(length - 6) != length - 6) {
1773                                 throw new IOException("Invalid length");
1774                             }
1775                             break;
1776                         }
1777                     }
1778                     // Copy non-EXIF APP1 segment.
1779                     dataOutputStream.writeByte(MARKER);
1780                     dataOutputStream.writeByte(marker);
1781                     dataOutputStream.writeUnsignedShort(length + 2);
1782                     if (length >= 6) {
1783                         length -= 6;
1784                         dataOutputStream.write(identifier);
1785                     }
1786                     int read;
1787                     while (length > 0 && (read = dataInputStream.read(
1788                             bytes, 0, Math.min(length, bytes.length))) >= 0) {
1789                         dataOutputStream.write(bytes, 0, read);
1790                         length -= read;
1791                     }
1792                     break;
1793                 }
1794                 case MARKER_EOI:
1795                 case MARKER_SOS: {
1796                     dataOutputStream.writeByte(MARKER);
1797                     dataOutputStream.writeByte(marker);
1798                     // Copy all the remaining data
1799                     Streams.copy(dataInputStream, dataOutputStream);
1800                     return;
1801                 }
1802                 default: {
1803                     // Copy JPEG segment
1804                     dataOutputStream.writeByte(MARKER);
1805                     dataOutputStream.writeByte(marker);
1806                     int length = dataInputStream.readUnsignedShort();
1807                     dataOutputStream.writeUnsignedShort(length);
1808                     length -= 2;
1809                     if (length < 0) {
1810                         throw new IOException("Invalid length");
1811                     }
1812                     int read;
1813                     while (length > 0 && (read = dataInputStream.read(
1814                             bytes, 0, Math.min(length, bytes.length))) >= 0) {
1815                         dataOutputStream.write(bytes, 0, read);
1816                         length -= read;
1817                     }
1818                     break;
1819                 }
1820             }
1821         }
1822     }
1823
1824     // Reads the given EXIF byte area and save its tag data into attributes.
1825     private void readExifSegment(byte[] exifBytes, int exifOffsetFromBeginning) throws IOException {
1826         // Parse TIFF Headers. See JEITA CP-3451C Table 1. page 10.
1827         ByteOrderAwarenessDataInputStream dataInputStream =
1828                 new ByteOrderAwarenessDataInputStream(exifBytes);
1829
1830         // Read byte align
1831         short byteOrder = dataInputStream.readShort();
1832         switch (byteOrder) {
1833             case BYTE_ALIGN_II:
1834                 if (DEBUG) {
1835                     Log.d(TAG, "readExifSegment: Byte Align II");
1836                 }
1837                 mExifByteOrder = ByteOrder.LITTLE_ENDIAN;
1838                 break;
1839             case BYTE_ALIGN_MM:
1840                 if (DEBUG) {
1841                     Log.d(TAG, "readExifSegment: Byte Align MM");
1842                 }
1843                 mExifByteOrder = ByteOrder.BIG_ENDIAN;
1844                 break;
1845             default:
1846                 throw new IOException("Invalid byte order: " + Integer.toHexString(byteOrder));
1847         }
1848
1849         // Set byte order.
1850         dataInputStream.setByteOrder(mExifByteOrder);
1851
1852         int startCode = dataInputStream.readUnsignedShort();
1853         if (startCode != 0x2a) {
1854             throw new IOException("Invalid exif start: " + Integer.toHexString(startCode));
1855         }
1856
1857         // Read first ifd offset
1858         long firstIfdOffset = dataInputStream.readUnsignedInt();
1859         if (firstIfdOffset < 8 || firstIfdOffset >= exifBytes.length) {
1860             throw new IOException("Invalid first Ifd offset: " + firstIfdOffset);
1861         }
1862         firstIfdOffset -= 8;
1863         if (firstIfdOffset > 0) {
1864             if (dataInputStream.skip(firstIfdOffset) != firstIfdOffset) {
1865                 throw new IOException("Couldn't jump to first Ifd: " + firstIfdOffset);
1866             }
1867         }
1868
1869         // Read primary image TIFF image file directory.
1870         readImageFileDirectory(dataInputStream, IFD_TIFF_HINT);
1871
1872         // Process thumbnail.
1873         String jpegInterchangeFormatString = getAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name);
1874         String jpegInterchangeFormatLengthString =
1875                 getAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name);
1876         if (jpegInterchangeFormatString != null && jpegInterchangeFormatLengthString != null) {
1877             try {
1878                 int jpegInterchangeFormat = Integer.parseInt(jpegInterchangeFormatString);
1879                 int jpegInterchangeFormatLength = Integer
1880                         .parseInt(jpegInterchangeFormatLengthString);
1881                 // The following code limits the size of thumbnail size not to overflow EXIF data area.
1882                 jpegInterchangeFormatLength = Math.min(jpegInterchangeFormat
1883                         + jpegInterchangeFormatLength, exifBytes.length) - jpegInterchangeFormat;
1884                 if (jpegInterchangeFormat > 0 && jpegInterchangeFormatLength > 0) {
1885                     mHasThumbnail = true;
1886                     mThumbnailOffset = exifOffsetFromBeginning + jpegInterchangeFormat;
1887                     mThumbnailLength = jpegInterchangeFormatLength;
1888                 }
1889             } catch (NumberFormatException e) {
1890                 // Ignored the corrupted image.
1891             }
1892         }
1893     }
1894
1895     private void addDefaultValuesForCompatibility() {
1896         // The value of DATETIME tag has the same value of DATETIME_ORIGINAL tag.
1897         String valueOfDateTimeOriginal = getAttribute(TAG_DATETIME_ORIGINAL);
1898         if (valueOfDateTimeOriginal != null) {
1899             mAttributes[IFD_TIFF_HINT].put(TAG_DATETIME,
1900                     ExifAttribute.createString(valueOfDateTimeOriginal));
1901         }
1902
1903         // Add the default value.
1904         if (getAttribute(TAG_IMAGE_WIDTH) == null) {
1905             mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_WIDTH,
1906                     ExifAttribute.createULong(0, mExifByteOrder));
1907         }
1908         if (getAttribute(TAG_IMAGE_LENGTH) == null) {
1909             mAttributes[IFD_TIFF_HINT].put(TAG_IMAGE_LENGTH,
1910                     ExifAttribute.createULong(0, mExifByteOrder));
1911         }
1912         if (getAttribute(TAG_ORIENTATION) == null) {
1913             mAttributes[IFD_TIFF_HINT].put(TAG_ORIENTATION,
1914                     ExifAttribute.createULong(0, mExifByteOrder));
1915         }
1916         if (getAttribute(TAG_LIGHT_SOURCE) == null) {
1917             mAttributes[IFD_EXIF_HINT].put(TAG_LIGHT_SOURCE,
1918                     ExifAttribute.createULong(0, mExifByteOrder));
1919         }
1920     }
1921
1922     // Reads image file directory, which is a tag group in EXIF.
1923     private void readImageFileDirectory(ByteOrderAwarenessDataInputStream dataInputStream, int hint)
1924             throws IOException {
1925         if (dataInputStream.peek() + 2 > dataInputStream.mLength) {
1926             // Return if there is no data from the offset.
1927             return;
1928         }
1929         // See JEITA CP-3451 Figure 5. page 9.
1930         short numberOfDirectoryEntry = dataInputStream.readShort();
1931         if (dataInputStream.peek() + 12 * numberOfDirectoryEntry > dataInputStream.mLength) {
1932             // Return if the size of entries is too big.
1933             return;
1934         }
1935
1936         if (DEBUG) {
1937             Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry);
1938         }
1939
1940         for (short i = 0; i < numberOfDirectoryEntry; ++i) {
1941             int tagNumber = dataInputStream.readUnsignedShort();
1942             int dataFormat = dataInputStream.readUnsignedShort();
1943             int numberOfComponents = dataInputStream.readInt();
1944             long nextEntryOffset = dataInputStream.peek() + 4;  // next four bytes is for data
1945                                                                 // offset or value.
1946             // Look up a corresponding tag from tag number
1947             final ExifTag tag = (ExifTag) sExifTagMapsForReading[hint].get(tagNumber);
1948
1949             if (DEBUG) {
1950                 Log.d(TAG, String.format("hint: %d, tagNumber: %d, tagName: %s, dataFormat: %d, " +
1951                         "numberOfComponents: %d", hint, tagNumber, tag != null ? tag.name : null,
1952                         dataFormat, numberOfComponents));
1953             }
1954
1955             if (tag == null || dataFormat <= 0 ||
1956                     dataFormat >= IFD_FORMAT_BYTES_PER_FORMAT.length) {
1957                 // Skip if the parsed tag number is not defined or invalid data format.
1958                 if (tag == null) {
1959                     Log.w(TAG, "Skip the tag entry since tag number is not defined: " + tagNumber);
1960                 } else {
1961                     Log.w(TAG, "Skip the tag entry since data format is invalid: " + dataFormat);
1962                 }
1963                 dataInputStream.seek(nextEntryOffset);
1964                 continue;
1965             }
1966
1967             // Read a value from data field or seek to the value offset which is stored in data
1968             // field if the size of the entry value is bigger than 4.
1969             int byteCount = numberOfComponents * IFD_FORMAT_BYTES_PER_FORMAT[dataFormat];
1970             if (byteCount > 4) {
1971                 long offset = dataInputStream.readUnsignedInt();
1972                 if (DEBUG) {
1973                     Log.d(TAG, "seek to data offset: " + offset);
1974                 }
1975                 if (offset + byteCount <= dataInputStream.mLength) {
1976                     dataInputStream.seek(offset);
1977                 } else {
1978                      // Skip if invalid data offset.
1979                     Log.w(TAG, "Skip the tag entry since data offset is invalid: " + offset);
1980                     dataInputStream.seek(nextEntryOffset);
1981                     continue;
1982                 }
1983             }
1984
1985             // Recursively parse IFD when a IFD pointer tag appears.
1986             int innerIfdHint = getIfdHintFromTagNumber(tagNumber);
1987             if (DEBUG) {
1988                 Log.d(TAG, "innerIfdHint: " + innerIfdHint + " byteCount: " + byteCount);
1989             }
1990
1991             if (innerIfdHint >= 0) {
1992                 long offset = -1L;
1993                 // Get offset from data field
1994                 switch (dataFormat) {
1995                     case IFD_FORMAT_USHORT: {
1996                         offset = dataInputStream.readUnsignedShort();
1997                         break;
1998                     }
1999                     case IFD_FORMAT_SSHORT: {
2000                         offset = dataInputStream.readShort();
2001                         break;
2002                     }
2003                     case IFD_FORMAT_ULONG: {
2004                         offset = dataInputStream.readUnsignedInt();
2005                         break;
2006                     }
2007                     case IFD_FORMAT_SLONG: {
2008                         offset = dataInputStream.readInt();
2009                         break;
2010                     }
2011                     default: {
2012                         // Nothing to do
2013                         break;
2014                     }
2015                 }
2016                 if (DEBUG) {
2017                     Log.d(TAG, String.format("Offset: %d, tagName: %s", offset, tag.name));
2018                 }
2019                 if (offset > 0L && offset < dataInputStream.mLength) {
2020                     dataInputStream.seek(offset);
2021                     readImageFileDirectory(dataInputStream, innerIfdHint);
2022                 } else {
2023                     Log.w(TAG, "Skip jump into the IFD since its offset is invalid: " + offset);
2024                 }
2025
2026                 dataInputStream.seek(nextEntryOffset);
2027                 continue;
2028             }
2029
2030             byte[] bytes = new byte[numberOfComponents * IFD_FORMAT_BYTES_PER_FORMAT[dataFormat]];
2031             dataInputStream.readFully(bytes);
2032             mAttributes[hint].put(
2033                     tag.name, new ExifAttribute(dataFormat, numberOfComponents, bytes));
2034             if (dataInputStream.peek() != nextEntryOffset) {
2035                 dataInputStream.seek(nextEntryOffset);
2036             }
2037         }
2038
2039         if (dataInputStream.peek() + 4 <= dataInputStream.mLength) {
2040             long nextIfdOffset = dataInputStream.readUnsignedInt();
2041             if (DEBUG) {
2042                 Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset));
2043             }
2044             // The next IFD offset needs to be bigger than 8
2045             // since the first IFD offset is at least 8.
2046             if (nextIfdOffset > 8 && nextIfdOffset < dataInputStream.mLength) {
2047                 dataInputStream.seek(nextIfdOffset);
2048                 readImageFileDirectory(dataInputStream, IFD_THUMBNAIL_HINT);
2049             }
2050         }
2051     }
2052
2053     // Gets the corresponding IFD group index of the given tag number for writing Exif Tags.
2054     private static int getIfdHintFromTagNumber(int tagNumber) {
2055         for (int i = 0; i < IFD_POINTER_TAG_HINTS.length; ++i) {
2056             if (IFD_POINTER_TAGS[i].number == tagNumber) {
2057                 return IFD_POINTER_TAG_HINTS[i];
2058             }
2059         }
2060         return -1;
2061     }
2062
2063     // Writes an Exif segment into the given output stream.
2064     private int writeExifSegment(ByteOrderAwarenessDataOutputStream dataOutputStream,
2065             int exifOffsetFromBeginning) throws IOException {
2066         // The following variables are for calculating each IFD tag group size in bytes.
2067         int[] ifdOffsets = new int[EXIF_TAGS.length];
2068         int[] ifdDataSizes = new int[EXIF_TAGS.length];
2069
2070         // Remove IFD pointer tags (we'll re-add it later.)
2071         for (ExifTag tag : IFD_POINTER_TAGS) {
2072             removeAttribute(tag.name);
2073         }
2074         // Remove old thumbnail data
2075         removeAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name);
2076         removeAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name);
2077
2078         // Remove null value tags.
2079         for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
2080             for (Object obj : mAttributes[hint].entrySet().toArray()) {
2081                 final Map.Entry entry = (Map.Entry) obj;
2082                 if (entry.getValue() == null) {
2083                     mAttributes[hint].remove(entry.getKey());
2084                 }
2085             }
2086         }
2087
2088         // Add IFD pointer tags. The next offset of primary image TIFF IFD will have thumbnail IFD
2089         // offset when there is one or more tags in the thumbnail IFD.
2090         if (!mAttributes[IFD_INTEROPERABILITY_HINT].isEmpty()) {
2091             mAttributes[IFD_EXIF_HINT].put(IFD_POINTER_TAGS[2].name,
2092                     ExifAttribute.createULong(0, mExifByteOrder));
2093         }
2094         if (!mAttributes[IFD_EXIF_HINT].isEmpty()) {
2095             mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[0].name,
2096                     ExifAttribute.createULong(0, mExifByteOrder));
2097         }
2098         if (!mAttributes[IFD_GPS_HINT].isEmpty()) {
2099             mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].name,
2100                     ExifAttribute.createULong(0, mExifByteOrder));
2101         }
2102         if (mHasThumbnail) {
2103             mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
2104                     ExifAttribute.createULong(0, mExifByteOrder));
2105             mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name,
2106                     ExifAttribute.createULong(mThumbnailLength, mExifByteOrder));
2107         }
2108
2109         // Calculate IFD group data area sizes. IFD group data area is assigned to save the entry
2110         // value which has a bigger size than 4 bytes.
2111         for (int i = 0; i < EXIF_TAGS.length; ++i) {
2112             int sum = 0;
2113             for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
2114                 final ExifAttribute exifAttribute = (ExifAttribute) entry.getValue();
2115                 final int size = exifAttribute.size();
2116                 if (size > 4) {
2117                     sum += size;
2118                 }
2119             }
2120             ifdDataSizes[i] += sum;
2121         }
2122
2123         // Calculate IFD offsets.
2124         int position = 8;
2125         for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
2126             if (!mAttributes[hint].isEmpty()) {
2127                 ifdOffsets[hint] = position;
2128                 position += 2 + mAttributes[hint].size() * 12 + 4 + ifdDataSizes[hint];
2129             }
2130         }
2131         if (mHasThumbnail) {
2132             int thumbnailOffset = position;
2133             mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
2134                     ExifAttribute.createULong(thumbnailOffset, mExifByteOrder));
2135             mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset;
2136             position += mThumbnailLength;
2137         }
2138
2139         // Calculate the total size
2140         int totalSize = position + 8;  // eight bytes is for header part.
2141         if (DEBUG) {
2142             Log.d(TAG, "totalSize length: " + totalSize);
2143             for (int i = 0; i < EXIF_TAGS.length; ++i) {
2144                 Log.d(TAG, String.format("index: %d, offsets: %d, tag count: %d, data sizes: %d",
2145                         i, ifdOffsets[i], mAttributes[i].size(), ifdDataSizes[i]));
2146             }
2147         }
2148
2149         // Update IFD pointer tags with the calculated offsets.
2150         if (!mAttributes[IFD_EXIF_HINT].isEmpty()) {
2151             mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[0].name,
2152                     ExifAttribute.createULong(ifdOffsets[IFD_EXIF_HINT], mExifByteOrder));
2153         }
2154         if (!mAttributes[IFD_GPS_HINT].isEmpty()) {
2155             mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].name,
2156                     ExifAttribute.createULong(ifdOffsets[IFD_GPS_HINT], mExifByteOrder));
2157         }
2158         if (!mAttributes[IFD_INTEROPERABILITY_HINT].isEmpty()) {
2159             mAttributes[IFD_EXIF_HINT].put(IFD_POINTER_TAGS[2].name, ExifAttribute.createULong(
2160                     ifdOffsets[IFD_INTEROPERABILITY_HINT], mExifByteOrder));
2161         }
2162
2163         // Write TIFF Headers. See JEITA CP-3451C Table 1. page 10.
2164         dataOutputStream.writeUnsignedShort(totalSize);
2165         dataOutputStream.write(IDENTIFIER_EXIF_APP1);
2166         dataOutputStream.writeShort(mExifByteOrder == ByteOrder.BIG_ENDIAN
2167                 ? BYTE_ALIGN_MM : BYTE_ALIGN_II);
2168         dataOutputStream.setByteOrder(mExifByteOrder);
2169         dataOutputStream.writeUnsignedShort(0x2a);
2170         dataOutputStream.writeUnsignedInt(8);
2171
2172         // Write IFD groups. See JEITA CP-3451C Figure 7. page 12.
2173         for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
2174             if (!mAttributes[hint].isEmpty()) {
2175                 // See JEITA CP-3451C 4.6.2 IFD structure. page 13.
2176                 // Write entry count
2177                 dataOutputStream.writeUnsignedShort(mAttributes[hint].size());
2178
2179                 // Write entry info
2180                 int dataOffset = ifdOffsets[hint] + 2 + mAttributes[hint].size() * 12 + 4;
2181                 for (Map.Entry entry : (Set<Map.Entry>) mAttributes[hint].entrySet()) {
2182                     // Convert tag name to tag number.
2183                     final ExifTag tag = (ExifTag) sExifTagMapsForWriting[hint].get(entry.getKey());
2184                     final int tagNumber = tag.number;
2185                     final ExifAttribute attribute = (ExifAttribute) entry.getValue();
2186                     final int size = attribute.size();
2187
2188                     dataOutputStream.writeUnsignedShort(tagNumber);
2189                     dataOutputStream.writeUnsignedShort(attribute.format);
2190                     dataOutputStream.writeInt(attribute.numberOfComponents);
2191                     if (size > 4) {
2192                         dataOutputStream.writeUnsignedInt(dataOffset);
2193                         dataOffset += size;
2194                     } else {
2195                         dataOutputStream.write(attribute.bytes);
2196                         // Fill zero up to 4 bytes
2197                         if (size < 4) {
2198                             for (int i = size; i < 4; ++i) {
2199                                 dataOutputStream.writeByte(0);
2200                             }
2201                         }
2202                     }
2203                 }
2204
2205                 // Write the next offset. It writes the offset of thumbnail IFD if there is one or
2206                 // more tags in the thumbnail IFD when the current IFD is the primary image TIFF
2207                 // IFD; Otherwise 0.
2208                 if (hint == 0 && !mAttributes[IFD_THUMBNAIL_HINT].isEmpty()) {
2209                     dataOutputStream.writeUnsignedInt(ifdOffsets[IFD_THUMBNAIL_HINT]);
2210                 } else {
2211                     dataOutputStream.writeUnsignedInt(0);
2212                 }
2213
2214                 // Write values of data field exceeding 4 bytes after the next offset.
2215                 for (Map.Entry entry : (Set<Map.Entry>) mAttributes[hint].entrySet()) {
2216                     ExifAttribute attribute = (ExifAttribute) entry.getValue();
2217
2218                     if (attribute.bytes.length > 4) {
2219                         dataOutputStream.write(attribute.bytes, 0, attribute.bytes.length);
2220                     }
2221                 }
2222             }
2223         }
2224
2225         // Write thumbnail
2226         if (mHasThumbnail) {
2227             dataOutputStream.write(getThumbnail());
2228         }
2229
2230         // Reset the byte order to big endian in order to write remaining parts of the JPEG file.
2231         dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
2232
2233         return totalSize;
2234     }
2235
2236     /**
2237      * Determines the data format of EXIF entry value.
2238      *
2239      * @param entryValue The value to be determined.
2240      * @return Returns two data formats gussed as a pair in integer. If there is no two candidate
2241                data formats for the given entry value, returns {@code -1} in the second of the pair.
2242      */
2243     private static Pair<Integer, Integer> guessDataFormat(String entryValue) {
2244         // See TIFF 6.0 spec Types. page 15.
2245         // Take the first component if there are more than one component.
2246         if (entryValue.contains(",")) {
2247             String[] entryValues = entryValue.split(",");
2248             Pair<Integer, Integer> dataFormat = guessDataFormat(entryValues[0]);
2249             if (dataFormat.first == IFD_FORMAT_STRING) {
2250                 return dataFormat;
2251             }
2252             for (int i = 1; i < entryValues.length; ++i) {
2253                 final Pair<Integer, Integer> guessDataFormat = guessDataFormat(entryValues[i]);
2254                 int first = -1, second = -1;
2255                 if (guessDataFormat.first == dataFormat.first
2256                         || guessDataFormat.second == dataFormat.first) {
2257                     first = dataFormat.first;
2258                 }
2259                 if (dataFormat.second != -1 && (guessDataFormat.first == dataFormat.second
2260                         || guessDataFormat.second == dataFormat.second)) {
2261                     second = dataFormat.second;
2262                 }
2263                 if (first == -1 && second == -1) {
2264                     return new Pair<>(IFD_FORMAT_STRING, -1);
2265                 }
2266                 if (first == -1) {
2267                     dataFormat = new Pair<>(second, -1);
2268                     continue;
2269                 }
2270                 if (second == -1) {
2271                     dataFormat = new Pair<>(first, -1);
2272                     continue;
2273                 }
2274             }
2275             return dataFormat;
2276         }
2277
2278         if (entryValue.contains("/")) {
2279             String[] rationalNumber = entryValue.split("/");
2280             if (rationalNumber.length == 2) {
2281                 try {
2282                     long numerator = Long.parseLong(rationalNumber[0]);
2283                     long denominator = Long.parseLong(rationalNumber[1]);
2284                     if (numerator < 0L || denominator < 0L) {
2285                         return new Pair<>(IFD_FORMAT_SRATIONAL, - 1);
2286                     }
2287                     if (numerator > Integer.MAX_VALUE || denominator > Integer.MAX_VALUE) {
2288                         return new Pair<>(IFD_FORMAT_URATIONAL, -1);
2289                     }
2290                     return new Pair<>(IFD_FORMAT_SRATIONAL, IFD_FORMAT_URATIONAL);
2291                 } catch (NumberFormatException e)  {
2292                     // Ignored
2293                 }
2294             }
2295             return new Pair<>(IFD_FORMAT_STRING, -1);
2296         }
2297         try {
2298             Long longValue = Long.parseLong(entryValue);
2299             if (longValue >= 0 && longValue <= 65535) {
2300                 return new Pair<>(IFD_FORMAT_USHORT, IFD_FORMAT_ULONG);
2301             }
2302             if (longValue < 0) {
2303                 return new Pair<>(IFD_FORMAT_SLONG, -1);
2304             }
2305             return new Pair<>(IFD_FORMAT_ULONG, -1);
2306         } catch (NumberFormatException e) {
2307             // Ignored
2308         }
2309         try {
2310             Double.parseDouble(entryValue);
2311             return new Pair<>(IFD_FORMAT_DOUBLE, -1);
2312         } catch (NumberFormatException e) {
2313             // Ignored
2314         }
2315         return new Pair<>(IFD_FORMAT_STRING, -1);
2316     }
2317
2318     // An input stream to parse EXIF data area, which can be written in either little or big endian
2319     // order.
2320     private static class ByteOrderAwarenessDataInputStream extends ByteArrayInputStream {
2321         private static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN;
2322         private static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN;
2323
2324         private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
2325         private final long mLength;
2326         private long mPosition;
2327
2328         public ByteOrderAwarenessDataInputStream(byte[] bytes) {
2329             super(bytes);
2330             mLength = bytes.length;
2331             mPosition = 0L;
2332         }
2333
2334         public void setByteOrder(ByteOrder byteOrder) {
2335             mByteOrder = byteOrder;
2336         }
2337
2338         public void seek(long byteCount) throws IOException {
2339             mPosition = 0L;
2340             reset();
2341             if (skip(byteCount) != byteCount) {
2342                 throw new IOException("Couldn't seek up to the byteCount");
2343             }
2344         }
2345
2346         public long peek() {
2347             return mPosition;
2348         }
2349
2350         public void readFully(byte[] buffer) throws IOException {
2351             mPosition += buffer.length;
2352             if (mPosition > mLength) {
2353                 throw new EOFException();
2354             }
2355             if (super.read(buffer, 0, buffer.length) != buffer.length) {
2356                 throw new IOException("Couldn't read up to the length of buffer");
2357             }
2358         }
2359
2360         public byte readByte() throws IOException {
2361             ++mPosition;
2362             if (mPosition > mLength) {
2363                 throw new EOFException();
2364             }
2365             int ch = super.read();
2366             if (ch < 0) {
2367                 throw new EOFException();
2368             }
2369             return (byte) ch;
2370         }
2371
2372         public short readShort() throws IOException {
2373             mPosition += 2;
2374             if (mPosition > mLength) {
2375                 throw new EOFException();
2376             }
2377             int ch1 = super.read();
2378             int ch2 = super.read();
2379             if ((ch1 | ch2) < 0) {
2380                 throw new EOFException();
2381             }
2382             if (mByteOrder == LITTLE_ENDIAN) {
2383                 return (short) ((ch2 << 8) + (ch1));
2384             } else if (mByteOrder == BIG_ENDIAN) {
2385                 return (short) ((ch1 << 8) + (ch2));
2386             }
2387             throw new IOException("Invalid byte order: " + mByteOrder);
2388         }
2389
2390         public int readInt() throws IOException {
2391             mPosition += 4;
2392             if (mPosition > mLength) {
2393                 throw new EOFException();
2394             }
2395             int ch1 = super.read();
2396             int ch2 = super.read();
2397             int ch3 = super.read();
2398             int ch4 = super.read();
2399             if ((ch1 | ch2 | ch3 | ch4) < 0) {
2400                 throw new EOFException();
2401             }
2402             if (mByteOrder == LITTLE_ENDIAN) {
2403                 return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + ch1);
2404             } else if (mByteOrder == BIG_ENDIAN) {
2405                 return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
2406             }
2407             throw new IOException("Invalid byte order: " + mByteOrder);
2408         }
2409
2410         @Override
2411         public long skip(long byteCount) {
2412             long skipped = super.skip(Math.min(byteCount, mLength - mPosition));
2413             mPosition += skipped;
2414             return skipped;
2415         }
2416
2417         public int readUnsignedShort() throws IOException {
2418             mPosition += 2;
2419             if (mPosition > mLength) {
2420                 throw new EOFException();
2421             }
2422             int ch1 = super.read();
2423             int ch2 = super.read();
2424             if ((ch1 | ch2) < 0) {
2425                 throw new EOFException();
2426             }
2427             if (mByteOrder == LITTLE_ENDIAN) {
2428                 return ((ch2 << 8) + (ch1));
2429             } else if (mByteOrder == BIG_ENDIAN) {
2430                 return ((ch1 << 8) + (ch2));
2431             }
2432             throw new IOException("Invalid byte order: " + mByteOrder);
2433         }
2434
2435         public long readUnsignedInt() throws IOException {
2436             return readInt() & 0xffffffffL;
2437         }
2438
2439         public long readLong() throws IOException {
2440             mPosition += 8;
2441             if (mPosition > mLength) {
2442                 throw new EOFException();
2443             }
2444             int ch1 = super.read();
2445             int ch2 = super.read();
2446             int ch3 = super.read();
2447             int ch4 = super.read();
2448             int ch5 = super.read();
2449             int ch6 = super.read();
2450             int ch7 = super.read();
2451             int ch8 = super.read();
2452             if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) {
2453                 throw new EOFException();
2454             }
2455             if (mByteOrder == LITTLE_ENDIAN) {
2456                 return (((long) ch8 << 56) + ((long) ch7 << 48) + ((long) ch6 << 40)
2457                         + ((long) ch5 << 32) + ((long) ch4 << 24) + ((long) ch3 << 16)
2458                         + ((long) ch2 << 8) + ch1);
2459             } else if (mByteOrder == BIG_ENDIAN) {
2460                 return (((long) ch1 << 56) + ((long) ch2 << 48) + ((long) ch3 << 40)
2461                         + ((long) ch4 << 32) + ((long) ch5 << 24) + ((long) ch6 << 16)
2462                         + ((long) ch7 << 8) + ch8);
2463             }
2464             throw new IOException("Invalid byte order: " + mByteOrder);
2465         }
2466
2467         public float readFloat() throws IOException {
2468             return Float.intBitsToFloat(readInt());
2469         }
2470
2471         public double readDouble() throws IOException {
2472             return Double.longBitsToDouble(readLong());
2473         }
2474     }
2475
2476     // An output stream to write EXIF data area, which can be written in either little or big endian
2477     // order.
2478     private static class ByteOrderAwarenessDataOutputStream extends FilterOutputStream {
2479         private final OutputStream mOutputStream;
2480         private ByteOrder mByteOrder;
2481
2482         public ByteOrderAwarenessDataOutputStream(OutputStream out, ByteOrder byteOrder) {
2483             super(out);
2484             mOutputStream = out;
2485             mByteOrder = byteOrder;
2486         }
2487
2488         public void setByteOrder(ByteOrder byteOrder) {
2489             mByteOrder = byteOrder;
2490         }
2491
2492         public void write(byte[] bytes) throws IOException {
2493             mOutputStream.write(bytes);
2494         }
2495
2496         public void write(byte[] bytes, int offset, int length) throws IOException {
2497             mOutputStream.write(bytes, offset, length);
2498         }
2499
2500         public void writeByte(int val) throws IOException {
2501             mOutputStream.write(val);
2502         }
2503
2504         public void writeShort(short val) throws IOException {
2505             if (mByteOrder == ByteOrder.LITTLE_ENDIAN) {
2506                 mOutputStream.write((val >>> 0) & 0xFF);
2507                 mOutputStream.write((val >>> 8) & 0xFF);
2508             } else if (mByteOrder == ByteOrder.BIG_ENDIAN) {
2509                 mOutputStream.write((val >>> 8) & 0xFF);
2510                 mOutputStream.write((val >>> 0) & 0xFF);
2511             }
2512         }
2513
2514         public void writeInt(int val) throws IOException {
2515             if (mByteOrder == ByteOrder.LITTLE_ENDIAN) {
2516                 mOutputStream.write((val >>> 0) & 0xFF);
2517                 mOutputStream.write((val >>> 8) & 0xFF);
2518                 mOutputStream.write((val >>> 16) & 0xFF);
2519                 mOutputStream.write((val >>> 24) & 0xFF);
2520             } else if (mByteOrder == ByteOrder.BIG_ENDIAN) {
2521                 mOutputStream.write((val >>> 24) & 0xFF);
2522                 mOutputStream.write((val >>> 16) & 0xFF);
2523                 mOutputStream.write((val >>> 8) & 0xFF);
2524                 mOutputStream.write((val >>> 0) & 0xFF);
2525             }
2526         }
2527
2528         public void writeUnsignedShort(int val) throws IOException {
2529             writeShort((short) val);
2530         }
2531
2532         public void writeUnsignedInt(long val) throws IOException {
2533             writeInt((int) val);
2534         }
2535     }
2536 }