ExifInterface.java revision bc4fd2c642f7db0a091fe6e9179b0380eda16b36
114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon/*
214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Copyright (C) 2007 The Android Open Source Project
314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon *
414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Licensed under the Apache License, Version 2.0 (the "License");
514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * you may not use this file except in compliance with the License.
614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * You may obtain a copy of the License at
714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon *
814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon *      http://www.apache.org/licenses/LICENSE-2.0
914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon *
1014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Unless required by applicable law or agreed to in writing, software
1114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * distributed under the License is distributed on an "AS IS" BASIS,
1214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * See the License for the specific language governing permissions and
1414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * limitations under the License.
1514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */
1614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
1714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonpackage android.support.media;
1814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
1914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.content.res.AssetManager;
2014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.graphics.Bitmap;
2114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.graphics.BitmapFactory;
22c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chenimport android.location.Location;
2314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.support.annotation.IntDef;
2414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.support.annotation.NonNull;
2514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.util.Log;
2614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport android.util.Pair;
2714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
2814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.BufferedInputStream;
2914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.ByteArrayInputStream;
3014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.Closeable;
3114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.DataInput;
3214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.DataInputStream;
3314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.EOFException;
3414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.File;
3514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.FileInputStream;
3614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.FileNotFoundException;
3714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.FileOutputStream;
3814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.FilterOutputStream;
3914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.IOException;
4014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.InputStream;
4114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.io.OutputStream;
4214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.lang.annotation.Retention;
4314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.lang.annotation.RetentionPolicy;
4414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.nio.ByteBuffer;
4514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.nio.ByteOrder;
4614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.nio.charset.Charset;
4714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.text.ParsePosition;
4814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.text.SimpleDateFormat;
4914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.Arrays;
5014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.Date;
5114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.HashMap;
5214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.HashSet;
53bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangrenimport java.util.List;
5414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.Map;
5514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.TimeZone;
56c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chenimport java.util.concurrent.TimeUnit;
5714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.regex.Matcher;
5814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonimport java.util.regex.Pattern;
5914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
6014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon/**
6114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * This is a class for reading and writing Exif tags in a JPEG file or a RAW image file.
6214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * <p>
6314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Supported formats are: JPEG, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW and RAF.
6414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * <p>
6514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon * Attribute mutation is supported for JPEG image files.
6614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon */
6714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moonpublic class ExifInterface {
6814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String TAG = "ExifInterface";
6914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final boolean DEBUG = false;
7014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
7114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // The Exif tag names. See Tiff 6.0 Section 3 and Section 8.
7214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
7314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_ARTIST = "Artist";
7414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
7514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_BITS_PER_SAMPLE = "BitsPerSample";
7614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
7714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_COMPRESSION = "Compression";
7814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
7914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_COPYRIGHT = "Copyright";
8014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
8114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_DATETIME = "DateTime";
8214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
8314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_IMAGE_DESCRIPTION = "ImageDescription";
8414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
8514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_IMAGE_LENGTH = "ImageLength";
8614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
8714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_IMAGE_WIDTH = "ImageWidth";
8814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
8914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
9014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
9114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
9214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
9314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_MAKE = "Make";
9414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
9514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_MODEL = "Model";
9614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
9714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_ORIENTATION = "Orientation";
9814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
9914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
10014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
10114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
10214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
10314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
10414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
10514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
10614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
10714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_RESOLUTION_UNIT = "ResolutionUnit";
10814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
10914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_ROWS_PER_STRIP = "RowsPerStrip";
11014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
11114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
11214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
11314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SOFTWARE = "Software";
11414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
11514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
11614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
11714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_STRIP_OFFSETS = "StripOffsets";
11814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
11914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_TRANSFER_FUNCTION = "TransferFunction";
12014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
12114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_WHITE_POINT = "WhitePoint";
12214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
12314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_X_RESOLUTION = "XResolution";
12414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
12514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
12614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
12714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
12814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
12914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
13014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
13114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_Y_RESOLUTION = "YResolution";
13214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
13314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_APERTURE_VALUE = "ApertureValue";
13414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
13514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
13614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
13714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_CFA_PATTERN = "CFAPattern";
13814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
13914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_COLOR_SPACE = "ColorSpace";
14014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
14114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
14214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
14314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
14414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
14514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_CONTRAST = "Contrast";
14614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
14714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_CUSTOM_RENDERED = "CustomRendered";
14814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
14914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
15014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
15114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
15214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
15314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
15414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is double. */
15514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
15614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
15714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_EXIF_VERSION = "ExifVersion";
15814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is double. */
15914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
16014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
16114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_EXPOSURE_INDEX = "ExposureIndex";
16214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
16314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_EXPOSURE_MODE = "ExposureMode";
16414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
16514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
16614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is double. */
16714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_EXPOSURE_TIME = "ExposureTime";
16814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is double. */
16914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_F_NUMBER = "FNumber";
17014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
17114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_FILE_SOURCE = "FileSource";
17214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
17314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_FLASH = "Flash";
17414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
17514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_FLASH_ENERGY = "FlashEnergy";
17614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
17714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_FLASHPIX_VERSION = "FlashpixVersion";
17814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
17914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_FOCAL_LENGTH = "FocalLength";
18014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
18114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
18214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
18314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
18414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
18514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
18614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
18714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
18814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
18914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GAIN_CONTROL = "GainControl";
19014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
19114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
19214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
19314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
19414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
19514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_LIGHT_SOURCE = "LightSource";
19614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
19714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_MAKER_NOTE = "MakerNote";
19814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
19914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
20014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
20114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_METERING_MODE = "MeteringMode";
20214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
20314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
20414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
20514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_OECF = "OECF";
20614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
20714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
20814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
20914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
21014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
21114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
21214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
21314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SATURATION = "Saturation";
21414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
21514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
21614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
21714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SCENE_TYPE = "SceneType";
21814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
21914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SENSING_METHOD = "SensingMethod";
22014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
22114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SHARPNESS = "Sharpness";
22214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
22314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
22414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
22514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
22614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
22714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
22814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
22914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SUBFILE_TYPE = "SubfileType";
23014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
23114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SUBSEC_TIME = "SubSecTime";
23214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
23314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
23414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
23514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
23614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
23714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SUBJECT_AREA = "SubjectArea";
23814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is double. */
23914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SUBJECT_DISTANCE = "SubjectDistance";
24014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
24114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
24214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
24314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_SUBJECT_LOCATION = "SubjectLocation";
24414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
24514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_USER_COMMENT = "UserComment";
24614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
24714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_WHITE_BALANCE = "WhiteBalance";
24814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
24914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * The altitude (in meters) based on the reference in TAG_GPS_ALTITUDE_REF.
25014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Type is rational.
25114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
25214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_ALTITUDE = "GPSAltitude";
25314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
25414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * 0 if the altitude is above sea level. 1 if the altitude is below sea
25514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * level. Type is int.
25614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
25714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
25814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
25914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
26014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
26114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_DOP = "GPSDOP";
26214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
26314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_DATESTAMP = "GPSDateStamp";
26414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
26514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_DEST_BEARING = "GPSDestBearing";
26614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
26714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
26814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
26914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
27014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
27114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
27214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
27314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
27414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
27514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
27614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
27714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
27814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
27914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
28014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
28114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
28214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
28314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
28414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
28514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
28614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. Format is "num1/denom1,num2/denom2,num3/denom3". */
28714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_LATITUDE = "GPSLatitude";
28814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
28914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
29014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. Format is "num1/denom1,num2/denom2,num3/denom3". */
29114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_LONGITUDE = "GPSLongitude";
29214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
29314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
29414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
29514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_MAP_DATUM = "GPSMapDatum";
29614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
29714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
29814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. Name of GPS processing method used for location finding. */
29914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
30014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
30114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_SATELLITES = "GPSSatellites";
30214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
30314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_SPEED = "GPSSpeed";
30414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
30514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_SPEED_REF = "GPSSpeedRef";
30614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
30714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_STATUS = "GPSStatus";
30814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. Format is "hh:mm:ss". */
30914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
31014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is rational. */
31114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_TRACK = "GPSTrack";
31214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
31314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_TRACK_REF = "GPSTrackRef";
31414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
31514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_GPS_VERSION_ID = "GPSVersionID";
31614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is String. */
31714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
31814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
31914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
32014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. */
32114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
32214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. DNG Specification 1.4.0.0. Section 4 */
32314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_DNG_VERSION = "DNGVersion";
32414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. DNG Specification 1.4.0.0. Section 4 */
32514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_DEFAULT_CROP_SIZE = "DefaultCropSize";
32614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is undefined. See Olympus MakerNote tags in http://www.exiv2.org/tags-olympus.html. */
32714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_ORF_THUMBNAIL_IMAGE = "ThumbnailImage";
32814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. See Olympus Camera Settings tags in http://www.exiv2.org/tags-olympus.html. */
32914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart";
33014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. See Olympus Camera Settings tags in http://www.exiv2.org/tags-olympus.html. */
33114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
33214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** Type is int. See Olympus Image Processing tags in http://www.exiv2.org/tags-olympus.html. */
33314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_ORF_ASPECT_FRAME = "AspectFrame";
33414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
33514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Type is int. See PanasonicRaw tags in
33614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
33714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
33814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder";
33914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
34014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Type is int. See PanasonicRaw tags in
34114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
34214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
34314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder";
34414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
34514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Type is int. See PanasonicRaw tags in
34614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
34714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
34814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder";
34914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
35014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Type is int. See PanasonicRaw tags in
35114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
35214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
35314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_RW2_SENSOR_TOP_BORDER = "SensorTopBorder";
35414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
35514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Type is int. See PanasonicRaw tags in
35614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
35714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
35814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_RW2_ISO = "ISO";
35914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
36014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Type is undefined. See PanasonicRaw tags in
36114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
36214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
36314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw";
36414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
36514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
36614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Private tags used for pointing the other IFD offsets.
36714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * The types of the following tags are int.
36814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * See JEITA CP-3451C Section 4.6.3: Exif-specific IFD.
36914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * For SubIFD, see Note 1 of Adobe PageMaker® 6.0 TIFF Technical Notes.
37014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
37114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String TAG_EXIF_IFD_POINTER = "ExifIFDPointer";
37214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String TAG_GPS_INFO_IFD_POINTER = "GPSInfoIFDPointer";
37314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String TAG_INTEROPERABILITY_IFD_POINTER = "InteroperabilityIFDPointer";
37414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String TAG_SUB_IFD_POINTER = "SubIFDPointer";
37514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Proprietary pointer tags used for ORF files.
37614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // See http://www.exiv2.org/tags-olympus.html
37714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String TAG_ORF_CAMERA_SETTINGS_IFD_POINTER = "CameraSettingsIFDPointer";
37814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String TAG_ORF_IMAGE_PROCESSING_IFD_POINTER = "ImageProcessingIFDPointer";
37914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
38014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Private tags used for thumbnail information.
38114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String TAG_HAS_THUMBNAIL = "HasThumbnail";
38214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String TAG_THUMBNAIL_OFFSET = "ThumbnailOffset";
38314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String TAG_THUMBNAIL_LENGTH = "ThumbnailLength";
38414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String TAG_THUMBNAIL_DATA = "ThumbnailData";
38514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int MAX_THUMBNAIL_SIZE = 512;
38614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
38714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Constants used for the Orientation Exif tag.
38814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final int ORIENTATION_UNDEFINED = 0;
38914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final int ORIENTATION_NORMAL = 1;
39014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final int ORIENTATION_FLIP_HORIZONTAL = 2;  // left right reversed mirror
39114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final int ORIENTATION_ROTATE_180 = 3;
39214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final int ORIENTATION_FLIP_VERTICAL = 4;  // upside down mirror
39314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // flipped about top-left <--> bottom-right axis
39414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final int ORIENTATION_TRANSPOSE = 5;
395bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    public static final int ORIENTATION_ROTATE_90 = 6;  // rotate 90 degree clockwise
39614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // flipped about top-right <--> bottom-left axis
39714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final int ORIENTATION_TRANSVERSE = 7;
398bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    public static final int ORIENTATION_ROTATE_270 = 8;  // rotate 270 degree clockwise
399bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    private static final List<Integer> ROTATION_ORDER = Arrays.asList(ORIENTATION_NORMAL,
400bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            ORIENTATION_ROTATE_90, ORIENTATION_ROTATE_180, ORIENTATION_ROTATE_270);
401bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    private static final List<Integer> FLIPPED_ROTATION_ORDER = Arrays.asList(
402bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            ORIENTATION_FLIP_HORIZONTAL, ORIENTATION_TRANSVERSE, ORIENTATION_FLIP_VERTICAL,
403bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            ORIENTATION_TRANSPOSE);
40414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
40514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Constants used for white balance
40614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final int WHITEBALANCE_AUTO = 0;
40714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public static final int WHITEBALANCE_MANUAL = 1;
40814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
40914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Maximum size for checking file type signature (see image_type_recognition_lite.cc)
41014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int SIGNATURE_CHECK_SIZE = 5000;
41114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
41214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte[] JPEG_SIGNATURE = new byte[] {(byte) 0xff, (byte) 0xd8, (byte) 0xff};
41314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String RAF_SIGNATURE = "FUJIFILMCCD-RAW";
41414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int RAF_OFFSET_TO_JPEG_IMAGE_OFFSET = 84;
41514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int RAF_INFO_SIZE = 160;
41614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int RAF_JPEG_LENGTH_VALUE_SIZE = 4;
41714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
41814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // See http://fileformats.archiveteam.org/wiki/Olympus_ORF
41914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final short ORF_SIGNATURE_1 = 0x4f52;
42014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final short ORF_SIGNATURE_2 = 0x5352;
42114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // There are two formats for Olympus Makernote Headers. Each has different identifiers and
42214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // offsets to the actual data.
42314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // See http://www.exiv2.org/makernote.html#R1
42414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte[] ORF_MAKER_NOTE_HEADER_1 = new byte[] {(byte) 0x4f, (byte) 0x4c,
42514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            (byte) 0x59, (byte) 0x4d, (byte) 0x50, (byte) 0x00}; // "OLYMP\0"
42614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte[] ORF_MAKER_NOTE_HEADER_2 = new byte[] {(byte) 0x4f, (byte) 0x4c,
42714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            (byte) 0x59, (byte) 0x4d, (byte) 0x50, (byte) 0x55, (byte) 0x53, (byte) 0x00,
42814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            (byte) 0x49, (byte) 0x49}; // "OLYMPUS\0II"
42914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int ORF_MAKER_NOTE_HEADER_1_SIZE = 8;
43014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int ORF_MAKER_NOTE_HEADER_2_SIZE = 12;
43114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
43214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // See http://fileformats.archiveteam.org/wiki/RW2
43314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final short RW2_SIGNATURE = 0x0055;
43414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
43514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // See http://fileformats.archiveteam.org/wiki/Pentax_PEF
43614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String PEF_SIGNATURE = "PENTAX";
43714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // See http://www.exiv2.org/makernote.html#R11
43814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int PEF_MAKER_NOTE_SKIP_SIZE = 6;
43914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
44014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static SimpleDateFormat sFormatter;
44114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
44214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // See Exchangeable image file format for digital still cameras: Exif version 2.2.
44314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // The following values are for parsing EXIF data area. There are tag groups in EXIF data area.
44414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // They are called "Image File Directory". They have multiple data formats to cover various
44514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // image metadata from GPS longitude to camera model name.
44614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
44714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Types of Exif byte alignments (see JEITA CP-3451C Section 4.5.2)
44814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final short BYTE_ALIGN_II = 0x4949;  // II: Intel order
44914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final short BYTE_ALIGN_MM = 0x4d4d;  // MM: Motorola order
45014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
45114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // TIFF Header Fixed Constant (see JEITA CP-3451C Section 4.5.2)
45214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte START_CODE = 0x2a; // 42
45314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_OFFSET = 8;
45414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
45514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Formats for the value in IFD entry (See TIFF 6.0 Section 2, "Image File Directory".)
45614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_BYTE = 1;
45714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_STRING = 2;
45814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_USHORT = 3;
45914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_ULONG = 4;
46014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_URATIONAL = 5;
46114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_SBYTE = 6;
46214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_UNDEFINED = 7;
46314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_SSHORT = 8;
46414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_SLONG = 9;
46514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_SRATIONAL = 10;
46614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_SINGLE = 11;
46714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_DOUBLE = 12;
46814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Format indicating a new IFD entry (See Adobe PageMaker® 6.0 TIFF Technical Notes, "New Tag")
46914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_FORMAT_IFD = 13;
47014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Names for the data formats for debugging purpose.
47114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final String[] IFD_FORMAT_NAMES = new String[] {
47214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            "", "BYTE", "STRING", "USHORT", "ULONG", "URATIONAL", "SBYTE", "UNDEFINED", "SSHORT",
47314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            "SLONG", "SRATIONAL", "SINGLE", "DOUBLE"
47414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
47514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Sizes of the components of each IFD value format
47614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int[] IFD_FORMAT_BYTES_PER_FORMAT = new int[] {
47714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 1
47814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
47914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte[] EXIF_ASCII_PREFIX = new byte[] {
48014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0
48114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
48214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
48314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
48414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Constants used for Compression tag.
48514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * For Value 1, 2, 32773, see TIFF 6.0 Spec Section 3: Bilevel Images, Compression
48614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * For Value 6, see TIFF 6.0 Spec Section 22: JPEG Compression, Extensions to Existing Fields
48714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * For Value 7, 8, 34892, see DNG Specification 1.4.0.0. Section 3, Compression
48814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
48914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int DATA_UNCOMPRESSED = 1;
49014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int DATA_HUFFMAN_COMPRESSED = 2;
49114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int DATA_JPEG = 6;
49214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int DATA_JPEG_COMPRESSED = 7;
49314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int DATA_DEFLATE_ZIP = 8;
49414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int DATA_PACK_BITS_COMPRESSED = 32773;
49514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int DATA_LOSSY_JPEG = 34892;
49614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
49714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
49814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Constants used for BitsPerSample tag.
49914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * For RGB, see TIFF 6.0 Spec Section 6, Differences from Palette Color Images
50014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * For Greyscale, see TIFF 6.0 Spec Section 4, Differences from Bilevel Images
50114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
50214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int[] BITS_PER_SAMPLE_RGB = new int[] { 8, 8, 8 };
50314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int[] BITS_PER_SAMPLE_GREYSCALE_1 = new int[] { 4 };
50414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int[] BITS_PER_SAMPLE_GREYSCALE_2 = new int[] { 8 };
50514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
50614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
50714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Constants used for PhotometricInterpretation tag.
50814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * For White/Black, see Section 3, Color.
50914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * See TIFF 6.0 Spec Section 22, Minimum Requirements for TIFF with JPEG Compression.
51014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
51114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO = 0;
51214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO = 1;
51314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int PHOTOMETRIC_INTERPRETATION_RGB = 2;
51414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int PHOTOMETRIC_INTERPRETATION_YCBCR = 6;
51514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
51614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
51714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Constants used for NewSubfileType tag.
51814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * See TIFF 6.0 Spec Section 8
51914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * */
52014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int ORIGINAL_RESOLUTION_IMAGE = 0;
52114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int REDUCED_RESOLUTION_IMAGE = 1;
52214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
52314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // A class for indicating EXIF rational type.
52414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static class Rational {
52514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public final long numerator;
52614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public final long denominator;
52714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
528c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        private Rational(double value) {
529c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen            this((long) (value * 10000), 10000);
530c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        }
531c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen
53214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private Rational(long numerator, long denominator) {
53314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Handle erroneous case
53414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (denominator == 0) {
53514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                this.numerator = 0;
53614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                this.denominator = 1;
53714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return;
53814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
53914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.numerator = numerator;
54014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.denominator = denominator;
54114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
54214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
54314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
54414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public String toString() {
54514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return numerator + "/" + denominator;
54614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
54714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
54814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public double calculate() {
54914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return (double) numerator / denominator;
55014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
55114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
55214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
55314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // A class for indicating EXIF attribute.
55414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static class ExifAttribute {
55514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public final int format;
55614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public final int numberOfComponents;
55714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public final byte[] bytes;
55814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
55914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private ExifAttribute(int format, int numberOfComponents, byte[] bytes) {
56014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.format = format;
56114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.numberOfComponents = numberOfComponents;
56214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.bytes = bytes;
56314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
56414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
56514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createUShort(int[] values, ByteOrder byteOrder) {
56614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            final ByteBuffer buffer = ByteBuffer.wrap(
56714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_USHORT] * values.length]);
56814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            buffer.order(byteOrder);
56914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (int value : values) {
57014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                buffer.putShort((short) value);
57114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
57214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return new ExifAttribute(IFD_FORMAT_USHORT, values.length, buffer.array());
57314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
57414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
57514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createUShort(int value, ByteOrder byteOrder) {
57614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return createUShort(new int[] {value}, byteOrder);
57714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
57814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
57914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createULong(long[] values, ByteOrder byteOrder) {
58014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            final ByteBuffer buffer = ByteBuffer.wrap(
58114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_ULONG] * values.length]);
58214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            buffer.order(byteOrder);
58314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (long value : values) {
58414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                buffer.putInt((int) value);
58514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
58614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return new ExifAttribute(IFD_FORMAT_ULONG, values.length, buffer.array());
58714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
58814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
58914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createULong(long value, ByteOrder byteOrder) {
59014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return createULong(new long[] {value}, byteOrder);
59114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
59214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
59314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createSLong(int[] values, ByteOrder byteOrder) {
59414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            final ByteBuffer buffer = ByteBuffer.wrap(
59514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_SLONG] * values.length]);
59614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            buffer.order(byteOrder);
59714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (int value : values) {
59814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                buffer.putInt(value);
59914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
60014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return new ExifAttribute(IFD_FORMAT_SLONG, values.length, buffer.array());
60114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
60214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
60314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createSLong(int value, ByteOrder byteOrder) {
60414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return createSLong(new int[] {value}, byteOrder);
60514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
60614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
60714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createByte(String value) {
60814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Exception for GPSAltitudeRef tag
60914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value.length() == 1 && value.charAt(0) >= '0' && value.charAt(0) <= '1') {
61014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                final byte[] bytes = new byte[] { (byte) (value.charAt(0) - '0') };
61114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return new ExifAttribute(IFD_FORMAT_BYTE, bytes.length, bytes);
61214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
61314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            final byte[] ascii = value.getBytes(ASCII);
61414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return new ExifAttribute(IFD_FORMAT_BYTE, ascii.length, ascii);
61514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
61614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
61714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createString(String value) {
61814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            final byte[] ascii = (value + '\0').getBytes(ASCII);
61914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return new ExifAttribute(IFD_FORMAT_STRING, ascii.length, ascii);
62014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
62114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
62214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createURational(Rational[] values, ByteOrder byteOrder) {
62314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            final ByteBuffer buffer = ByteBuffer.wrap(
62414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_URATIONAL] * values.length]);
62514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            buffer.order(byteOrder);
62614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (Rational value : values) {
62714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                buffer.putInt((int) value.numerator);
62814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                buffer.putInt((int) value.denominator);
62914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
63014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return new ExifAttribute(IFD_FORMAT_URATIONAL, values.length, buffer.array());
63114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
63214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
63314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createURational(Rational value, ByteOrder byteOrder) {
63414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return createURational(new Rational[] {value}, byteOrder);
63514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
63614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
63714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createSRational(Rational[] values, ByteOrder byteOrder) {
63814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            final ByteBuffer buffer = ByteBuffer.wrap(
63914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_SRATIONAL] * values.length]);
64014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            buffer.order(byteOrder);
64114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (Rational value : values) {
64214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                buffer.putInt((int) value.numerator);
64314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                buffer.putInt((int) value.denominator);
64414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
64514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return new ExifAttribute(IFD_FORMAT_SRATIONAL, values.length, buffer.array());
64614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
64714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
64814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createSRational(Rational value, ByteOrder byteOrder) {
64914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return createSRational(new Rational[] {value}, byteOrder);
65014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
65114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
65214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createDouble(double[] values, ByteOrder byteOrder) {
65314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            final ByteBuffer buffer = ByteBuffer.wrap(
65414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    new byte[IFD_FORMAT_BYTES_PER_FORMAT[IFD_FORMAT_DOUBLE] * values.length]);
65514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            buffer.order(byteOrder);
65614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (double value : values) {
65714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                buffer.putDouble(value);
65814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
65914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return new ExifAttribute(IFD_FORMAT_DOUBLE, values.length, buffer.array());
66014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
66114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
66214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public static ExifAttribute createDouble(double value, ByteOrder byteOrder) {
66314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return createDouble(new double[] {value}, byteOrder);
66414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
66514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
66614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
66714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public String toString() {
66814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return "(" + IFD_FORMAT_NAMES[format] + ", data length:" + bytes.length + ")";
66914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
67014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
67114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private Object getValue(ByteOrder byteOrder) {
672f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes            ByteOrderedDataInputStream inputStream = null;
67314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            try {
674f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes                inputStream = new ByteOrderedDataInputStream(bytes);
67514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                inputStream.setByteOrder(byteOrder);
67614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                switch (format) {
67714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_BYTE:
67814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_SBYTE: {
67914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        // Exception for GPSAltitudeRef tag
68014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        if (bytes.length == 1 && bytes[0] >= 0 && bytes[0] <= 1) {
68114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            return new String(new char[] { (char) (bytes[0] + '0') });
68214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
68314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return new String(bytes, ASCII);
68414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
68514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_UNDEFINED:
68614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_STRING: {
68714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        int index = 0;
68814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        if (numberOfComponents >= EXIF_ASCII_PREFIX.length) {
68914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            boolean same = true;
69014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            for (int i = 0; i < EXIF_ASCII_PREFIX.length; ++i) {
69114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                if (bytes[i] != EXIF_ASCII_PREFIX[i]) {
69214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                    same = false;
69314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                    break;
69414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                }
69514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            }
69614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            if (same) {
69714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                index = EXIF_ASCII_PREFIX.length;
69814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            }
69914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
70014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
70114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        StringBuilder stringBuilder = new StringBuilder();
70214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        while (index < numberOfComponents) {
70314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            int ch = bytes[index];
70414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            if (ch == 0) {
70514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                break;
70614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            }
70714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            if (ch >= 32) {
70814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                stringBuilder.append((char) ch);
70914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            } else {
71014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                stringBuilder.append('?');
71114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            }
71214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            ++index;
71314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
71414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return stringBuilder.toString();
71514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
71614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_USHORT: {
71714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final int[] values = new int[numberOfComponents];
71814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int i = 0; i < numberOfComponents; ++i) {
71914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            values[i] = inputStream.readUnsignedShort();
72014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
72114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return values;
72214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
72314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_ULONG: {
72414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final long[] values = new long[numberOfComponents];
72514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int i = 0; i < numberOfComponents; ++i) {
72614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            values[i] = inputStream.readUnsignedInt();
72714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
72814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return values;
72914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
73014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_URATIONAL: {
73114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final Rational[] values = new Rational[numberOfComponents];
73214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int i = 0; i < numberOfComponents; ++i) {
73314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            final long numerator = inputStream.readUnsignedInt();
73414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            final long denominator = inputStream.readUnsignedInt();
73514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            values[i] = new Rational(numerator, denominator);
73614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
73714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return values;
73814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
73914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_SSHORT: {
74014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final int[] values = new int[numberOfComponents];
74114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int i = 0; i < numberOfComponents; ++i) {
74214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            values[i] = inputStream.readShort();
74314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
74414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return values;
74514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
74614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_SLONG: {
74714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final int[] values = new int[numberOfComponents];
74814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int i = 0; i < numberOfComponents; ++i) {
74914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            values[i] = inputStream.readInt();
75014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
75114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return values;
75214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
75314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_SRATIONAL: {
75414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final Rational[] values = new Rational[numberOfComponents];
75514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int i = 0; i < numberOfComponents; ++i) {
75614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            final long numerator = inputStream.readInt();
75714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            final long denominator = inputStream.readInt();
75814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            values[i] = new Rational(numerator, denominator);
75914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
76014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return values;
76114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
76214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_SINGLE: {
76314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final double[] values = new double[numberOfComponents];
76414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int i = 0; i < numberOfComponents; ++i) {
76514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            values[i] = inputStream.readFloat();
76614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
76714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return values;
76814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
76914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_DOUBLE: {
77014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final double[] values = new double[numberOfComponents];
77114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int i = 0; i < numberOfComponents; ++i) {
77214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            values[i] = inputStream.readDouble();
77314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
77414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return values;
77514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
77614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    default:
77714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return null;
77814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
77914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } catch (IOException e) {
78014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.w(TAG, "IOException occurred during reading a value", e);
78114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return null;
782f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes            } finally {
783f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes                if (inputStream != null) {
784f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes                    try {
785f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes                        inputStream.close();
786f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes                    } catch (IOException e) {
787f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes                        Log.e(TAG, "IOException occurred while closing InputStream", e);
788f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes                    }
789f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes                }
79014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
79114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
79214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
79314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public double getDoubleValue(ByteOrder byteOrder) {
79414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Object value = getValue(byteOrder);
79514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value == null) {
79614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new NumberFormatException("NULL can't be converted to a double value");
79714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
79814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof String) {
79914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return Double.parseDouble((String) value);
80014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
80114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof long[]) {
80214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                long[] array = (long[]) value;
80314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (array.length == 1) {
80414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return array[0];
80514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
80614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new NumberFormatException("There are more than one component");
80714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
80814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof int[]) {
80914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int[] array = (int[]) value;
81014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (array.length == 1) {
81114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return array[0];
81214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
81314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new NumberFormatException("There are more than one component");
81414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
81514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof double[]) {
81614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                double[] array = (double[]) value;
81714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (array.length == 1) {
81814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return array[0];
81914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
82014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new NumberFormatException("There are more than one component");
82114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
82214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof Rational[]) {
82314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Rational[] array = (Rational[]) value;
82414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (array.length == 1) {
82514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return array[0].calculate();
82614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
82714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new NumberFormatException("There are more than one component");
82814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
82914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new NumberFormatException("Couldn't find a double value");
83014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
83114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
83214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public int getIntValue(ByteOrder byteOrder) {
83314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Object value = getValue(byteOrder);
83414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value == null) {
83514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new NumberFormatException("NULL can't be converted to a integer value");
83614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
83714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof String) {
83814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return Integer.parseInt((String) value);
83914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
84014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof long[]) {
84114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                long[] array = (long[]) value;
84214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (array.length == 1) {
84314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return (int) array[0];
84414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
84514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new NumberFormatException("There are more than one component");
84614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
84714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof int[]) {
84814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int[] array = (int[]) value;
84914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (array.length == 1) {
85014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return array[0];
85114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
85214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new NumberFormatException("There are more than one component");
85314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
85414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new NumberFormatException("Couldn't find a integer value");
85514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
85614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
85714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public String getStringValue(ByteOrder byteOrder) {
85814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Object value = getValue(byteOrder);
85914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value == null) {
86014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return null;
86114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
86214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof String) {
86314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return (String) value;
86414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
86514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
86614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            final StringBuilder stringBuilder = new StringBuilder();
86714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof long[]) {
86814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                long[] array = (long[]) value;
86914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                for (int i = 0; i < array.length; ++i) {
87014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    stringBuilder.append(array[i]);
87114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (i + 1 != array.length) {
87214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        stringBuilder.append(",");
87314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
87414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
87514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return stringBuilder.toString();
87614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
87714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof int[]) {
87814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int[] array = (int[]) value;
87914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                for (int i = 0; i < array.length; ++i) {
88014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    stringBuilder.append(array[i]);
88114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (i + 1 != array.length) {
88214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        stringBuilder.append(",");
88314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
88414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
88514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return stringBuilder.toString();
88614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
88714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof double[]) {
88814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                double[] array = (double[]) value;
88914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                for (int i = 0; i < array.length; ++i) {
89014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    stringBuilder.append(array[i]);
89114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (i + 1 != array.length) {
89214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        stringBuilder.append(",");
89314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
89414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
89514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return stringBuilder.toString();
89614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
89714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value instanceof Rational[]) {
89814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Rational[] array = (Rational[]) value;
89914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                for (int i = 0; i < array.length; ++i) {
90014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    stringBuilder.append(array[i].numerator);
90114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    stringBuilder.append('/');
90214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    stringBuilder.append(array[i].denominator);
90314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (i + 1 != array.length) {
90414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        stringBuilder.append(",");
90514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
90614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
90714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return stringBuilder.toString();
90814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
90914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return null;
91014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
91114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
91214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public int size() {
91314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return IFD_FORMAT_BYTES_PER_FORMAT[format] * numberOfComponents;
91414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
91514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
91614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
91714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // A class for indicating EXIF tag.
91814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static class ExifTag {
91914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public final int number;
92014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public final String name;
92114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public final int primaryFormat;
92214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public final int secondaryFormat;
92314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
92414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private ExifTag(String name, int number, int format) {
92514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.name = name;
92614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.number = number;
92714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.primaryFormat = format;
92814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.secondaryFormat = -1;
92914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
93014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
93114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private ExifTag(String name, int number, int primaryFormat, int secondaryFormat) {
93214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.name = name;
93314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.number = number;
93414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.primaryFormat = primaryFormat;
93514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this.secondaryFormat = secondaryFormat;
93614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
93714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
93814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
93914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Primary image IFD TIFF tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels)
94014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag[] IFD_TIFF_TAGS = new ExifTag[] {
94114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // For below two, see TIFF 6.0 Spec Section 3: Bilevel Images.
94214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_NEW_SUBFILE_TYPE, 254, IFD_FORMAT_ULONG),
94314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUBFILE_TYPE, 255, IFD_FORMAT_ULONG),
94414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_IMAGE_WIDTH, 256, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
94514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_IMAGE_LENGTH, 257, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
94614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_BITS_PER_SAMPLE, 258, IFD_FORMAT_USHORT),
94714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_COMPRESSION, 259, IFD_FORMAT_USHORT),
94814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262, IFD_FORMAT_USHORT),
94914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_IMAGE_DESCRIPTION, 270, IFD_FORMAT_STRING),
95014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_MAKE, 271, IFD_FORMAT_STRING),
95114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_MODEL, 272, IFD_FORMAT_STRING),
95214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_STRIP_OFFSETS, 273, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
95314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ORIENTATION, 274, IFD_FORMAT_USHORT),
95414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SAMPLES_PER_PIXEL, 277, IFD_FORMAT_USHORT),
95514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ROWS_PER_STRIP, 278, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
95614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_STRIP_BYTE_COUNTS, 279, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
95714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_X_RESOLUTION, 282, IFD_FORMAT_URATIONAL),
95814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_Y_RESOLUTION, 283, IFD_FORMAT_URATIONAL),
95914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_PLANAR_CONFIGURATION, 284, IFD_FORMAT_USHORT),
96014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_RESOLUTION_UNIT, 296, IFD_FORMAT_USHORT),
96114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_TRANSFER_FUNCTION, 301, IFD_FORMAT_USHORT),
96214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SOFTWARE, 305, IFD_FORMAT_STRING),
96314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_DATETIME, 306, IFD_FORMAT_STRING),
96414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ARTIST, 315, IFD_FORMAT_STRING),
96514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_WHITE_POINT, 318, IFD_FORMAT_URATIONAL),
96614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319, IFD_FORMAT_URATIONAL),
96714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // See Adobe PageMaker® 6.0 TIFF Technical Notes, Note 1.
96814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUB_IFD_POINTER, 330, IFD_FORMAT_ULONG),
96914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG),
97014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG),
97114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529, IFD_FORMAT_URATIONAL),
97214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530, IFD_FORMAT_USHORT),
97314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_Y_CB_CR_POSITIONING, 531, IFD_FORMAT_USHORT),
97414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL),
97514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING),
97614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
97714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG),
97814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // RW2 file tags
97914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html)
98014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_RW2_SENSOR_TOP_BORDER, 4, IFD_FORMAT_ULONG),
98114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_RW2_SENSOR_LEFT_BORDER, 5, IFD_FORMAT_ULONG),
98214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_RW2_SENSOR_BOTTOM_BORDER, 6, IFD_FORMAT_ULONG),
98314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_RW2_SENSOR_RIGHT_BORDER, 7, IFD_FORMAT_ULONG),
98414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_RW2_ISO, 23, IFD_FORMAT_USHORT),
98514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_RW2_JPG_FROM_RAW, 46, IFD_FORMAT_UNDEFINED)
98614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
98714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
98814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Primary image IFD Exif Private tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels)
98914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag[] IFD_EXIF_TAGS = new ExifTag[] {
99014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_EXPOSURE_TIME, 33434, IFD_FORMAT_URATIONAL),
99114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_F_NUMBER, 33437, IFD_FORMAT_URATIONAL),
99214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_EXPOSURE_PROGRAM, 34850, IFD_FORMAT_USHORT),
99314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SPECTRAL_SENSITIVITY, 34852, IFD_FORMAT_STRING),
99414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ISO_SPEED_RATINGS, 34855, IFD_FORMAT_USHORT),
99514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_OECF, 34856, IFD_FORMAT_UNDEFINED),
99614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_EXIF_VERSION, 36864, IFD_FORMAT_STRING),
99714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_DATETIME_ORIGINAL, 36867, IFD_FORMAT_STRING),
99814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_DATETIME_DIGITIZED, 36868, IFD_FORMAT_STRING),
99914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_COMPONENTS_CONFIGURATION, 37121, IFD_FORMAT_UNDEFINED),
100014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_COMPRESSED_BITS_PER_PIXEL, 37122, IFD_FORMAT_URATIONAL),
100114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SHUTTER_SPEED_VALUE, 37377, IFD_FORMAT_SRATIONAL),
100214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_APERTURE_VALUE, 37378, IFD_FORMAT_URATIONAL),
100314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_BRIGHTNESS_VALUE, 37379, IFD_FORMAT_SRATIONAL),
100414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_EXPOSURE_BIAS_VALUE, 37380, IFD_FORMAT_SRATIONAL),
100514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_MAX_APERTURE_VALUE, 37381, IFD_FORMAT_URATIONAL),
100614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUBJECT_DISTANCE, 37382, IFD_FORMAT_URATIONAL),
100714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_METERING_MODE, 37383, IFD_FORMAT_USHORT),
100814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_LIGHT_SOURCE, 37384, IFD_FORMAT_USHORT),
100914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_FLASH, 37385, IFD_FORMAT_USHORT),
101014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_FOCAL_LENGTH, 37386, IFD_FORMAT_URATIONAL),
101114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUBJECT_AREA, 37396, IFD_FORMAT_USHORT),
101214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_MAKER_NOTE, 37500, IFD_FORMAT_UNDEFINED),
101314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_USER_COMMENT, 37510, IFD_FORMAT_UNDEFINED),
101414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUBSEC_TIME, 37520, IFD_FORMAT_STRING),
101514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUBSEC_TIME_ORIGINAL, 37521, IFD_FORMAT_STRING),
101614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUBSEC_TIME_DIGITIZED, 37522, IFD_FORMAT_STRING),
101714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_FLASHPIX_VERSION, 40960, IFD_FORMAT_UNDEFINED),
101814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_COLOR_SPACE, 40961, IFD_FORMAT_USHORT),
101914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_PIXEL_X_DIMENSION, 40962, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
102014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_PIXEL_Y_DIMENSION, 40963, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
102114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_RELATED_SOUND_FILE, 40964, IFD_FORMAT_STRING),
102214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965, IFD_FORMAT_ULONG),
102314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_FLASH_ENERGY, 41483, IFD_FORMAT_URATIONAL),
102414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SPATIAL_FREQUENCY_RESPONSE, 41484, IFD_FORMAT_UNDEFINED),
102514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_FOCAL_PLANE_X_RESOLUTION, 41486, IFD_FORMAT_URATIONAL),
102614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_FOCAL_PLANE_Y_RESOLUTION, 41487, IFD_FORMAT_URATIONAL),
102714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_FOCAL_PLANE_RESOLUTION_UNIT, 41488, IFD_FORMAT_USHORT),
102814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUBJECT_LOCATION, 41492, IFD_FORMAT_USHORT),
102914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_EXPOSURE_INDEX, 41493, IFD_FORMAT_URATIONAL),
103014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SENSING_METHOD, 41495, IFD_FORMAT_USHORT),
103114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_FILE_SOURCE, 41728, IFD_FORMAT_UNDEFINED),
103214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SCENE_TYPE, 41729, IFD_FORMAT_UNDEFINED),
103314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_CFA_PATTERN, 41730, IFD_FORMAT_UNDEFINED),
103414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_CUSTOM_RENDERED, 41985, IFD_FORMAT_USHORT),
103514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_EXPOSURE_MODE, 41986, IFD_FORMAT_USHORT),
103614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_WHITE_BALANCE, 41987, IFD_FORMAT_USHORT),
103714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_DIGITAL_ZOOM_RATIO, 41988, IFD_FORMAT_URATIONAL),
103814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_FOCAL_LENGTH_IN_35MM_FILM, 41989, IFD_FORMAT_USHORT),
103914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SCENE_CAPTURE_TYPE, 41990, IFD_FORMAT_USHORT),
104014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GAIN_CONTROL, 41991, IFD_FORMAT_USHORT),
104114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_CONTRAST, 41992, IFD_FORMAT_USHORT),
104214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SATURATION, 41993, IFD_FORMAT_USHORT),
104314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SHARPNESS, 41994, IFD_FORMAT_USHORT),
104414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_DEVICE_SETTING_DESCRIPTION, 41995, IFD_FORMAT_UNDEFINED),
104514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUBJECT_DISTANCE_RANGE, 41996, IFD_FORMAT_USHORT),
104614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_IMAGE_UNIQUE_ID, 42016, IFD_FORMAT_STRING),
104714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_DNG_VERSION, 50706, IFD_FORMAT_BYTE),
104814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_DEFAULT_CROP_SIZE, 50720, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG)
104914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
105014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
105114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Primary image IFD GPS Info tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels)
105214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag[] IFD_GPS_TAGS = new ExifTag[] {
105314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_VERSION_ID, 0, IFD_FORMAT_BYTE),
105414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_LATITUDE_REF, 1, IFD_FORMAT_STRING),
105514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_LATITUDE, 2, IFD_FORMAT_URATIONAL),
105614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_LONGITUDE_REF, 3, IFD_FORMAT_STRING),
105714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_LONGITUDE, 4, IFD_FORMAT_URATIONAL),
105814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_ALTITUDE_REF, 5, IFD_FORMAT_BYTE),
105914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_ALTITUDE, 6, IFD_FORMAT_URATIONAL),
106014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_TIMESTAMP, 7, IFD_FORMAT_URATIONAL),
106114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_SATELLITES, 8, IFD_FORMAT_STRING),
106214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_STATUS, 9, IFD_FORMAT_STRING),
106314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_MEASURE_MODE, 10, IFD_FORMAT_STRING),
106414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_DOP, 11, IFD_FORMAT_URATIONAL),
106514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_SPEED_REF, 12, IFD_FORMAT_STRING),
106614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_SPEED, 13, IFD_FORMAT_URATIONAL),
106714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_TRACK_REF, 14, IFD_FORMAT_STRING),
106814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_TRACK, 15, IFD_FORMAT_URATIONAL),
106914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_IMG_DIRECTION_REF, 16, IFD_FORMAT_STRING),
107014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_IMG_DIRECTION, 17, IFD_FORMAT_URATIONAL),
107114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_MAP_DATUM, 18, IFD_FORMAT_STRING),
107214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_DEST_LATITUDE_REF, 19, IFD_FORMAT_STRING),
107314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_DEST_LATITUDE, 20, IFD_FORMAT_URATIONAL),
107414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_DEST_LONGITUDE_REF, 21, IFD_FORMAT_STRING),
107514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_DEST_LONGITUDE, 22, IFD_FORMAT_URATIONAL),
107614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_DEST_BEARING_REF, 23, IFD_FORMAT_STRING),
107714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_DEST_BEARING, 24, IFD_FORMAT_URATIONAL),
107814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_DEST_DISTANCE_REF, 25, IFD_FORMAT_STRING),
107914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_DEST_DISTANCE, 26, IFD_FORMAT_URATIONAL),
108014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_PROCESSING_METHOD, 27, IFD_FORMAT_UNDEFINED),
108114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_AREA_INFORMATION, 28, IFD_FORMAT_UNDEFINED),
108214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_DATESTAMP, 29, IFD_FORMAT_STRING),
108314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_DIFFERENTIAL, 30, IFD_FORMAT_USHORT)
108414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
108514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Primary image IFD Interoperability tag (See JEITA CP-3451C Section 4.6.8 Tag Support Levels)
108614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag[] IFD_INTEROPERABILITY_TAGS = new ExifTag[] {
108714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_INTEROPERABILITY_INDEX, 1, IFD_FORMAT_STRING)
108814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
108914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // IFD Thumbnail tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels)
109014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag[] IFD_THUMBNAIL_TAGS = new ExifTag[] {
109114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // For below two, see TIFF 6.0 Spec Section 3: Bilevel Images.
109214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_NEW_SUBFILE_TYPE, 254, IFD_FORMAT_ULONG),
109314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUBFILE_TYPE, 255, IFD_FORMAT_ULONG),
109414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_THUMBNAIL_IMAGE_WIDTH, 256, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
109514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_THUMBNAIL_IMAGE_LENGTH, 257, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
109614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_BITS_PER_SAMPLE, 258, IFD_FORMAT_USHORT),
109714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_COMPRESSION, 259, IFD_FORMAT_USHORT),
109814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262, IFD_FORMAT_USHORT),
109914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_IMAGE_DESCRIPTION, 270, IFD_FORMAT_STRING),
110014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_MAKE, 271, IFD_FORMAT_STRING),
110114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_MODEL, 272, IFD_FORMAT_STRING),
110214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_STRIP_OFFSETS, 273, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
110314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ORIENTATION, 274, IFD_FORMAT_USHORT),
110414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SAMPLES_PER_PIXEL, 277, IFD_FORMAT_USHORT),
110514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ROWS_PER_STRIP, 278, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
110614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_STRIP_BYTE_COUNTS, 279, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG),
110714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_X_RESOLUTION, 282, IFD_FORMAT_URATIONAL),
110814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_Y_RESOLUTION, 283, IFD_FORMAT_URATIONAL),
110914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_PLANAR_CONFIGURATION, 284, IFD_FORMAT_USHORT),
111014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_RESOLUTION_UNIT, 296, IFD_FORMAT_USHORT),
111114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_TRANSFER_FUNCTION, 301, IFD_FORMAT_USHORT),
111214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SOFTWARE, 305, IFD_FORMAT_STRING),
111314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_DATETIME, 306, IFD_FORMAT_STRING),
111414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ARTIST, 315, IFD_FORMAT_STRING),
111514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_WHITE_POINT, 318, IFD_FORMAT_URATIONAL),
111614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319, IFD_FORMAT_URATIONAL),
111714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // See Adobe PageMaker® 6.0 TIFF Technical Notes, Note 1.
111814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUB_IFD_POINTER, 330, IFD_FORMAT_ULONG),
111914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG),
112014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG),
112114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529, IFD_FORMAT_URATIONAL),
112214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530, IFD_FORMAT_USHORT),
112314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_Y_CB_CR_POSITIONING, 531, IFD_FORMAT_USHORT),
112414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL),
112514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING),
112614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
112714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG),
112814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_DNG_VERSION, 50706, IFD_FORMAT_BYTE),
112914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_DEFAULT_CROP_SIZE, 50720, IFD_FORMAT_USHORT, IFD_FORMAT_ULONG)
113014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
113114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
113214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // RAF file tag (See piex.cc line 372)
113314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag TAG_RAF_IMAGE_SIZE =
113414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_STRIP_OFFSETS, 273, IFD_FORMAT_USHORT);
113514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
113614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // ORF file tags (See http://www.exiv2.org/tags-olympus.html)
113714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag[] ORF_MAKER_NOTE_TAGS = new ExifTag[] {
113814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ORF_THUMBNAIL_IMAGE, 256, IFD_FORMAT_UNDEFINED),
113914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ORF_CAMERA_SETTINGS_IFD_POINTER, 8224, IFD_FORMAT_ULONG),
114014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ORF_IMAGE_PROCESSING_IFD_POINTER, 8256, IFD_FORMAT_ULONG)
114114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
114214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag[] ORF_CAMERA_SETTINGS_TAGS = new ExifTag[] {
114314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ORF_PREVIEW_IMAGE_START, 257, IFD_FORMAT_ULONG),
114414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ORF_PREVIEW_IMAGE_LENGTH, 258, IFD_FORMAT_ULONG)
114514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
114614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag[] ORF_IMAGE_PROCESSING_TAGS = new ExifTag[] {
114714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ORF_ASPECT_FRAME, 4371, IFD_FORMAT_USHORT)
114814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
114914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // PEF file tag (See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Pentax.html)
115014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag[] PEF_TAGS = new ExifTag[] {
115114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_COLOR_SPACE, 55, IFD_FORMAT_USHORT)
115214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
115314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
115414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // See JEITA CP-3451C Section 4.6.3: Exif-specific IFD.
115514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // The following values are used for indicating pointers to the other Image File Directories.
115614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
115714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Indices of Exif Ifd tag groups
115814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /** @hide */
115914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    @Retention(RetentionPolicy.SOURCE)
116014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    @IntDef({IFD_TYPE_PRIMARY, IFD_TYPE_EXIF, IFD_TYPE_GPS, IFD_TYPE_INTEROPERABILITY,
116114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            IFD_TYPE_THUMBNAIL, IFD_TYPE_PREVIEW, IFD_TYPE_ORF_MAKER_NOTE,
116214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            IFD_TYPE_ORF_CAMERA_SETTINGS, IFD_TYPE_ORF_IMAGE_PROCESSING, IFD_TYPE_PEF})
116314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public @interface IfdType {}
116414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
116514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_TYPE_PRIMARY = 0;
116614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_TYPE_EXIF = 1;
116714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_TYPE_GPS = 2;
116814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_TYPE_INTEROPERABILITY = 3;
116914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_TYPE_THUMBNAIL = 4;
117014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_TYPE_PREVIEW = 5;
117114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_TYPE_ORF_MAKER_NOTE = 6;
117214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_TYPE_ORF_CAMERA_SETTINGS = 7;
117314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_TYPE_ORF_IMAGE_PROCESSING = 8;
117414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IFD_TYPE_PEF = 9;
117514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
117614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // List of Exif tag groups
117714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag[][] EXIF_TAGS = new ExifTag[][] {
117814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            IFD_TIFF_TAGS, IFD_EXIF_TAGS, IFD_GPS_TAGS, IFD_INTEROPERABILITY_TAGS,
117914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            IFD_THUMBNAIL_TAGS, IFD_TIFF_TAGS, ORF_MAKER_NOTE_TAGS, ORF_CAMERA_SETTINGS_TAGS,
118014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ORF_IMAGE_PROCESSING_TAGS, PEF_TAGS
118114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
118214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // List of tags for pointing to the other image file directory offset.
118314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag[] EXIF_POINTER_TAGS = new ExifTag[] {
118414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_SUB_IFD_POINTER, 330, IFD_FORMAT_ULONG),
118514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
118614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG),
118714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965, IFD_FORMAT_ULONG),
118814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ORF_CAMERA_SETTINGS_IFD_POINTER, 8224, IFD_FORMAT_BYTE),
118914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_ORF_IMAGE_PROCESSING_IFD_POINTER, 8256, IFD_FORMAT_BYTE)
119014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    };
119114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
119214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Tags for indicating the thumbnail offset and length
119314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag JPEG_INTERCHANGE_FORMAT_TAG =
119414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513, IFD_FORMAT_ULONG);
119514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final ExifTag JPEG_INTERCHANGE_FORMAT_LENGTH_TAG =
119614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514, IFD_FORMAT_ULONG);
119714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
119814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Mappings from tag number to tag name and each item represents one IFD tag group.
1199abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas    @SuppressWarnings("unchecked")
1200abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas    private static final HashMap<Integer, ExifTag>[] sExifTagMapsForReading =
1201abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas            new HashMap[EXIF_TAGS.length];
120214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Mappings from tag name to tag number and each item represents one IFD tag group.
1203abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas    @SuppressWarnings("unchecked")
1204abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas    private static final HashMap<String, ExifTag>[] sExifTagMapsForWriting =
1205abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas            new HashMap[EXIF_TAGS.length];
120614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final HashSet<String> sTagSetForCompatibility = new HashSet<>(Arrays.asList(
120714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            TAG_F_NUMBER, TAG_DIGITAL_ZOOM_RATIO, TAG_EXPOSURE_TIME, TAG_SUBJECT_DISTANCE,
120814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            TAG_GPS_TIMESTAMP));
120914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Mappings from tag number to IFD type for pointer tags.
1210abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas    @SuppressWarnings("unchecked")
1211abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas    private static final HashMap<Integer, Integer> sExifPointerTagMap = new HashMap();
121214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
121314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // See JPEG File Interchange Format Version 1.02.
121414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // The following values are defined for handling JPEG streams. In this implementation, we are
121514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // not only getting information from EXIF but also from some JPEG special segments such as
121614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // MARKER_COM for user comment and MARKER_SOFx for image width and height.
121714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
121814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final Charset ASCII = Charset.forName("US-ASCII");
121914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Identifier for EXIF APP1 segment in JPEG
122014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte[] IDENTIFIER_EXIF_APP1 = "Exif\0\0".getBytes(ASCII);
122114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // JPEG segment markers, that each marker consumes two bytes beginning with 0xff and ending with
122214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // the indicator. There is no SOF4, SOF8, SOF16 markers in JPEG and SOFx markers indicates start
122314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // of frame(baseline DCT) and the image size info exists in its beginning part.
122414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER = (byte) 0xff;
122514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOI = (byte) 0xd8;
122614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF0 = (byte) 0xc0;
122714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF1 = (byte) 0xc1;
122814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF2 = (byte) 0xc2;
122914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF3 = (byte) 0xc3;
123014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF5 = (byte) 0xc5;
123114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF6 = (byte) 0xc6;
123214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF7 = (byte) 0xc7;
123314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF9 = (byte) 0xc9;
123414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF10 = (byte) 0xca;
123514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF11 = (byte) 0xcb;
123614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF13 = (byte) 0xcd;
123714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF14 = (byte) 0xce;
123814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOF15 = (byte) 0xcf;
123914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_SOS = (byte) 0xda;
124014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_APP1 = (byte) 0xe1;
124114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_COM = (byte) 0xfe;
124214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final byte MARKER_EOI = (byte) 0xd9;
124314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
124414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Supported Image File Types
124514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_UNKNOWN = 0;
124614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_ARW = 1;
124714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_CR2 = 2;
124814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_DNG = 3;
124914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_JPEG = 4;
125014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_NEF = 5;
125114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_NRW = 6;
125214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_ORF = 7;
125314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_PEF = 8;
125414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_RAF = 9;
125514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_RW2 = 10;
125614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final int IMAGE_TYPE_SRW = 11;
125714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
125814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    static {
125914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
126014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        sFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
126114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
126214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Build up the hash tables to look up Exif tags for reading Exif tags.
126314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
1264abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas            sExifTagMapsForReading[ifdType] = new HashMap<>();
1265abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas            sExifTagMapsForWriting[ifdType] = new HashMap<>();
126614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (ExifTag tag : EXIF_TAGS[ifdType]) {
126714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                sExifTagMapsForReading[ifdType].put(tag.number, tag);
126814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                sExifTagMapsForWriting[ifdType].put(tag.name, tag);
126914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
127014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
127114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
127214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Build up the hash table to look up Exif pointer tags.
127314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        sExifPointerTagMap.put(EXIF_POINTER_TAGS[0].number, IFD_TYPE_PREVIEW); // 330
127414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        sExifPointerTagMap.put(EXIF_POINTER_TAGS[1].number, IFD_TYPE_EXIF); // 34665
127514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        sExifPointerTagMap.put(EXIF_POINTER_TAGS[2].number, IFD_TYPE_GPS); // 34853
127614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        sExifPointerTagMap.put(EXIF_POINTER_TAGS[3].number, IFD_TYPE_INTEROPERABILITY); // 40965
127714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        sExifPointerTagMap.put(EXIF_POINTER_TAGS[4].number, IFD_TYPE_ORF_CAMERA_SETTINGS); // 8224
127814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        sExifPointerTagMap.put(EXIF_POINTER_TAGS[5].number, IFD_TYPE_ORF_IMAGE_PROCESSING); // 8256
127914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
128014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
128114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private final String mFilename;
128214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private final AssetManager.AssetInputStream mAssetInputStream;
128314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private int mMimeType;
1284abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas    @SuppressWarnings("unchecked")
1285abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas    private final HashMap<String, ExifAttribute>[] mAttributes = new HashMap[EXIF_TAGS.length];
128614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
128714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private boolean mHasThumbnail;
128814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // The following values used for indicating a thumbnail position.
128914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private int mThumbnailOffset;
129014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private int mThumbnailLength;
129114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private byte[] mThumbnailBytes;
129214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private int mThumbnailCompression;
129314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private int mExifOffset;
129414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private int mOrfMakerNoteOffset;
129514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private int mOrfThumbnailOffset;
129614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private int mOrfThumbnailLength;
129714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private int mRw2JpgFromRawOffset;
129814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private boolean mIsSupportedFile;
129914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
130014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Pattern to check non zero timestamp
130114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*");
130214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Pattern to check gps timestamp
130314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static final Pattern sGpsTimestampPattern =
130414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Pattern.compile("^([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$");
130514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
130614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
130714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Reads Exif tags from the specified image file.
130814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
130914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public ExifInterface(String filename) throws IOException {
131014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (filename == null) {
131114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IllegalArgumentException("filename cannot be null");
131214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
131314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        FileInputStream in = null;
131414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        mAssetInputStream = null;
131514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        mFilename = filename;
131614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        try {
131714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            in = new FileInputStream(filename);
131814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            loadAttributes(in);
131914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } finally {
132014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            closeQuietly(in);
132114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
132214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
132314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
132414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
132514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Reads Exif tags from the specified image input stream. Attribute mutation is not supported
132614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * for input streams. The given input stream will proceed its current position. Developers
132746ffc16f1c2e80e8fc401a5a440c3c3a847b4ba7Hyundo Moon     * should close the input stream after use. This constructor is not intended to be used with
132846ffc16f1c2e80e8fc401a5a440c3c3a847b4ba7Hyundo Moon     * an input stream that performs any networking operations.
132914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
133014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public ExifInterface(InputStream inputStream) throws IOException {
133114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (inputStream == null) {
133214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IllegalArgumentException("inputStream cannot be null");
133314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
133414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        mFilename = null;
133514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (inputStream instanceof AssetManager.AssetInputStream) {
133614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAssetInputStream = (AssetManager.AssetInputStream) inputStream;
133714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else {
133814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAssetInputStream = null;
133914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
134014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        loadAttributes(inputStream);
134114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
134214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
134314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
134414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns the EXIF attribute of the specified tag or {@code null} if there is no such tag in
134514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * the image file.
134614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
134714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param tag the name of the tag.
134814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
134914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private ExifAttribute getExifAttribute(String tag) {
135014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Retrieves all tag groups. The value from primary image tag group has a higher priority
135114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // than the value from the thumbnail tag group if there are more than one candidates.
135214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int i = 0; i < EXIF_TAGS.length; ++i) {
1353abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas            ExifAttribute value = mAttributes[i].get(tag);
135414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (value != null) {
1355abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                return value;
135614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
135714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
135814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return null;
135914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
136014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
136114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
136214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns the value of the specified tag or {@code null} if there
136314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * is no such tag in the image file.
136414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
136514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param tag the name of the tag.
136614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
136714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public String getAttribute(String tag) {
136814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute attribute = getExifAttribute(tag);
136914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (attribute != null) {
137014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (!sTagSetForCompatibility.contains(tag)) {
137114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return attribute.getStringValue(mExifByteOrder);
137214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
137314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (tag.equals(TAG_GPS_TIMESTAMP)) {
137414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Convert the rational values to the custom formats for backwards compatibility.
137514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (attribute.format != IFD_FORMAT_URATIONAL
137614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        && attribute.format != IFD_FORMAT_SRATIONAL) {
137714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.w(TAG, "GPS Timestamp format is not rational. format=" + attribute.format);
137814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return null;
137914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
138014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Rational[] array = (Rational[]) attribute.getValue(mExifByteOrder);
138114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (array == null || array.length != 3) {
138214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.w(TAG, "Invalid GPS Timestamp array. array=" + Arrays.toString(array));
138314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return null;
138414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
138514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return String.format("%02d:%02d:%02d",
138614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        (int) ((float) array[0].numerator / array[0].denominator),
138714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        (int) ((float) array[1].numerator / array[1].denominator),
138814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        (int) ((float) array[2].numerator / array[2].denominator));
138914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
139014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            try {
139114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return Double.toString(attribute.getDoubleValue(mExifByteOrder));
139214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } catch (NumberFormatException e) {
139314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return null;
139414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
139514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
139614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return null;
139714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
139814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
139914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
140014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns the integer value of the specified tag. If there is no such tag
140114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * in the image file or the value cannot be parsed as integer, return
140214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * <var>defaultValue</var>.
140314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
140414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param tag the name of the tag.
140514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param defaultValue the value to return if the tag is not available.
140614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
140714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public int getAttributeInt(String tag, int defaultValue) {
140814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute exifAttribute = getExifAttribute(tag);
140914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (exifAttribute == null) {
141014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return defaultValue;
141114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
141214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
141314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        try {
141414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return exifAttribute.getIntValue(mExifByteOrder);
141514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } catch (NumberFormatException e) {
141614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return defaultValue;
141714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
141814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
141914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
142014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
142114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns the double value of the tag that is specified as rational or contains a
142214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * double-formatted value. If there is no such tag in the image file or the value cannot be
142314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * parsed as double, return <var>defaultValue</var>.
142414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
142514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param tag the name of the tag.
142614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param defaultValue the value to return if the tag is not available.
142714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
142814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public double getAttributeDouble(String tag, double defaultValue) {
142914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute exifAttribute = getExifAttribute(tag);
143014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (exifAttribute == null) {
143114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return defaultValue;
143214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
143314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
143414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        try {
143514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return exifAttribute.getDoubleValue(mExifByteOrder);
143614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } catch (NumberFormatException e) {
143714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return defaultValue;
143814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
143914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
144014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
144114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
1442bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     * Sets the value of the specified tag.
144314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
144414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param tag the name of the tag.
144514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param value the value of the tag.
144614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
144714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public void setAttribute(String tag, String value) {
144814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Convert the given value to rational values for backwards compatibility.
144914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (value != null && sTagSetForCompatibility.contains(tag)) {
145014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (tag.equals(TAG_GPS_TIMESTAMP)) {
145114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Matcher m = sGpsTimestampPattern.matcher(value);
145214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (!m.find()) {
145314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.w(TAG, "Invalid value for " + tag + " : " + value);
145414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return;
145514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
145614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                value = Integer.parseInt(m.group(1)) + "/1," + Integer.parseInt(m.group(2)) + "/1,"
145714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + Integer.parseInt(m.group(3)) + "/1";
145814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else {
145914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                try {
146014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    double doubleValue = Double.parseDouble(value);
1461c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen                    value = new Rational(doubleValue).toString();
146214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } catch (NumberFormatException e) {
146314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.w(TAG, "Invalid value for " + tag + " : " + value);
146414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return;
146514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
146614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
146714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
146814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
146914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
147014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (i == IFD_TYPE_THUMBNAIL && !mHasThumbnail) {
147114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                continue;
147214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
1473abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas            final ExifTag exifTag = sExifTagMapsForWriting[i].get(tag);
1474abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas            if (exifTag != null) {
147514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (value == null) {
147614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mAttributes[i].remove(tag);
147714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    continue;
147814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
147914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Pair<Integer, Integer> guess = guessDataFormat(value);
148014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int dataFormat;
148114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (exifTag.primaryFormat == guess.first || exifTag.primaryFormat == guess.second) {
148214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataFormat = exifTag.primaryFormat;
148314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } else if (exifTag.secondaryFormat != -1 && (exifTag.secondaryFormat == guess.first
148414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        || exifTag.secondaryFormat == guess.second)) {
148514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataFormat = exifTag.secondaryFormat;
148614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } else if (exifTag.primaryFormat == IFD_FORMAT_BYTE
148714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        || exifTag.primaryFormat == IFD_FORMAT_UNDEFINED
148814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        || exifTag.primaryFormat == IFD_FORMAT_STRING) {
148914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataFormat = exifTag.primaryFormat;
149014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } else {
149114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.w(TAG, "Given tag (" + tag + ") value didn't match with one of expected "
149214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            + "formats: " + IFD_FORMAT_NAMES[exifTag.primaryFormat]
149314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            + (exifTag.secondaryFormat == -1 ? "" : ", "
149414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            + IFD_FORMAT_NAMES[exifTag.secondaryFormat]) + " (guess: "
149514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            + IFD_FORMAT_NAMES[guess.first] + (guess.second == -1 ? "" : ", "
149614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            + IFD_FORMAT_NAMES[guess.second]) + ")");
149714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    continue;
149814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
149914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                switch (dataFormat) {
150014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_BYTE: {
150114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[i].put(tag, ExifAttribute.createByte(value));
150214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
150314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
150414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_UNDEFINED:
150514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_STRING: {
150614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[i].put(tag, ExifAttribute.createString(value));
150714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
150814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
150914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_USHORT: {
151014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final String[] values = value.split(",");
151114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final int[] intArray = new int[values.length];
151214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int j = 0; j < values.length; ++j) {
151314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            intArray[j] = Integer.parseInt(values[j]);
151414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
151514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[i].put(tag,
151614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                ExifAttribute.createUShort(intArray, mExifByteOrder));
151714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
151814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
151914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_SLONG: {
152014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final String[] values = value.split(",");
152114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final int[] intArray = new int[values.length];
152214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int j = 0; j < values.length; ++j) {
152314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            intArray[j] = Integer.parseInt(values[j]);
152414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
152514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[i].put(tag,
152614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                ExifAttribute.createSLong(intArray, mExifByteOrder));
152714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
152814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
152914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_ULONG: {
153014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final String[] values = value.split(",");
153114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final long[] longArray = new long[values.length];
153214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int j = 0; j < values.length; ++j) {
153314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            longArray[j] = Long.parseLong(values[j]);
153414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
153514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[i].put(tag,
153614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                ExifAttribute.createULong(longArray, mExifByteOrder));
153714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
153814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
153914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_URATIONAL: {
154014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final String[] values = value.split(",");
154114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final Rational[] rationalArray = new Rational[values.length];
154214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int j = 0; j < values.length; ++j) {
154314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            final String[] numbers = values[j].split("/");
154477966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon                            rationalArray[j] = new Rational((long) Double.parseDouble(numbers[0]),
154577966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon                                    (long) Double.parseDouble(numbers[1]));
154614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
154714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[i].put(tag,
154814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                ExifAttribute.createURational(rationalArray, mExifByteOrder));
154914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
155014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
155114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_SRATIONAL: {
155214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final String[] values = value.split(",");
155314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final Rational[] rationalArray = new Rational[values.length];
155414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int j = 0; j < values.length; ++j) {
155514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            final String[] numbers = values[j].split("/");
155677966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon                            rationalArray[j] = new Rational((long) Double.parseDouble(numbers[0]),
155777966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon                                    (long) Double.parseDouble(numbers[1]));
155814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
155914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[i].put(tag,
156014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                ExifAttribute.createSRational(rationalArray, mExifByteOrder));
156114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
156214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
156314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_DOUBLE: {
156414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final String[] values = value.split(",");
156514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        final double[] doubleArray = new double[values.length];
156614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        for (int j = 0; j < values.length; ++j) {
156714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            doubleArray[j] = Double.parseDouble(values[j]);
156814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
156914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[i].put(tag,
157014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                ExifAttribute.createDouble(doubleArray, mExifByteOrder));
157114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
157214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
157314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    default:
157414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        Log.w(TAG, "Data format isn't one of expected formats: " + dataFormat);
157514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        continue;
157614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
157714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
157814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
157914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
158014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
158114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
1582bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     * Resets the {@link #TAG_ORIENTATION} of the image to be {@link #ORIENTATION_NORMAL}.
1583bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     */
1584bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    public void resetOrientation() {
1585bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        setAttribute(TAG_ORIENTATION, Integer.toString(ORIENTATION_NORMAL));
1586bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    }
1587bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren
1588bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    /**
1589bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     * Rotates the image by the given degree clockwise. The degree should be a multiple of
1590bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     * 90 (e.g, 90, 180, -90, etc.).
1591bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     *
1592bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     * @param degree The degree of rotation.
1593bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     */
1594bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    public void rotate(int degree) {
1595bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        if (degree % 90 !=0) {
1596bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            throw new IllegalArgumentException("degree should be a multiple of 90");
1597bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        }
1598bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren
1599bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        int currentOrientation = getAttributeInt(TAG_ORIENTATION, ORIENTATION_NORMAL);
1600bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        int currentIndex, newIndex;
1601bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        int resultOrientation;
1602bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        if (ROTATION_ORDER.contains(currentOrientation)) {
1603bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            currentIndex = ROTATION_ORDER.indexOf(currentOrientation);
1604bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            newIndex = (currentIndex + degree / 90) % 4;
1605bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            newIndex += newIndex < 0 ? 4 : 0;
1606bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            resultOrientation = ROTATION_ORDER.get(newIndex);
1607bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        } else if (FLIPPED_ROTATION_ORDER.contains(currentOrientation)) {
1608bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            currentIndex = FLIPPED_ROTATION_ORDER.indexOf(currentOrientation);
1609bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            newIndex = (currentIndex + degree / 90) % 4;
1610bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            newIndex += newIndex < 0 ? 4 : 0;
1611bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            resultOrientation = FLIPPED_ROTATION_ORDER.get(newIndex);
1612bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        } else {
1613bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            resultOrientation = ORIENTATION_UNDEFINED;
1614bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        }
1615bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren
1616bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        setAttribute(TAG_ORIENTATION, Integer.toString(resultOrientation));
1617bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    }
1618bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren
1619bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    /**
1620bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     * Flips the image vertically.
1621bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     */
1622bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    public void flipVertically() {
1623bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        int currentOrientation = getAttributeInt(TAG_ORIENTATION, ORIENTATION_NORMAL);
1624bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        int resultOrientation;
1625bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        switch (currentOrientation) {
1626bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_FLIP_HORIZONTAL:
1627bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_ROTATE_180;
1628bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1629bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_ROTATE_180:
1630bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_FLIP_HORIZONTAL;
1631bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1632bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_FLIP_VERTICAL:
1633bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_NORMAL;
1634bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1635bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_TRANSPOSE:
1636bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_ROTATE_270;
1637bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1638bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_ROTATE_90:
1639bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_TRANSVERSE;
1640bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1641bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_TRANSVERSE:
1642bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_ROTATE_90;
1643bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1644bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_ROTATE_270:
1645bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_TRANSPOSE;
1646bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1647bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_NORMAL:
1648bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_FLIP_VERTICAL;
1649bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1650bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_UNDEFINED:
1651bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            default:
1652bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_UNDEFINED;
1653bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1654bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        }
1655bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        setAttribute(TAG_ORIENTATION, Integer.toString(resultOrientation));
1656bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    }
1657bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren
1658bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    /**
1659bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     * Flips the image horizontally.
1660bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren     */
1661bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    public void flipHorizontally() {
1662bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        int currentOrientation = getAttributeInt(TAG_ORIENTATION, ORIENTATION_NORMAL);
1663bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        int resultOrientation;
1664bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        switch (currentOrientation) {
1665bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_FLIP_HORIZONTAL:
1666bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_NORMAL;
1667bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1668bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_ROTATE_180:
1669bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_FLIP_VERTICAL;
1670bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1671bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_FLIP_VERTICAL:
1672bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_ROTATE_180;
1673bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1674bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_TRANSPOSE:
1675bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_ROTATE_90;
1676bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1677bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_ROTATE_90:
1678bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_TRANSPOSE;
1679bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1680bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_TRANSVERSE:
1681bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_ROTATE_270;
1682bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1683bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_ROTATE_270:
1684bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_TRANSVERSE;
1685bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1686bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_NORMAL:
1687bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_FLIP_HORIZONTAL;
1688bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1689bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            case ORIENTATION_UNDEFINED:
1690bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren            default:
1691bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                resultOrientation = ORIENTATION_UNDEFINED;
1692bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren                break;
1693bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        }
1694bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren        setAttribute(TAG_ORIENTATION, Integer.toString(resultOrientation));
1695bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    }
1696bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren
1697bc4fd2c642f7db0a091fe6e9179b0380eda16b36yangren    /**
169814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Update the values of the tags in the tag groups if any value for the tag already was stored.
169914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
170014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param tag the name of the tag.
170114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param value the value of the tag in a form of {@link ExifAttribute}.
170214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @return Returns {@code true} if updating is placed.
170314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
170414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private boolean updateAttribute(String tag, ExifAttribute value) {
170514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        boolean updated = false;
170614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
170714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mAttributes[i].containsKey(tag)) {
170814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mAttributes[i].put(tag, value);
170914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                updated = true;
171014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
171114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
171214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return updated;
171314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
171414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
171514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
171614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Remove any values of the specified tag.
171714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
171814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param tag the name of the tag.
171914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
172014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void removeAttribute(String tag) {
172114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
172214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[i].remove(tag);
172314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
172414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
172514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
172614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
172714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * This function decides which parser to read the image data according to the given input stream
172814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * type and the content of the input stream. In each case, it reads the first three bytes to
172914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * determine whether the image data format is JPEG or not.
173014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
173114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void loadAttributes(@NonNull InputStream in) throws IOException {
173214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        try {
173314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Initialize mAttributes.
173414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (int i = 0; i < EXIF_TAGS.length; ++i) {
1735abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                mAttributes[i] = new HashMap<>();
173614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
173714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
173814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Check file type
173914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            in = new BufferedInputStream(in, SIGNATURE_CHECK_SIZE);
174014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mMimeType = getMimeType((BufferedInputStream) in);
174114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
174214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Create byte-ordered input stream
174314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ByteOrderedDataInputStream inputStream = new ByteOrderedDataInputStream(in);
174414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
174514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            switch (mMimeType) {
174614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_JPEG: {
174714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    getJpegAttributes(inputStream, 0, IFD_TYPE_PRIMARY); // 0 is offset
174814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
174914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
175014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_RAF: {
175114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    getRafAttributes(inputStream);
175214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
175314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
175414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_ORF: {
175514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    getOrfAttributes(inputStream);
175614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
175714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
175814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_RW2: {
175914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    getRw2Attributes(inputStream);
176014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
176114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
176214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_ARW:
176314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_CR2:
176414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_DNG:
176514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_NEF:
176614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_NRW:
176714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_PEF:
176814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_SRW:
176914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case IMAGE_TYPE_UNKNOWN: {
177014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    getRawAttributes(inputStream);
177114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
177214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
177314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                default: {
177414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
177514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
177614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
177714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Set thumbnail image offset and length
177814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            setThumbnailData(inputStream);
177914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mIsSupportedFile = true;
178014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } catch (IOException e) {
178114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Ignore exceptions in order to keep the compatibility with the old versions of
178214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // ExifInterface.
178314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mIsSupportedFile = false;
178414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (DEBUG) {
178514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.w(TAG, "Invalid image: ExifInterface got an unsupported image format file"
178614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + "(ExifInterface supports JPEG and some RAW image formats only) "
178714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + "or a corrupted JPEG file to ExifInterface.", e);
178814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
178914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } finally {
179014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            addDefaultValuesForCompatibility();
179114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
179214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (DEBUG) {
179314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                printAttributes();
179414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
179514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
179614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
179714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
179814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Prints out attributes for debugging.
179914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void printAttributes() {
180014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int i = 0; i < mAttributes.length; ++i) {
180114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Log.d(TAG, "The size of tag group[" + i + "]: " + mAttributes[i].size());
1802abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas            for (Map.Entry<String, ExifAttribute> entry : mAttributes[i].entrySet()) {
1803abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                final ExifAttribute tagValue = entry.getValue();
180414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.d(TAG, "tagName: " + entry.getKey() + ", tagType: " + tagValue.toString()
180514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + ", tagValue: '" + tagValue.getStringValue(mExifByteOrder) + "'");
180614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
180714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
180814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
180914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
181014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
181114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Save the tag data into the original image file. This is expensive because it involves
181214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * copying all the data from one file to another and deleting the old file and renaming the
181314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write
181414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * and make a single call rather than multiple calls for each attribute.
181514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * <p>
181614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * This method is only supported for JPEG files.
181714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * </p>
181814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
181914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public void saveAttributes() throws IOException {
182014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!mIsSupportedFile || mMimeType != IMAGE_TYPE_JPEG) {
182114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("ExifInterface only supports saving attributes on JPEG formats.");
182214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
182314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (mFilename == null) {
182414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException(
182514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    "ExifInterface does not support saving attributes for the current input.");
182614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
182714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
182814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Keep the thumbnail in memory
182914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        mThumbnailBytes = getThumbnail();
183014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
183114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        File tempFile = new File(mFilename + ".tmp");
183214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        File originalFile = new File(mFilename);
183314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!originalFile.renameTo(tempFile)) {
183414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("Could not rename to " + tempFile.getAbsolutePath());
183514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
183614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
183714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        FileInputStream in = null;
183814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        FileOutputStream out = null;
183914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        try {
184014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Save the new file.
184114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            in = new FileInputStream(tempFile);
184214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            out = new FileOutputStream(mFilename);
184314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            saveJpegAttributes(in, out);
184414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } finally {
184514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            closeQuietly(in);
184614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            closeQuietly(out);
184714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            tempFile.delete();
184814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
184914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
185014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Discard the thumbnail in memory
185114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        mThumbnailBytes = null;
185214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
185314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
185414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
185514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns true if the image file has a thumbnail.
185614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
185714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public boolean hasThumbnail() {
185814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return mHasThumbnail;
185914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
186014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
186114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
186214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns the JPEG compressed thumbnail inside the image file, or {@code null} if there is no
186314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * JPEG compressed thumbnail.
186414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * The returned data can be decoded using
186514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * {@link android.graphics.BitmapFactory#decodeByteArray(byte[],int,int)}
186614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
186714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public byte[] getThumbnail() {
186814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (mThumbnailCompression == DATA_JPEG || mThumbnailCompression == DATA_JPEG_COMPRESSED) {
186914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return getThumbnailBytes();
187014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
187114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return null;
187214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
187314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
187414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
187514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns the thumbnail bytes inside the image file, regardless of the compression type of the
187614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * thumbnail image.
187714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
187814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public byte[] getThumbnailBytes() {
187914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!mHasThumbnail) {
188014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return null;
188114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
188214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (mThumbnailBytes != null) {
188314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return mThumbnailBytes;
188414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
188514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
188614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Read the thumbnail.
188714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        InputStream in = null;
188814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        try {
188914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mAssetInputStream != null) {
189014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                in = mAssetInputStream;
189114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (in.markSupported()) {
189214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    in.reset();
189314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } else {
189414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.d(TAG, "Cannot read thumbnail from inputstream without mark/reset support");
189514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return null;
189614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
189714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else if (mFilename != null) {
189814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                in = new FileInputStream(mFilename);
189914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
190014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (in == null) {
190114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Should not be reached this.
190214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new FileNotFoundException();
190314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
190414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (in.skip(mThumbnailOffset) != mThumbnailOffset) {
190514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Corrupted image");
190614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
190714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            byte[] buffer = new byte[mThumbnailLength];
190814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (in.read(buffer) != mThumbnailLength) {
190914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Corrupted image");
191014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
191114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mThumbnailBytes = buffer;
191214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return buffer;
191314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } catch (IOException e) {
191414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Couldn't get a thumbnail image.
191514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Log.d(TAG, "Encountered exception while getting thumbnail", e);
191614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } finally {
191714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            closeQuietly(in);
191814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
191914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return null;
192014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
192114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
192214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
192314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Creates and returns a Bitmap object of the thumbnail image based on the byte array and the
192414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * thumbnail compression value, or {@code null} if the compression type is unsupported.
192514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
192614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public Bitmap getThumbnailBitmap() {
192714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!mHasThumbnail) {
192814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return null;
192914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else if (mThumbnailBytes == null) {
193014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mThumbnailBytes = getThumbnailBytes();
193114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
193214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
193314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (mThumbnailCompression == DATA_JPEG || mThumbnailCompression == DATA_JPEG_COMPRESSED) {
193414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return BitmapFactory.decodeByteArray(mThumbnailBytes, 0, mThumbnailLength);
193514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else if (mThumbnailCompression == DATA_UNCOMPRESSED) {
193614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int[] rgbValues = new int[mThumbnailBytes.length / 3];
193714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            byte alpha = (byte) 0xff000000;
193814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (int i = 0; i < rgbValues.length; i++) {
193914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                rgbValues[i] = alpha + (mThumbnailBytes[3 * i] << 16)
194014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + (mThumbnailBytes[3 * i + 1] << 8) + mThumbnailBytes[3 * i + 2];
194114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
194214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
194314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ExifAttribute imageLengthAttribute =
194414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    (ExifAttribute) mAttributes[IFD_TYPE_THUMBNAIL].get(TAG_IMAGE_LENGTH);
194514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ExifAttribute imageWidthAttribute =
194614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    (ExifAttribute) mAttributes[IFD_TYPE_THUMBNAIL].get(TAG_IMAGE_WIDTH);
194714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (imageLengthAttribute != null && imageWidthAttribute != null) {
194814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int imageLength = imageLengthAttribute.getIntValue(mExifByteOrder);
194914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int imageWidth = imageWidthAttribute.getIntValue(mExifByteOrder);
195014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return Bitmap.createBitmap(
195114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        rgbValues, imageWidth, imageLength, Bitmap.Config.ARGB_8888);
195214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
195314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
195414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return null;
195514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
195614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
195714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
195814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns true if thumbnail image is JPEG Compressed, or false if either thumbnail image does
195914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * not exist or thumbnail image is uncompressed.
196014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
196114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public boolean isThumbnailCompressed() {
196214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return mThumbnailCompression == DATA_JPEG || mThumbnailCompression == DATA_JPEG_COMPRESSED;
196314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
196414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
196514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
196614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns the offset and length of thumbnail inside the image file, or
196714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * {@code null} if there is no thumbnail.
196814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
196914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @return two-element array, the offset in the first value, and length in
197014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *         the second, or {@code null} if no thumbnail was found.
197114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
197214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public long[] getThumbnailRange() {
197314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!mHasThumbnail) {
197414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return null;
197514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
197614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
197714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        long[] range = new long[2];
197814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        range[0] = mThumbnailOffset;
197914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        range[1] = mThumbnailLength;
198014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
198114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return range;
198214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
198314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
198414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
1985d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * Stores the latitude and longitude value in a float array. The first element is the latitude,
1986d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * and the second element is the longitude. Returns false if the Exif tags are not available.
1987d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     *
1988d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * @deprecated Use {@link #getLatLong()} instead.
198914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
1990d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon    @Deprecated
199114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public boolean getLatLong(float output[]) {
1992d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        double[] latLong = getLatLong();
1993d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        if (latLong == null) {
1994d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon            return false;
1995d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        }
1996d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon
1997d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        output[0] = (float) latLong[0];
1998d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        output[1] = (float) latLong[1];
1999d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        return true;
2000d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon    }
2001d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon
2002d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon    /**
2003d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * Gets the latitude and longitude values.
2004d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * <p>
2005d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * If there are valid latitude and longitude values in the image, this method returns a double
2006d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * array where the first element is the latitude and the second element is the longitude.
2007d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * Otherwise, it returns null.
2008d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     */
2009d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon    public double[] getLatLong() {
201014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        String latValue = getAttribute(TAG_GPS_LATITUDE);
201114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        String latRef = getAttribute(TAG_GPS_LATITUDE_REF);
201214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        String lngValue = getAttribute(TAG_GPS_LONGITUDE);
201314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        String lngRef = getAttribute(TAG_GPS_LONGITUDE_REF);
201414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
201514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (latValue != null && latRef != null && lngValue != null && lngRef != null) {
201614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            try {
2017d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon                double latitude = convertRationalLatLonToDouble(latValue, latRef);
2018d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon                double longitude = convertRationalLatLonToDouble(lngValue, lngRef);
2019d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon                return new double[] {latitude, longitude};
202014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } catch (IllegalArgumentException e) {
202114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.w(TAG, "Latitude/longitude values are not parseable. " +
202214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        String.format("latValue=%s, latRef=%s, lngValue=%s, lngRef=%s",
202314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                latValue, latRef, lngValue, lngRef));
202414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
202514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
2026d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        return null;
2027d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon    }
2028d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon
2029d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon    /**
2030c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen     * Sets the GPS-related information. It will set GPS processing method, latitude and longitude
2031c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen     * values, GPS timestamp, and speed information at the same time.
2032c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen     *
2033c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen     * @param location the {@link Location} object returned by GPS service.
2034c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen     */
2035c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen    public void setGpsInfo(Location location) {
2036c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        if (location == null) {
2037c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen            return;
2038c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        }
2039c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, location.getProvider());
2040c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        setLatLong(location.getLatitude(), location.getLongitude());
2041c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        setAltitude(location.getAltitude());
2042c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        // Location objects store speeds in m/sec. Translates it to km/hr here.
2043c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        setAttribute(TAG_GPS_SPEED_REF, "K");
2044c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        setAttribute(TAG_GPS_SPEED, new Rational(location.getSpeed()
2045c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen                * TimeUnit.HOURS.toSeconds(1) / 1000).toString());
2046c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        String[] dateTime = sFormatter.format(new Date(location.getTime())).split("\\s+");
2047c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        setAttribute(ExifInterface.TAG_GPS_DATESTAMP, dateTime[0]);
2048c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, dateTime[1]);
2049c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen    }
2050c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen
2051c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen    /**
2052d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * Sets the latitude and longitude values.
2053d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     *
2054d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * @param latitude the decimal value of latitude. Must be a valid double value between -90.0 and
2055d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     *                 90.0.
2056d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * @param longitude the decimal value of longitude. Must be a valid double value between -180.0
2057d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     *                  and 180.0.
2058d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     * @throws IllegalArgumentException If {@code latitude} or {@code longitude} is outside the
2059d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     *                                  specified range.
2060d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon     */
2061d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon    public void setLatLong(double latitude, double longitude) {
2062d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        if (latitude < -90.0 || latitude > 90.0 || Double.isNaN(latitude)) {
2063d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon            throw new IllegalArgumentException("Latitude value " + latitude + " is not valid.");
2064d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        }
2065d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        if (longitude < -180.0 || longitude > 180.0 || Double.isNaN(longitude)) {
2066d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon            throw new IllegalArgumentException("Longitude value " + longitude + " is not valid.");
2067d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        }
2068d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        setAttribute(TAG_GPS_LATITUDE_REF, latitude >= 0 ? "N" : "S");
2069d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        setAttribute(TAG_GPS_LATITUDE, convertDecimalDegree(Math.abs(latitude)));
2070d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        setAttribute(TAG_GPS_LONGITUDE_REF, longitude >= 0 ? "E" : "W");
2071d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        setAttribute(TAG_GPS_LONGITUDE, convertDecimalDegree(Math.abs(longitude)));
207214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
207314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
207414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
207514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Return the altitude in meters. If the exif tag does not exist, return
207614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * <var>defaultValue</var>.
207714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
207814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param defaultValue the value to return if the tag is not available.
207914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
208014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public double getAltitude(double defaultValue) {
208114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        double altitude = getAttributeDouble(TAG_GPS_ALTITUDE, -1);
208214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int ref = getAttributeInt(TAG_GPS_ALTITUDE_REF, -1);
208314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
208414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (altitude >= 0 && ref >= 0) {
208514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return (altitude * ((ref == 1) ? -1 : 1));
208614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else {
208714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return defaultValue;
208814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
208914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
209014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
209114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
2092c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen     * Sets the altitude in meters.
2093c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen     */
2094c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen    public void setAltitude(double altitude) {
2095c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        String ref = altitude >= 0 ? "0" : "1";
2096c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        setAttribute(TAG_GPS_ALTITUDE, new Rational(Math.abs(altitude)).toString());
2097c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen        setAttribute(TAG_GPS_ALTITUDE_REF, ref);
2098c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen    }
2099c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen
2100c5d30247a9f0ae2d36b4db80c0d7fa6e73bb008dConrad Chen    /**
21018f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren     * Set the date time value.
21028f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren     *
21038f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren     * @param timeStamp number of milliseconds since Jan. 1, 1970, midnight local time.
21048f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren     * @hide
21058f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren     */
21068f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren    public void setDateTime(long timeStamp) {
21078f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren        long sub = timeStamp % 1000;
21088f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren        setAttribute(TAG_DATETIME, sFormatter.format(new Date(timeStamp)));
21098f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren        setAttribute(TAG_SUBSEC_TIME, Long.toString(sub));
21108f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren    }
21118f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren
21128f31117b0d0b9cb24ef4ef0464f526ace39e2709yangren    /**
211314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns number of milliseconds since Jan. 1, 1970, midnight local time.
211414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns -1 if the date time information if not available.
211514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @hide
211614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
211714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public long getDateTime() {
211814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        String dateTimeString = getAttribute(TAG_DATETIME);
211914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (dateTimeString == null
212014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                || !sNonZeroTimePattern.matcher(dateTimeString).matches()) return -1;
212114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
212214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ParsePosition pos = new ParsePosition(0);
212314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        try {
212414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // The exif field is in local time. Parsing it as if it is UTC will yield time
212514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // since 1/1/1970 local time
212614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Date datetime = sFormatter.parse(dateTimeString, pos);
212714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (datetime == null) return -1;
212814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            long msecs = datetime.getTime();
212914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
213014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            String subSecs = getAttribute(TAG_SUBSEC_TIME);
213114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (subSecs != null) {
213214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                try {
213314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    long sub = Long.parseLong(subSecs);
213414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    while (sub > 1000) {
213514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        sub /= 10;
213614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
213714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    msecs += sub;
213814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } catch (NumberFormatException e) {
213914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    // Ignored
214014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
214114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
214214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return msecs;
214314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } catch (IllegalArgumentException e) {
214414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return -1;
214514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
214614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
214714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
214814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
214914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns number of milliseconds since Jan. 1, 1970, midnight UTC.
215014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns -1 if the date time information if not available.
215114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @hide
215214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
215314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    public long getGpsDateTime() {
215414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        String date = getAttribute(TAG_GPS_DATESTAMP);
215514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        String time = getAttribute(TAG_GPS_TIMESTAMP);
215614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (date == null || time == null
215714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                || (!sNonZeroTimePattern.matcher(date).matches()
215814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                && !sNonZeroTimePattern.matcher(time).matches())) {
215914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return -1;
216014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
216114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
216214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        String dateTimeString = date + ' ' + time;
216314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
216414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ParsePosition pos = new ParsePosition(0);
216514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        try {
216614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Date datetime = sFormatter.parse(dateTimeString, pos);
216714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (datetime == null) return -1;
216814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return datetime.getTime();
216914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } catch (IllegalArgumentException e) {
217014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return -1;
217114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
217214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
217314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
2174d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon    private static double convertRationalLatLonToDouble(String rationalString, String ref) {
217514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        try {
217614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            String [] parts = rationalString.split(",");
217714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
217814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            String [] pair;
217914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            pair = parts[0].split("/");
218014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            double degrees = Double.parseDouble(pair[0].trim())
218114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    / Double.parseDouble(pair[1].trim());
218214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
218314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            pair = parts[1].split("/");
218414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            double minutes = Double.parseDouble(pair[0].trim())
218514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    / Double.parseDouble(pair[1].trim());
218614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
218714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            pair = parts[2].split("/");
218814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            double seconds = Double.parseDouble(pair[0].trim())
218914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    / Double.parseDouble(pair[1].trim());
219014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
219114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            double result = degrees + (minutes / 60.0) + (seconds / 3600.0);
219214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if ((ref.equals("S") || ref.equals("W"))) {
2193d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon                return -result;
2194d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon            } else if (ref.equals("N") || ref.equals("E")) {
2195d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon                return result;
2196d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon            } else {
2197d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon                // Not valid
2198d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon                throw new IllegalArgumentException();
219914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
220014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
220114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Not valid
220214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IllegalArgumentException();
220314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
220414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
220514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
2206d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon    private String convertDecimalDegree(double decimalDegree) {
2207d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        long degrees = (long) decimalDegree;
2208d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        long minutes = (long) ((decimalDegree - degrees) * 60.0);
2209d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        long seconds = Math.round((decimalDegree - degrees - minutes / 60.0) * 3600.0 * 1e7);
2210d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon        return degrees + "/1," + minutes + "/1," + seconds + "/10000000";
2211d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon    }
2212d56d8611e9a0e06799114a3d4716ac5921c06342Hyundo Moon
221314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Checks the type of image file
221414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private int getMimeType(BufferedInputStream in) throws IOException {
221514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        in.mark(SIGNATURE_CHECK_SIZE);
221614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        byte[] signatureCheckBytes = new byte[SIGNATURE_CHECK_SIZE];
221714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (in.read(signatureCheckBytes) != SIGNATURE_CHECK_SIZE) {
221814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new EOFException();
221914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
222014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        in.reset();
222114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (isJpegFormat(signatureCheckBytes)) {
222214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return IMAGE_TYPE_JPEG;
222314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else if (isRafFormat(signatureCheckBytes)) {
222414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return IMAGE_TYPE_RAF;
222514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else if (isOrfFormat(signatureCheckBytes)) {
222614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return IMAGE_TYPE_ORF;
222714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else if (isRw2Format(signatureCheckBytes)) {
222814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return IMAGE_TYPE_RW2;
222914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
223014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Certain file formats (PEF) are identified in readImageFileDirectory()
223114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return IMAGE_TYPE_UNKNOWN;
223214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
223314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
223414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
223514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * This method looks at the first 3 bytes to determine if this file is a JPEG file.
223614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * See http://www.media.mit.edu/pia/Research/deepview/exif.html, "JPEG format and Marker"
223714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
223814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static boolean isJpegFormat(byte[] signatureCheckBytes) throws IOException {
223914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int i = 0; i < JPEG_SIGNATURE.length; i++) {
224014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (signatureCheckBytes[i] != JPEG_SIGNATURE[i]) {
224114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return false;
224214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
224314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
224414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return true;
224514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
224614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
224714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
224814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * This method looks at the first 15 bytes to determine if this file is a RAF file.
224914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * There is no official specification for RAF files from Fuji, but there is an online archive of
225014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * image file specifications:
225114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * http://fileformats.archiveteam.org/wiki/Fujifilm_RAF
225214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
225314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private boolean isRafFormat(byte[] signatureCheckBytes) throws IOException {
225489889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon        byte[] rafSignatureBytes = RAF_SIGNATURE.getBytes(Charset.defaultCharset());
225514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int i = 0; i < rafSignatureBytes.length; i++) {
225614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (signatureCheckBytes[i] != rafSignatureBytes[i]) {
225714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return false;
225814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
225914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
226014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return true;
226114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
226214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
226314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
226414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * ORF has a similar structure to TIFF but it contains a different signature at the TIFF Header.
226514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * This method looks at the 2 bytes following the Byte Order bytes to determine if this file is
226614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * an ORF file.
226714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * There is no official specification for ORF files from Olympus, but there is an online archive
226814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * of image file specifications:
226914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * http://fileformats.archiveteam.org/wiki/Olympus_ORF
227014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
227114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private boolean isOrfFormat(byte[] signatureCheckBytes) throws IOException {
227214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ByteOrderedDataInputStream signatureInputStream =
227314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                new ByteOrderedDataInputStream(signatureCheckBytes);
227414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Read byte order
227514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        mExifByteOrder = readByteOrder(signatureInputStream);
227614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Set byte order
227714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        signatureInputStream.setByteOrder(mExifByteOrder);
227814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
227914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        short orfSignature = signatureInputStream.readShort();
2280f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes        signatureInputStream.close();
228114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return orfSignature == ORF_SIGNATURE_1 || orfSignature == ORF_SIGNATURE_2;
228214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
228314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
228414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
228514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * RW2 is TIFF-based, but stores 0x55 signature byte instead of 0x42 at the header
228614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * See http://lclevy.free.fr/raw/
228714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
228814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private boolean isRw2Format(byte[] signatureCheckBytes) throws IOException {
228914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ByteOrderedDataInputStream signatureInputStream =
229014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                new ByteOrderedDataInputStream(signatureCheckBytes);
229114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Read byte order
229214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        mExifByteOrder = readByteOrder(signatureInputStream);
229314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Set byte order
229414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        signatureInputStream.setByteOrder(mExifByteOrder);
229514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
229614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        short signatureByte = signatureInputStream.readShort();
2297f83358389f0c4ea37a7e7d9e493857f99baf0440Chris Banes        signatureInputStream.close();
229814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return signatureByte == RW2_SIGNATURE;
229914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
230014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
230114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
230214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Loads EXIF attributes from a JPEG input stream.
230314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
230414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param in The input stream that starts with the JPEG data.
230514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param jpegOffset The offset value in input stream for JPEG data.
230614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param imageType The image type from which to retrieve metadata. Use IFD_TYPE_PRIMARY for
230714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *                   primary image, IFD_TYPE_PREVIEW for preview image, and
230814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *                   IFD_TYPE_THUMBNAIL for thumbnail image.
230914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @throws IOException If the data contains invalid JPEG markers, offsets, or length values.
231014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
231114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void getJpegAttributes(ByteOrderedDataInputStream in, int jpegOffset, int imageType)
231214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throws IOException {
231314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // See JPEG File Interchange Format Specification, "JFIF Specification"
231414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (DEBUG) {
231514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Log.d(TAG, "getJpegAttributes starting with: " + in);
231614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
231714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
231814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // JPEG uses Big Endian by default. See https://people.cs.umass.edu/~verts/cs32/endian.html
231914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        in.setByteOrder(ByteOrder.BIG_ENDIAN);
232014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
232114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Skip to JPEG data
232214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        in.seek(jpegOffset);
232314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int bytesRead = jpegOffset;
232414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
232514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        byte marker;
232614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if ((marker = in.readByte()) != MARKER) {
232714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff));
232814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
232914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ++bytesRead;
233014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (in.readByte() != MARKER_SOI) {
233114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff));
233214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
233314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ++bytesRead;
233414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        while (true) {
233514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            marker = in.readByte();
233614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (marker != MARKER) {
233714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Invalid marker:" + Integer.toHexString(marker & 0xff));
233814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
233914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ++bytesRead;
234014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            marker = in.readByte();
234114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (DEBUG) {
234214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.d(TAG, "Found JPEG segment indicator: " + Integer.toHexString(marker & 0xff));
234314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
234414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ++bytesRead;
234514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
234614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // EOI indicates the end of an image and in case of SOS, JPEG image stream starts and
234714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // the image data will terminate right after.
234814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (marker == MARKER_EOI || marker == MARKER_SOS) {
234914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                break;
235014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
235114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int length = in.readUnsignedShort() - 2;
235214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            bytesRead += 2;
235314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (DEBUG) {
235414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.d(TAG, "JPEG segment: " + Integer.toHexString(marker & 0xff) + " (length: "
235514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + (length + 2) + ")");
235614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
235714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (length < 0) {
235814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Invalid length");
235914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
236014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            switch (marker) {
236114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_APP1: {
236214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (DEBUG) {
236314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        Log.d(TAG, "MARKER_APP1");
236414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
236514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (length < 6) {
236614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        // Skip if it's not an EXIF APP1 segment.
236714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
236814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
236914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    byte[] identifier = new byte[6];
237014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (in.read(identifier) != 6) {
237114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        throw new IOException("Invalid exif");
237214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
237314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    bytesRead += 6;
237414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    length -= 6;
237514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (!Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) {
237614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        // Skip if it's not an EXIF APP1 segment.
237714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
237814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
237914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (length <= 0) {
238014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        throw new IOException("Invalid exif");
238114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
238214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (DEBUG) {
238314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        Log.d(TAG, "readExifSegment with a byte array (length: " + length + ")");
238414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
238514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    // Save offset values for createJpegThumbnailBitmap() function
238614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mExifOffset = bytesRead;
238714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
238814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    byte[] bytes = new byte[length];
238914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (in.read(bytes) != length) {
239014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        throw new IOException("Invalid exif");
239114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
239214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    bytesRead += length;
239314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    length = 0;
239414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
239514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    readExifSegment(bytes, imageType);
239614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
239714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
239814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
239914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_COM: {
240014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    byte[] bytes = new byte[length];
240114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (in.read(bytes) != length) {
240214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        throw new IOException("Invalid exif");
240314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
240414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    length = 0;
240514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (getAttribute(TAG_USER_COMMENT) == null) {
240614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[IFD_TYPE_EXIF].put(TAG_USER_COMMENT, ExifAttribute.createString(
240714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                new String(bytes, ASCII)));
240814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
240914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
241014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
241114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
241214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF0:
241314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF1:
241414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF2:
241514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF3:
241614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF5:
241714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF6:
241814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF7:
241914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF9:
242014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF10:
242114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF11:
242214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF13:
242314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF14:
242414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOF15: {
242514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (in.skipBytes(1) != 1) {
242614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        throw new IOException("Invalid SOFx");
242714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
242814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mAttributes[imageType].put(TAG_IMAGE_LENGTH, ExifAttribute.createULong(
242914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            in.readUnsignedShort(), mExifByteOrder));
243014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mAttributes[imageType].put(TAG_IMAGE_WIDTH, ExifAttribute.createULong(
243114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            in.readUnsignedShort(), mExifByteOrder));
243214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    length -= 5;
243314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
243414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
243514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
243614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                default: {
243714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
243814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
243914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
244014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (length < 0) {
244114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Invalid length");
244214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
244314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (in.skipBytes(length) != length) {
244414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Invalid JPEG segment");
244514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
244614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            bytesRead += length;
244714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
244814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Restore original byte order
244914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        in.setByteOrder(mExifByteOrder);
245014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
245114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
245214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void getRawAttributes(ByteOrderedDataInputStream in) throws IOException {
245314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Parse TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1.
245414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        parseTiffHeaders(in, in.available());
245514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
245614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6.
245714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        readImageFileDirectory(in, IFD_TYPE_PRIMARY);
245814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
245914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Update ImageLength/Width tags for all image data.
246014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        updateImageSizeValues(in, IFD_TYPE_PRIMARY);
246114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        updateImageSizeValues(in, IFD_TYPE_PREVIEW);
246214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        updateImageSizeValues(in, IFD_TYPE_THUMBNAIL);
246314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
246414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Check if each image data is in valid position.
246514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        validateImages(in);
246614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
246714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (mMimeType == IMAGE_TYPE_PEF) {
246814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // PEF files contain a MakerNote data, which contains the data for ColorSpace tag.
246914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // See http://lclevy.free.fr/raw/ and piex.cc PefGetPreviewData()
247014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ExifAttribute makerNoteAttribute =
247114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_MAKER_NOTE);
247214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (makerNoteAttribute != null) {
247314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Create an ordered DataInputStream for MakerNote
247414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                ByteOrderedDataInputStream makerNoteDataInputStream =
247514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        new ByteOrderedDataInputStream(makerNoteAttribute.bytes);
247614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                makerNoteDataInputStream.setByteOrder(mExifByteOrder);
247714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
247814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Seek to MakerNote data
247914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                makerNoteDataInputStream.seek(PEF_MAKER_NOTE_SKIP_SIZE);
248014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
248114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Read IFD data from MakerNote
248214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                readImageFileDirectory(makerNoteDataInputStream, IFD_TYPE_PEF);
248314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
248414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Update ColorSpace tag
248514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                ExifAttribute colorSpaceAttribute =
248614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        (ExifAttribute) mAttributes[IFD_TYPE_PEF].get(TAG_COLOR_SPACE);
248714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (colorSpaceAttribute != null) {
248814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mAttributes[IFD_TYPE_EXIF].put(TAG_COLOR_SPACE, colorSpaceAttribute);
248914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
249014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
249114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
249214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
249314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
249414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
249514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * RAF files contains a JPEG and a CFA data.
249614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * The JPEG contains two images, a preview and a thumbnail, while the CFA contains a RAW image.
249714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * This method looks at the first 160 bytes of a RAF file to retrieve the offset and length
249814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * values for the JPEG and CFA data.
249914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Using that data, it parses the JPEG data to retrieve the preview and thumbnail image data,
250014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * then parses the CFA metadata to retrieve the primary image length/width values.
250114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * For data format details, see http://fileformats.archiveteam.org/wiki/Fujifilm_RAF
250214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
250314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void getRafAttributes(ByteOrderedDataInputStream in) throws IOException {
250414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Retrieve offset & length values
250514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        in.skipBytes(RAF_OFFSET_TO_JPEG_IMAGE_OFFSET);
250614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        byte[] jpegOffsetBytes = new byte[4];
250714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        byte[] cfaHeaderOffsetBytes = new byte[4];
250814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        in.read(jpegOffsetBytes);
250914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Skip JPEG length value since it is not needed
251014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        in.skipBytes(RAF_JPEG_LENGTH_VALUE_SIZE);
251114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        in.read(cfaHeaderOffsetBytes);
251214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int rafJpegOffset = ByteBuffer.wrap(jpegOffsetBytes).getInt();
251314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int rafCfaHeaderOffset = ByteBuffer.wrap(cfaHeaderOffsetBytes).getInt();
251414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
251514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Retrieve JPEG image metadata
251614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        getJpegAttributes(in, rafJpegOffset, IFD_TYPE_PREVIEW);
251714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
251814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Skip to CFA header offset.
251914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        in.seek(rafCfaHeaderOffset);
252014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
252114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Retrieve primary image length/width values, if TAG_RAF_IMAGE_SIZE exists
252214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        in.setByteOrder(ByteOrder.BIG_ENDIAN);
252314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int numberOfDirectoryEntry = in.readInt();
252414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (DEBUG) {
252514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry);
252614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
252714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // CFA stores some metadata about the RAW image. Since CFA uses proprietary tags, can only
252814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // find and retrieve image size information tags, while skipping others.
252914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // See piex.cc RafGetDimension()
253014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int i = 0; i < numberOfDirectoryEntry; ++i) {
253114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int tagNumber = in.readUnsignedShort();
253214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int numberOfBytes = in.readUnsignedShort();
253314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (tagNumber == TAG_RAF_IMAGE_SIZE.number) {
253414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int imageLength = in.readShort();
253514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int imageWidth = in.readShort();
253614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                ExifAttribute imageLengthAttribute =
253714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        ExifAttribute.createUShort(imageLength, mExifByteOrder);
253814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                ExifAttribute imageWidthAttribute =
253914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        ExifAttribute.createUShort(imageWidth, mExifByteOrder);
254014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH, imageLengthAttribute);
254114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH, imageWidthAttribute);
254214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (DEBUG) {
254314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.d(TAG, "Updated to length: " + imageLength + ", width: " + imageWidth);
254414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
254514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return;
254614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
254714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            in.skipBytes(numberOfBytes);
254814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
254914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
255014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
255114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
255214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * ORF files contains a primary image data and a MakerNote data that contains preview/thumbnail
255314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * images. Both data takes the form of IFDs and can therefore be read with the
255414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * readImageFileDirectory() method.
255514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * This method reads all the necessary data and updates the primary/preview/thumbnail image
255614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * information according to the GetOlympusPreviewImage() method in piex.cc.
255714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * For data format details, see the following:
255814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * http://fileformats.archiveteam.org/wiki/Olympus_ORF
255914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * https://libopenraw.freedesktop.org/wiki/Olympus_ORF
256014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
256114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void getOrfAttributes(ByteOrderedDataInputStream in) throws IOException {
256214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Retrieve primary image data
256314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Other Exif data will be located in the Makernote.
256414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        getRawAttributes(in);
256514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
256614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Additionally retrieve preview/thumbnail information from MakerNote tag, which contains
256714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // proprietary tags and therefore does not have offical documentation
256814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // See GetOlympusPreviewImage() in piex.cc & http://www.exiv2.org/tags-olympus.html
256914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute makerNoteAttribute =
257014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_MAKER_NOTE);
257114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (makerNoteAttribute != null) {
257214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Create an ordered DataInputStream for MakerNote
257314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ByteOrderedDataInputStream makerNoteDataInputStream =
257414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    new ByteOrderedDataInputStream(makerNoteAttribute.bytes);
257514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            makerNoteDataInputStream.setByteOrder(mExifByteOrder);
257614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
257714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // There are two types of headers for Olympus MakerNotes
257814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // See http://www.exiv2.org/makernote.html#R1
257914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            byte[] makerNoteHeader1Bytes = new byte[ORF_MAKER_NOTE_HEADER_1.length];
258014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            makerNoteDataInputStream.readFully(makerNoteHeader1Bytes);
258114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            makerNoteDataInputStream.seek(0);
258214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            byte[] makerNoteHeader2Bytes = new byte[ORF_MAKER_NOTE_HEADER_2.length];
258314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            makerNoteDataInputStream.readFully(makerNoteHeader2Bytes);
258414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Skip the corresponding amount of bytes for each header type
258514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (Arrays.equals(makerNoteHeader1Bytes, ORF_MAKER_NOTE_HEADER_1)) {
258614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                makerNoteDataInputStream.seek(ORF_MAKER_NOTE_HEADER_1_SIZE);
258714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else if (Arrays.equals(makerNoteHeader2Bytes, ORF_MAKER_NOTE_HEADER_2)) {
258814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                makerNoteDataInputStream.seek(ORF_MAKER_NOTE_HEADER_2_SIZE);
258914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
259014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
259114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Read IFD data from MakerNote
259214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            readImageFileDirectory(makerNoteDataInputStream, IFD_TYPE_ORF_MAKER_NOTE);
259314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
259414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Retrieve & update preview image offset & length values
259514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ExifAttribute imageLengthAttribute = (ExifAttribute)
259614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mAttributes[IFD_TYPE_ORF_CAMERA_SETTINGS].get(TAG_ORF_PREVIEW_IMAGE_START);
259714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ExifAttribute bitsPerSampleAttribute = (ExifAttribute)
259814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mAttributes[IFD_TYPE_ORF_CAMERA_SETTINGS].get(TAG_ORF_PREVIEW_IMAGE_LENGTH);
259914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
260014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (imageLengthAttribute != null && bitsPerSampleAttribute != null) {
260114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mAttributes[IFD_TYPE_PREVIEW].put(TAG_JPEG_INTERCHANGE_FORMAT,
260214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        imageLengthAttribute);
260314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mAttributes[IFD_TYPE_PREVIEW].put(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
260414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        bitsPerSampleAttribute);
260514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
260614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
260714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // TODO: Check this behavior in other ORF files
260814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Retrieve primary image length & width values
260914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // See piex.cc GetOlympusPreviewImage()
261014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ExifAttribute aspectFrameAttribute = (ExifAttribute)
261114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mAttributes[IFD_TYPE_ORF_IMAGE_PROCESSING].get(TAG_ORF_ASPECT_FRAME);
261214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (aspectFrameAttribute != null) {
261314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int[] aspectFrameValues = (int[]) aspectFrameAttribute.getValue(mExifByteOrder);
261414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (aspectFrameValues == null || aspectFrameValues.length != 4) {
261514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.w(TAG, "Invalid aspect frame values. frame="
261614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            + Arrays.toString(aspectFrameValues));
261714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return;
261814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
261914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (aspectFrameValues[2] > aspectFrameValues[0] &&
262014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        aspectFrameValues[3] > aspectFrameValues[1]) {
262114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    int primaryImageWidth = aspectFrameValues[2] - aspectFrameValues[0] + 1;
262214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    int primaryImageLength = aspectFrameValues[3] - aspectFrameValues[1] + 1;
262314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    // Swap width & length values
262414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (primaryImageWidth < primaryImageLength) {
262514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        primaryImageWidth += primaryImageLength;
262614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        primaryImageLength = primaryImageWidth - primaryImageLength;
262714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        primaryImageWidth -= primaryImageLength;
262814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
262914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute primaryImageWidthAttribute =
263014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            ExifAttribute.createUShort(primaryImageWidth, mExifByteOrder);
263114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute primaryImageLengthAttribute =
263214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            ExifAttribute.createUShort(primaryImageLength, mExifByteOrder);
263314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
263414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH, primaryImageWidthAttribute);
263514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH, primaryImageLengthAttribute);
263614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
263714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
263814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
263914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
264014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
264114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // RW2 contains the primary image data in IFD0 and the preview and/or thumbnail image data in
264214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // the JpgFromRaw tag
264314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // See https://libopenraw.freedesktop.org/wiki/Panasonic_RAW/ and piex.cc Rw2GetPreviewData()
264414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void getRw2Attributes(ByteOrderedDataInputStream in) throws IOException {
264514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Retrieve primary image data
264614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        getRawAttributes(in);
264714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
264814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Retrieve preview and/or thumbnail image data
264914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute jpgFromRawAttribute =
265014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[IFD_TYPE_PRIMARY].get(TAG_RW2_JPG_FROM_RAW);
265114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (jpgFromRawAttribute != null) {
265214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            getJpegAttributes(in, mRw2JpgFromRawOffset, IFD_TYPE_PREVIEW);
265314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
265414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
265514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Set ISO tag value if necessary
265614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute rw2IsoAttribute =
265714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[IFD_TYPE_PRIMARY].get(TAG_RW2_ISO);
265814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute exifIsoAttribute =
265914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_ISO_SPEED_RATINGS);
266014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (rw2IsoAttribute != null && exifIsoAttribute == null) {
266114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Place this attribute only if it doesn't exist
266214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_EXIF].put(TAG_ISO_SPEED_RATINGS, rw2IsoAttribute);
266314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
266414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
266514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
266614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Stores a new JPEG image with EXIF attributes into a given output stream.
266714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void saveJpegAttributes(InputStream inputStream, OutputStream outputStream)
266814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throws IOException {
266914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // See JPEG File Interchange Format Specification, "JFIF Specification"
267014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (DEBUG) {
267114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Log.d(TAG, "saveJpegAttributes starting with (inputStream: " + inputStream
267214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    + ", outputStream: " + outputStream + ")");
267314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
267414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        DataInputStream dataInputStream = new DataInputStream(inputStream);
267514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ByteOrderedDataOutputStream dataOutputStream =
267614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                new ByteOrderedDataOutputStream(outputStream, ByteOrder.BIG_ENDIAN);
267714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (dataInputStream.readByte() != MARKER) {
267814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("Invalid marker");
267914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
268014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataOutputStream.writeByte(MARKER);
268114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (dataInputStream.readByte() != MARKER_SOI) {
268214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("Invalid marker");
268314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
268414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataOutputStream.writeByte(MARKER_SOI);
268514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
268614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Write EXIF APP1 segment
268714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataOutputStream.writeByte(MARKER);
268814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataOutputStream.writeByte(MARKER_APP1);
268914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        writeExifSegment(dataOutputStream, 6);
269014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
269114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        byte[] bytes = new byte[4096];
269214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
269314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        while (true) {
269414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            byte marker = dataInputStream.readByte();
269514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (marker != MARKER) {
269614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Invalid marker");
269714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
269814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            marker = dataInputStream.readByte();
269914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            switch (marker) {
270014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_APP1: {
270114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    int length = dataInputStream.readUnsignedShort() - 2;
270214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (length < 0) {
270314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        throw new IOException("Invalid length");
270414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
270514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    byte[] identifier = new byte[6];
270614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (length >= 6) {
270714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        if (dataInputStream.read(identifier) != 6) {
270814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            throw new IOException("Invalid exif");
270914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
271014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        if (Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) {
271114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            // Skip the original EXIF APP1 segment.
271214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            if (dataInputStream.skipBytes(length - 6) != length - 6) {
271314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                throw new IOException("Invalid length");
271414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            }
271514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            break;
271614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
271714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
271814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    // Copy non-EXIF APP1 segment.
271914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeByte(MARKER);
272014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeByte(marker);
272114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeUnsignedShort(length + 2);
272214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (length >= 6) {
272314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        length -= 6;
272414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        dataOutputStream.write(identifier);
272514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
272614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    int read;
272714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    while (length > 0 && (read = dataInputStream.read(
272814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            bytes, 0, Math.min(length, bytes.length))) >= 0) {
272914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        dataOutputStream.write(bytes, 0, read);
273014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        length -= read;
273114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
273214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
273314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
273414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_EOI:
273514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case MARKER_SOS: {
273614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeByte(MARKER);
273714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeByte(marker);
273814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    // Copy all the remaining data
273914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    copy(dataInputStream, dataOutputStream);
274014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return;
274114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
274214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                default: {
274314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    // Copy JPEG segment
274414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeByte(MARKER);
274514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeByte(marker);
274614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    int length = dataInputStream.readUnsignedShort();
274714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeUnsignedShort(length);
274814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    length -= 2;
274914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (length < 0) {
275014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        throw new IOException("Invalid length");
275114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
275214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    int read;
275314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    while (length > 0 && (read = dataInputStream.read(
275414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            bytes, 0, Math.min(length, bytes.length))) >= 0) {
275514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        dataOutputStream.write(bytes, 0, read);
275614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        length -= read;
275714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
275814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
275914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
276014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
276114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
276214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
276314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
276414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Reads the given EXIF byte area and save its tag data into attributes.
276514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void readExifSegment(byte[] exifBytes, int imageType) throws IOException {
276614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ByteOrderedDataInputStream dataInputStream =
276714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                new ByteOrderedDataInputStream(exifBytes);
276814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
276914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Parse TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1.
277014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        parseTiffHeaders(dataInputStream, exifBytes.length);
277114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
277214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6.
277314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        readImageFileDirectory(dataInputStream, imageType);
277414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
277514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
277614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void addDefaultValuesForCompatibility() {
2777a39fc6268fbf33ad5d39829cacebf49b11f35c3eHyundo Moon        // If DATETIME tag has no value, then set the value to DATETIME_ORIGINAL tag's.
277814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        String valueOfDateTimeOriginal = getAttribute(TAG_DATETIME_ORIGINAL);
2779a39fc6268fbf33ad5d39829cacebf49b11f35c3eHyundo Moon        if (valueOfDateTimeOriginal != null && getAttribute(TAG_DATETIME) == null) {
278014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_PRIMARY].put(TAG_DATETIME,
278114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createString(valueOfDateTimeOriginal));
278214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
278314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
278414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Add the default value.
278514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (getAttribute(TAG_IMAGE_WIDTH) == null) {
278614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH,
278714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(0, mExifByteOrder));
278814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
278914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (getAttribute(TAG_IMAGE_LENGTH) == null) {
279014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH,
279114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(0, mExifByteOrder));
279214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
279314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (getAttribute(TAG_ORIENTATION) == null) {
279414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_PRIMARY].put(TAG_ORIENTATION,
279514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(0, mExifByteOrder));
279614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
279714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (getAttribute(TAG_LIGHT_SOURCE) == null) {
279814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_EXIF].put(TAG_LIGHT_SOURCE,
279914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(0, mExifByteOrder));
280014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
280114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
280214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
280314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private ByteOrder readByteOrder(ByteOrderedDataInputStream dataInputStream)
280414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throws IOException {
280514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Read byte order.
280614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        short byteOrder = dataInputStream.readShort();
280714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        switch (byteOrder) {
280814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            case BYTE_ALIGN_II:
280914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (DEBUG) {
281014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.d(TAG, "readExifSegment: Byte Align II");
281114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
281214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return ByteOrder.LITTLE_ENDIAN;
281314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            case BYTE_ALIGN_MM:
281414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (DEBUG) {
281514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.d(TAG, "readExifSegment: Byte Align MM");
281614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
281714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return ByteOrder.BIG_ENDIAN;
281814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            default:
281914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Invalid byte order: " + Integer.toHexString(byteOrder));
282014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
282114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
282214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
282314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void parseTiffHeaders(ByteOrderedDataInputStream dataInputStream,
282414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int exifBytesLength) throws IOException {
282514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Read byte order
282614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        mExifByteOrder = readByteOrder(dataInputStream);
282714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Set byte order
282814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataInputStream.setByteOrder(mExifByteOrder);
282914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
283014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Check start code
283114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int startCode = dataInputStream.readUnsignedShort();
283214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (mMimeType != IMAGE_TYPE_ORF && mMimeType != IMAGE_TYPE_RW2 && startCode != START_CODE) {
283314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("Invalid start code: " + Integer.toHexString(startCode));
283414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
283514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
283614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Read and skip to first ifd offset
283714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int firstIfdOffset = dataInputStream.readInt();
283814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (firstIfdOffset < 8 || firstIfdOffset >= exifBytesLength) {
283914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("Invalid first Ifd offset: " + firstIfdOffset);
284014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
284114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        firstIfdOffset -= 8;
284214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (firstIfdOffset > 0) {
284314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (dataInputStream.skipBytes(firstIfdOffset) != firstIfdOffset) {
284414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Couldn't jump to first Ifd: " + firstIfdOffset);
284514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
284614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
284714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
284814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
284914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Reads image file directory, which is a tag group in EXIF.
285014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void readImageFileDirectory(ByteOrderedDataInputStream dataInputStream,
285114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            @IfdType int ifdType) throws IOException {
285214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (dataInputStream.mPosition + 2 > dataInputStream.mLength) {
285314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Return if there is no data from the offset.
285414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return;
285514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
285614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // See TIFF 6.0 Section 2: TIFF Structure, Figure 1.
285714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        short numberOfDirectoryEntry = dataInputStream.readShort();
285814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (dataInputStream.mPosition + 12 * numberOfDirectoryEntry > dataInputStream.mLength) {
285914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Return if the size of entries is too big.
286014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return;
286114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
286214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
286314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (DEBUG) {
286414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry);
286514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
286614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
286714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // See TIFF 6.0 Section 2: TIFF Structure, "Image File Directory".
286814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (short i = 0; i < numberOfDirectoryEntry; ++i) {
286914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int tagNumber = dataInputStream.readUnsignedShort();
287014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int dataFormat = dataInputStream.readUnsignedShort();
287114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int numberOfComponents = dataInputStream.readInt();
287214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Next four bytes is for data offset or value.
287314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            long nextEntryOffset = dataInputStream.peek() + 4;
287414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
287514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Look up a corresponding tag from tag number
287614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ExifTag tag = (ExifTag) sExifTagMapsForReading[ifdType].get(tagNumber);
287714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
287814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (DEBUG) {
287914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.d(TAG, String.format("ifdType: %d, tagNumber: %d, tagName: %s, dataFormat: %d, "
288014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + "numberOfComponents: %d", ifdType, tagNumber,
288114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        tag != null ? tag.name : null, dataFormat, numberOfComponents));
288214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
288314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
288414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            long byteCount = 0;
288514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            boolean valid = false;
288614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (tag == null) {
288714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.w(TAG, "Skip the tag entry since tag number is not defined: " + tagNumber);
288814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else if (dataFormat <= 0 || dataFormat >= IFD_FORMAT_BYTES_PER_FORMAT.length) {
288914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.w(TAG, "Skip the tag entry since data format is invalid: " + dataFormat);
289014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else {
289114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                byteCount = (long) numberOfComponents * IFD_FORMAT_BYTES_PER_FORMAT[dataFormat];
289214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (byteCount < 0 || byteCount > Integer.MAX_VALUE) {
289314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.w(TAG, "Skip the tag entry since the number of components is invalid: "
289414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            + numberOfComponents);
289514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } else {
289614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    valid = true;
289714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
289814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
289914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (!valid) {
290014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                dataInputStream.seek(nextEntryOffset);
290114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                continue;
290214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
290314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
290414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Read a value from data field or seek to the value offset which is stored in data
290514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // field if the size of the entry value is bigger than 4.
290614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (byteCount > 4) {
290714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int offset = dataInputStream.readInt();
290814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (DEBUG) {
290914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.d(TAG, "seek to data offset: " + offset);
291014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
291114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (mMimeType == IMAGE_TYPE_ORF) {
291289889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon                    if (TAG_MAKER_NOTE.equals(tag.name)) {
291314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        // Save offset value for reading thumbnail
291414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mOrfMakerNoteOffset = offset;
291514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    } else if (ifdType == IFD_TYPE_ORF_MAKER_NOTE
291689889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon                            && TAG_ORF_THUMBNAIL_IMAGE.equals(tag.name)) {
291714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        // Retrieve & update values for thumbnail offset and length values for ORF
291814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mOrfThumbnailOffset = offset;
291914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mOrfThumbnailLength = numberOfComponents;
292014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
292114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        ExifAttribute compressionAttribute =
292214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                ExifAttribute.createUShort(DATA_JPEG, mExifByteOrder);
292314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        ExifAttribute jpegInterchangeFormatAttribute =
292414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                ExifAttribute.createULong(mOrfThumbnailOffset, mExifByteOrder);
292514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        ExifAttribute jpegInterchangeFormatLengthAttribute =
292614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                ExifAttribute.createULong(mOrfThumbnailLength, mExifByteOrder);
292714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
292814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[IFD_TYPE_THUMBNAIL].put(TAG_COMPRESSION, compressionAttribute);
292914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[IFD_TYPE_THUMBNAIL].put(TAG_JPEG_INTERCHANGE_FORMAT,
293014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                jpegInterchangeFormatAttribute);
293114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mAttributes[IFD_TYPE_THUMBNAIL].put(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
293214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                jpegInterchangeFormatLengthAttribute);
293314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
293414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } else if (mMimeType == IMAGE_TYPE_RW2) {
293589889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon                    if (TAG_RW2_JPG_FROM_RAW.equals(tag.name)) {
293614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        mRw2JpgFromRawOffset = offset;
293714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
293814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
293914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (offset + byteCount <= dataInputStream.mLength) {
294014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataInputStream.seek(offset);
294114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } else {
294214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    // Skip if invalid data offset.
294314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.w(TAG, "Skip the tag entry since data offset is invalid: " + offset);
294414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataInputStream.seek(nextEntryOffset);
294514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    continue;
294614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
294714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
294814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
294914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Recursively parse IFD when a IFD pointer tag appears.
2950abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas            Integer nextIfdType = sExifPointerTagMap.get(tagNumber);
295114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (DEBUG) {
295214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.d(TAG, "nextIfdType: " + nextIfdType + " byteCount: " + byteCount);
295314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
295414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
295514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (nextIfdType != null) {
295614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                long offset = -1L;
295714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Get offset from data field
295814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                switch (dataFormat) {
295914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_USHORT: {
296014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        offset = dataInputStream.readUnsignedShort();
296114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
296214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
296314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_SSHORT: {
296414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        offset = dataInputStream.readShort();
296514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
296614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
296714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_ULONG: {
296814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        offset = dataInputStream.readUnsignedInt();
296914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
297014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
297114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_SLONG:
297214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    case IFD_FORMAT_IFD: {
297314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        offset = dataInputStream.readInt();
297414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
297514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
297614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    default: {
297714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        // Nothing to do
297814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        break;
297914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
298014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
298114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (DEBUG) {
298214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.d(TAG, String.format("Offset: %d, tagName: %s", offset, tag.name));
298314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
298414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (offset > 0L && offset < dataInputStream.mLength) {
298514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataInputStream.seek(offset);
2986abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                    readImageFileDirectory(dataInputStream, nextIfdType);
298714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } else {
298814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.w(TAG, "Skip jump into the IFD since its offset is invalid: " + offset);
298914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
299014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
299114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                dataInputStream.seek(nextEntryOffset);
299214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                continue;
299314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
299414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
299514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            byte[] bytes = new byte[(int) byteCount];
299614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            dataInputStream.readFully(bytes);
299714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents, bytes);
299814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[ifdType].put(tag.name, attribute);
299914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
300014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // DNG files have a DNG Version tag specifying the version of specifications that the
300114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // image file is following.
300214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // See http://fileformats.archiveteam.org/wiki/DNG
300389889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon            if (TAG_DNG_VERSION.equals(tag.name)) {
300414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mMimeType = IMAGE_TYPE_DNG;
300514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
300614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
300714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // PEF files have a Make or Model tag that begins with "PENTAX" or a compression tag
300814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // that is 65535.
300914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // See http://fileformats.archiveteam.org/wiki/Pentax_PEF
301089889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon            if (((TAG_MAKE.equals(tag.name) || TAG_MODEL.equals(tag.name))
301114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    && attribute.getStringValue(mExifByteOrder).contains(PEF_SIGNATURE))
301289889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon                    || (TAG_COMPRESSION.equals(tag.name)
301314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    && attribute.getIntValue(mExifByteOrder) == 65535)) {
301414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mMimeType = IMAGE_TYPE_PEF;
301514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
301614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
301714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Seek to next tag offset
301814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (dataInputStream.peek() != nextEntryOffset) {
301914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                dataInputStream.seek(nextEntryOffset);
302014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
302114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
302214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
302314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (dataInputStream.peek() + 4 <= dataInputStream.mLength) {
302414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int nextIfdOffset = dataInputStream.readInt();
302514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (DEBUG) {
302614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset));
302714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
302814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // The next IFD offset needs to be bigger than 8
302914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // since the first IFD offset is at least 8.
303014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (nextIfdOffset > 8 && nextIfdOffset < dataInputStream.mLength) {
303114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                dataInputStream.seek(nextIfdOffset);
303214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) {
303314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    // Do not overwrite thumbnail IFD data if it alreay exists.
303414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    readImageFileDirectory(dataInputStream, IFD_TYPE_THUMBNAIL);
303514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } else if (mAttributes[IFD_TYPE_PREVIEW].isEmpty()) {
303614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    readImageFileDirectory(dataInputStream, IFD_TYPE_PREVIEW);
303714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
303814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
303914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
304014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
304114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
304214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
304314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * JPEG compressed images do not contain IMAGE_LENGTH & IMAGE_WIDTH tags.
304414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * This value uses JpegInterchangeFormat(JPEG data offset) value, and calls getJpegAttributes()
304514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * to locate SOF(Start of Frame) marker and update the image length & width values.
304614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * See JEITA CP-3451C Table 5 and Section 4.8.1. B.
304714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
304814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void retrieveJpegImageSize(ByteOrderedDataInputStream in, int imageType)
304914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throws IOException {
305014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Check if image already has IMAGE_LENGTH & IMAGE_WIDTH values
305114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute imageLengthAttribute =
305214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[imageType].get(TAG_IMAGE_LENGTH);
305314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute imageWidthAttribute =
305414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[imageType].get(TAG_IMAGE_WIDTH);
305514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
305614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (imageLengthAttribute == null || imageWidthAttribute == null) {
305714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Find if offset for JPEG data exists
305814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ExifAttribute jpegInterchangeFormatAttribute =
305914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    (ExifAttribute) mAttributes[imageType].get(TAG_JPEG_INTERCHANGE_FORMAT);
306014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (jpegInterchangeFormatAttribute != null) {
306114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int jpegInterchangeFormat =
306214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder);
306314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
306414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Searches for SOF marker in JPEG data and updates IMAGE_LENGTH & IMAGE_WIDTH tags
306514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                getJpegAttributes(in, jpegInterchangeFormat, imageType);
306614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
306714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
306814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
306914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
307014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Sets thumbnail offset & length attributes based on JpegInterchangeFormat or StripOffsets tags
307114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void setThumbnailData(ByteOrderedDataInputStream in) throws IOException {
307214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        HashMap thumbnailData = mAttributes[IFD_TYPE_THUMBNAIL];
307314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
307414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute compressionAttribute =
307514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) thumbnailData.get(TAG_COMPRESSION);
307614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (compressionAttribute != null) {
307714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mThumbnailCompression = compressionAttribute.getIntValue(mExifByteOrder);
307814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            switch (mThumbnailCompression) {
307914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case DATA_JPEG: {
308014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    handleThumbnailFromJfif(in, thumbnailData);
308114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
308214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
308314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case DATA_UNCOMPRESSED:
308414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                case DATA_JPEG_COMPRESSED: {
308514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (isSupportedDataType(thumbnailData)) {
308614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        handleThumbnailFromStrips(in, thumbnailData);
308714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
308814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    break;
308914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
309014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
309114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else {
309214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Thumbnail data may not contain Compression tag value
309314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mThumbnailCompression = DATA_JPEG;
309414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            handleThumbnailFromJfif(in, thumbnailData);
309514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
309614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
309714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
309814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Check JpegInterchangeFormat(JFIF) tags to retrieve thumbnail offset & length values
309914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // and reads the corresponding bytes if stream does not support seek function
310014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void handleThumbnailFromJfif(ByteOrderedDataInputStream in, HashMap thumbnailData)
310114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throws IOException {
310214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute jpegInterchangeFormatAttribute =
310314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT);
310414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute jpegInterchangeFormatLengthAttribute =
310514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
310614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (jpegInterchangeFormatAttribute != null
310714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                && jpegInterchangeFormatLengthAttribute != null) {
310814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int thumbnailOffset = jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder);
310914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int thumbnailLength = jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder);
311014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
311114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // The following code limits the size of thumbnail size not to overflow EXIF data area.
311214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            thumbnailLength = Math.min(thumbnailLength, in.available() - thumbnailOffset);
311314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF
311414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    || mMimeType == IMAGE_TYPE_RW2) {
311514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                thumbnailOffset += mExifOffset;
311614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else if (mMimeType == IMAGE_TYPE_ORF) {
311714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Update offset value since RAF files have IFD data preceding MakerNote data.
311814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                thumbnailOffset += mOrfMakerNoteOffset;
311914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
312014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (DEBUG) {
312114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.d(TAG, "Setting thumbnail attributes with offset: " + thumbnailOffset
312214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + ", length: " + thumbnailLength);
312314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
312414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (thumbnailOffset > 0 && thumbnailLength > 0) {
312514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mHasThumbnail = true;
312614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mThumbnailOffset = thumbnailOffset;
312714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mThumbnailLength = thumbnailLength;
312814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (mFilename == null && mAssetInputStream == null) {
312914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    // Save the thumbnail in memory if the input doesn't support reading again.
313014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    byte[] thumbnailBytes = new byte[thumbnailLength];
313114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    in.seek(thumbnailOffset);
313214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    in.readFully(thumbnailBytes);
313314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mThumbnailBytes = thumbnailBytes;
313414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
313514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
313614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
313714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
313814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
313914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Check StripOffsets & StripByteCounts tags to retrieve thumbnail offset & length values
314014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void handleThumbnailFromStrips(ByteOrderedDataInputStream in, HashMap thumbnailData)
314114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throws IOException {
314214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute stripOffsetsAttribute =
314314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) thumbnailData.get(TAG_STRIP_OFFSETS);
314414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute stripByteCountsAttribute =
314514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) thumbnailData.get(TAG_STRIP_BYTE_COUNTS);
314614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
314714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (stripOffsetsAttribute != null && stripByteCountsAttribute != null) {
314814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            long[] stripOffsets =
3149f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon                    convertToLongArray(stripOffsetsAttribute.getValue(mExifByteOrder));
315014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            long[] stripByteCounts =
3151f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon                    convertToLongArray(stripByteCountsAttribute.getValue(mExifByteOrder));
315214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
315314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (stripOffsets == null) {
315414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.w(TAG, "stripOffsets should not be null.");
315514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return;
315614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
315714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (stripByteCounts == null) {
315814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.w(TAG, "stripByteCounts should not be null.");
315914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return;
316014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
316114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
316214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            long totalStripByteCount = 0;
316314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (long byteCount : stripByteCounts) {
316414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                totalStripByteCount += byteCount;
316514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
316614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
316714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Set thumbnail byte array data for non-consecutive strip bytes
316814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            byte[] totalStripBytes = new byte[(int) totalStripByteCount];
316914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
317014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int bytesRead = 0;
317114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int bytesAdded = 0;
317214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (int i = 0; i < stripOffsets.length; i++) {
317314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int stripOffset = (int) stripOffsets[i];
317414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int stripByteCount = (int) stripByteCounts[i];
317514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
317614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Skip to offset
317714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int skipBytes = stripOffset - bytesRead;
317814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (skipBytes < 0) {
317914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.d(TAG, "Invalid strip offset value");
318014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
318114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                in.seek(skipBytes);
318214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                bytesRead += skipBytes;
318314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
318414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Read strip bytes
318514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                byte[] stripBytes = new byte[stripByteCount];
318614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                in.read(stripBytes);
318714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                bytesRead += stripByteCount;
318814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
318914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Add bytes to array
319014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                System.arraycopy(stripBytes, 0, totalStripBytes, bytesAdded,
319114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        stripBytes.length);
319214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                bytesAdded += stripBytes.length;
319314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
319414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
319514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mHasThumbnail = true;
319614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mThumbnailBytes = totalStripBytes;
319714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mThumbnailLength = totalStripBytes.length;
319814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
319914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
320014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
320114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Check if thumbnail data type is currently supported or not
320214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private boolean isSupportedDataType(HashMap thumbnailData) throws IOException {
320314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute bitsPerSampleAttribute =
320414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) thumbnailData.get(TAG_BITS_PER_SAMPLE);
320514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (bitsPerSampleAttribute != null) {
320614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int[] bitsPerSampleValue = (int[]) bitsPerSampleAttribute.getValue(mExifByteOrder);
320714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
320814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (Arrays.equals(BITS_PER_SAMPLE_RGB, bitsPerSampleValue)) {
320914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return true;
321014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
321114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
321214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // See DNG Specification 1.4.0.0. Section 3, Compression.
321314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mMimeType == IMAGE_TYPE_DNG) {
321414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                ExifAttribute photometricInterpretationAttribute =
321514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        (ExifAttribute) thumbnailData.get(TAG_PHOTOMETRIC_INTERPRETATION);
321614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (photometricInterpretationAttribute != null) {
321714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    int photometricInterpretationValue
321814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            = photometricInterpretationAttribute.getIntValue(mExifByteOrder);
321914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if ((photometricInterpretationValue == PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO
322014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            && Arrays.equals(bitsPerSampleValue, BITS_PER_SAMPLE_GREYSCALE_2))
322114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            || ((photometricInterpretationValue == PHOTOMETRIC_INTERPRETATION_YCBCR)
322214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            && (Arrays.equals(bitsPerSampleValue, BITS_PER_SAMPLE_RGB)))) {
322314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return true;
322414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    } else {
322514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        // TODO: Add support for lossless Huffman JPEG data
322614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
322714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
322814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
322914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
323014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (DEBUG) {
323114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Log.d(TAG, "Unsupported data type value");
323214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
323314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return false;
323414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
323514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
323614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Returns true if the image length and width values are <= 512.
323714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // See Section 4.8 of http://standardsproposals.bsigroup.com/Home/getPDF/567
323814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private boolean isThumbnail(HashMap map) throws IOException {
323914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute imageLengthAttribute = (ExifAttribute) map.get(TAG_IMAGE_LENGTH);
324014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute imageWidthAttribute = (ExifAttribute) map.get(TAG_IMAGE_WIDTH);
324114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
324214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (imageLengthAttribute != null && imageWidthAttribute != null) {
324314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int imageLengthValue = imageLengthAttribute.getIntValue(mExifByteOrder);
324414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int imageWidthValue = imageWidthAttribute.getIntValue(mExifByteOrder);
324514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (imageLengthValue <= MAX_THUMBNAIL_SIZE && imageWidthValue <= MAX_THUMBNAIL_SIZE) {
324614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return true;
324714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
324814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
324914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return false;
325014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
325114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
325214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Validate primary, preview, thumbnail image data by comparing image size
325314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void validateImages(InputStream in) throws IOException {
325414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Swap images based on size (primary > preview > thumbnail)
325514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        swapBasedOnImageSize(IFD_TYPE_PRIMARY, IFD_TYPE_PREVIEW);
325614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        swapBasedOnImageSize(IFD_TYPE_PRIMARY, IFD_TYPE_THUMBNAIL);
325714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        swapBasedOnImageSize(IFD_TYPE_PREVIEW, IFD_TYPE_THUMBNAIL);
325814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
325914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Check if image has PixelXDimension/PixelYDimension tags, which contain valid image
326014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // sizes, excluding padding at the right end or bottom end of the image to make sure that
326114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // the values are multiples of 64. See JEITA CP-3451C Table 5 and Section 4.8.1. B.
326214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute pixelXDimAttribute =
326314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_PIXEL_X_DIMENSION);
326414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute pixelYDimAttribute =
326514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_PIXEL_Y_DIMENSION);
326614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (pixelXDimAttribute != null && pixelYDimAttribute != null) {
326714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH, pixelXDimAttribute);
326814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH, pixelYDimAttribute);
326914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
327014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
327114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Check whether thumbnail image exists and whether preview image satisfies the thumbnail
327214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // image requirements
327314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) {
327414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (isThumbnail(mAttributes[IFD_TYPE_PREVIEW])) {
327514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mAttributes[IFD_TYPE_THUMBNAIL] = mAttributes[IFD_TYPE_PREVIEW];
3276abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                mAttributes[IFD_TYPE_PREVIEW] = new HashMap<>();
327714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
327814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
327914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
328014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Check if the thumbnail image satisfies the thumbnail size requirements
328114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!isThumbnail(mAttributes[IFD_TYPE_THUMBNAIL])) {
328214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Log.d(TAG, "No image meets the size requirements of a thumbnail image.");
328314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
328414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
328514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
328614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
328714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * If image is uncompressed, ImageWidth/Length tags are used to store size info.
328814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * However, uncompressed images often store extra pixels around the edges of the final image,
328914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * which results in larger values for TAG_IMAGE_WIDTH and TAG_IMAGE_LENGTH tags.
329014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * This method corrects those tag values by checking first the values of TAG_DEFAULT_CROP_SIZE
329114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * See DNG Specification 1.4.0.0. Section 4. (DefaultCropSize)
329214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
329314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * If image is a RW2 file, valid image sizes are stored in SensorBorder tags.
329414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * See tiff_parser.cc GetFullDimension32()
329514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * */
329614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void updateImageSizeValues(ByteOrderedDataInputStream in, int imageType)
329714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throws IOException {
329814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Uncompressed image valid image size values
329914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute defaultCropSizeAttribute =
330014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[imageType].get(TAG_DEFAULT_CROP_SIZE);
330114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // RW2 image valid image size values
330214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute topBorderAttribute =
330314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_TOP_BORDER);
330414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute leftBorderAttribute =
330514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_LEFT_BORDER);
330614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute bottomBorderAttribute =
330714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_BOTTOM_BORDER);
330814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute rightBorderAttribute =
330914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[imageType].get(TAG_RW2_SENSOR_RIGHT_BORDER);
331014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
331114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (defaultCropSizeAttribute != null) {
331214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Update for uncompressed image
331314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ExifAttribute defaultCropSizeXAttribute, defaultCropSizeYAttribute;
331414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (defaultCropSizeAttribute.format == IFD_FORMAT_URATIONAL) {
331514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Rational[] defaultCropSizeValue =
331614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        (Rational[]) defaultCropSizeAttribute.getValue(mExifByteOrder);
331714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (defaultCropSizeValue == null || defaultCropSizeValue.length != 2) {
331814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.w(TAG, "Invalid crop size values. cropSize="
331914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            + Arrays.toString(defaultCropSizeValue));
332014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return;
332114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
332214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                defaultCropSizeXAttribute =
332314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        ExifAttribute.createURational(defaultCropSizeValue[0], mExifByteOrder);
332414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                defaultCropSizeYAttribute =
332514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        ExifAttribute.createURational(defaultCropSizeValue[1], mExifByteOrder);
332614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else {
332714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int[] defaultCropSizeValue =
332814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        (int[]) defaultCropSizeAttribute.getValue(mExifByteOrder);
332914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (defaultCropSizeValue == null || defaultCropSizeValue.length != 2) {
333014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    Log.w(TAG, "Invalid crop size values. cropSize="
333114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            + Arrays.toString(defaultCropSizeValue));
333214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return;
333314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
333414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                defaultCropSizeXAttribute =
333514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        ExifAttribute.createUShort(defaultCropSizeValue[0], mExifByteOrder);
333614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                defaultCropSizeYAttribute =
333714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        ExifAttribute.createUShort(defaultCropSizeValue[1], mExifByteOrder);
333814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
333914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[imageType].put(TAG_IMAGE_WIDTH, defaultCropSizeXAttribute);
334014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[imageType].put(TAG_IMAGE_LENGTH, defaultCropSizeYAttribute);
334114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else if (topBorderAttribute != null && leftBorderAttribute != null &&
334214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                bottomBorderAttribute != null && rightBorderAttribute != null) {
334314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Update for RW2 image
334414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int topBorderValue = topBorderAttribute.getIntValue(mExifByteOrder);
334514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int bottomBorderValue = bottomBorderAttribute.getIntValue(mExifByteOrder);
334614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int rightBorderValue = rightBorderAttribute.getIntValue(mExifByteOrder);
334714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int leftBorderValue = leftBorderAttribute.getIntValue(mExifByteOrder);
334814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (bottomBorderValue > topBorderValue && rightBorderValue > leftBorderValue) {
334914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int length = bottomBorderValue - topBorderValue;
335014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int width = rightBorderValue - leftBorderValue;
335114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                ExifAttribute imageLengthAttribute =
335214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        ExifAttribute.createUShort(length, mExifByteOrder);
335314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                ExifAttribute imageWidthAttribute =
335414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        ExifAttribute.createUShort(width, mExifByteOrder);
335514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mAttributes[imageType].put(TAG_IMAGE_LENGTH, imageLengthAttribute);
335614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mAttributes[imageType].put(TAG_IMAGE_WIDTH, imageWidthAttribute);
335714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
335814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else {
335914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            retrieveJpegImageSize(in, imageType);
336014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
336114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
336214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
336314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Writes an Exif segment into the given output stream.
336414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private int writeExifSegment(ByteOrderedDataOutputStream dataOutputStream,
336514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int exifOffsetFromBeginning) throws IOException {
336614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // The following variables are for calculating each IFD tag group size in bytes.
336714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int[] ifdOffsets = new int[EXIF_TAGS.length];
336814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int[] ifdDataSizes = new int[EXIF_TAGS.length];
336914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
337014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Remove IFD pointer tags (we'll re-add it later.)
337114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (ExifTag tag : EXIF_POINTER_TAGS) {
337214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            removeAttribute(tag.name);
337314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
337414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Remove old thumbnail data
337514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        removeAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name);
337614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        removeAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name);
337714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
337814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Remove null value tags.
337914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
338014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (Object obj : mAttributes[ifdType].entrySet().toArray()) {
338114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                final Map.Entry entry = (Map.Entry) obj;
338214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (entry.getValue() == null) {
338314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    mAttributes[ifdType].remove(entry.getKey());
338414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
338514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
338614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
338714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
338814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Add IFD pointer tags. The next offset of primary image TIFF IFD will have thumbnail IFD
338914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // offset when there is one or more tags in the thumbnail IFD.
339014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!mAttributes[IFD_TYPE_EXIF].isEmpty()) {
339114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[1].name,
339214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(0, mExifByteOrder));
339314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
339414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!mAttributes[IFD_TYPE_GPS].isEmpty()) {
339514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[2].name,
339614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(0, mExifByteOrder));
339714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
339814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!mAttributes[IFD_TYPE_INTEROPERABILITY].isEmpty()) {
339914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_EXIF].put(EXIF_POINTER_TAGS[3].name,
340014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(0, mExifByteOrder));
340114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
340214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (mHasThumbnail) {
340314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
340414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(0, mExifByteOrder));
340514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name,
340614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(mThumbnailLength, mExifByteOrder));
340714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
340814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
340914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Calculate IFD group data area sizes. IFD group data area is assigned to save the entry
341014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // value which has a bigger size than 4 bytes.
341114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int i = 0; i < EXIF_TAGS.length; ++i) {
341214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int sum = 0;
3413abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas            for (Map.Entry<String, ExifAttribute> entry : mAttributes[i].entrySet()) {
3414abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                final ExifAttribute exifAttribute = entry.getValue();
341514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                final int size = exifAttribute.size();
341614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (size > 4) {
341714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    sum += size;
341814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
341914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
342014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ifdDataSizes[i] += sum;
342114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
342214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
342314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Calculate IFD offsets.
342414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int position = 8;
342514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
342614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (!mAttributes[ifdType].isEmpty()) {
342714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                ifdOffsets[ifdType] = position;
342814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                position += 2 + mAttributes[ifdType].size() * 12 + 4 + ifdDataSizes[ifdType];
342914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
343014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
343114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (mHasThumbnail) {
343214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int thumbnailOffset = position;
343314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
343414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(thumbnailOffset, mExifByteOrder));
343514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset;
343614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            position += mThumbnailLength;
343714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
343814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
343914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Calculate the total size
344014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int totalSize = position + 8;  // eight bytes is for header part.
344114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (DEBUG) {
344214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Log.d(TAG, "totalSize length: " + totalSize);
344314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (int i = 0; i < EXIF_TAGS.length; ++i) {
344414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.d(TAG, String.format("index: %d, offsets: %d, tag count: %d, data sizes: %d",
344514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        i, ifdOffsets[i], mAttributes[i].size(), ifdDataSizes[i]));
344614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
344714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
344814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
344914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Update IFD pointer tags with the calculated offsets.
345014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!mAttributes[IFD_TYPE_EXIF].isEmpty()) {
345114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[1].name,
345214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(ifdOffsets[IFD_TYPE_EXIF], mExifByteOrder));
345314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
345414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!mAttributes[IFD_TYPE_GPS].isEmpty()) {
345514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_PRIMARY].put(EXIF_POINTER_TAGS[2].name,
345614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ExifAttribute.createULong(ifdOffsets[IFD_TYPE_GPS], mExifByteOrder));
345714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
345814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (!mAttributes[IFD_TYPE_INTEROPERABILITY].isEmpty()) {
345914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mAttributes[IFD_TYPE_EXIF].put(EXIF_POINTER_TAGS[3].name, ExifAttribute.createULong(
346014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    ifdOffsets[IFD_TYPE_INTEROPERABILITY], mExifByteOrder));
346114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
346214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
346314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Write TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1.
346414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataOutputStream.writeUnsignedShort(totalSize);
346514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataOutputStream.write(IDENTIFIER_EXIF_APP1);
346614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataOutputStream.writeShort(mExifByteOrder == ByteOrder.BIG_ENDIAN
346714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                ? BYTE_ALIGN_MM : BYTE_ALIGN_II);
346814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataOutputStream.setByteOrder(mExifByteOrder);
346914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataOutputStream.writeUnsignedShort(START_CODE);
347014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataOutputStream.writeUnsignedInt(IFD_OFFSET);
347114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
347214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Write IFD groups. See JEITA CP-3451C Section 4.5.8. Figure 9.
347314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
347414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (!mAttributes[ifdType].isEmpty()) {
347514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // See JEITA CP-3451C Section 4.6.2: IFD structure.
347614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Write entry count
347714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                dataOutputStream.writeUnsignedShort(mAttributes[ifdType].size());
347814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
347914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Write entry info
348014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int dataOffset = ifdOffsets[ifdType] + 2 + mAttributes[ifdType].size() * 12 + 4;
3481abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                for (Map.Entry<String, ExifAttribute> entry : mAttributes[ifdType].entrySet()) {
348214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    // Convert tag name to tag number.
3483abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                    final ExifTag tag = sExifTagMapsForWriting[ifdType].get(entry.getKey());
348414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    final int tagNumber = tag.number;
3485abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                    final ExifAttribute attribute = entry.getValue();
348614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    final int size = attribute.size();
348714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
348814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeUnsignedShort(tagNumber);
348914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeUnsignedShort(attribute.format);
349014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeInt(attribute.numberOfComponents);
349114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (size > 4) {
349214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        dataOutputStream.writeUnsignedInt(dataOffset);
349314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        dataOffset += size;
349414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    } else {
349514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        dataOutputStream.write(attribute.bytes);
349614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        // Fill zero up to 4 bytes
349714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        if (size < 4) {
349814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            for (int i = size; i < 4; ++i) {
349914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                                dataOutputStream.writeByte(0);
350014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                            }
350114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        }
350214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
350314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
350414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
350514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Write the next offset. It writes the offset of thumbnail IFD if there is one or
350614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // more tags in the thumbnail IFD when the current IFD is the primary image TIFF
350714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // IFD; Otherwise 0.
350814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (ifdType == 0 && !mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) {
350914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeUnsignedInt(ifdOffsets[IFD_TYPE_THUMBNAIL]);
351014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } else {
351114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataOutputStream.writeUnsignedInt(0);
351214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
351314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
351414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                // Write values of data field exceeding 4 bytes after the next offset.
3515abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                for (Map.Entry<String, ExifAttribute> entry : mAttributes[ifdType].entrySet()) {
3516abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                    ExifAttribute attribute = entry.getValue();
351714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
351814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (attribute.bytes.length > 4) {
351914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        dataOutputStream.write(attribute.bytes, 0, attribute.bytes.length);
352014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
352114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
352214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
352314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
352414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
352514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Write thumbnail
352614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (mHasThumbnail) {
352714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            dataOutputStream.write(getThumbnailBytes());
352814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
352914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
353014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Reset the byte order to big endian in order to write remaining parts of the JPEG file.
353114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
353214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
353314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return totalSize;
353414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
353514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
353614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
353714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Determines the data format of EXIF entry value.
353814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     *
353914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @param entryValue The value to be determined.
354014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * @return Returns two data formats gussed as a pair in integer. If there is no two candidate
354114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon               data formats for the given entry value, returns {@code -1} in the second of the pair.
354214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
354314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static Pair<Integer, Integer> guessDataFormat(String entryValue) {
354414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // See TIFF 6.0 Section 2, "Image File Directory".
354514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        // Take the first component if there are more than one component.
354614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (entryValue.contains(",")) {
354714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            String[] entryValues = entryValue.split(",");
354814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Pair<Integer, Integer> dataFormat = guessDataFormat(entryValues[0]);
354914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (dataFormat.first == IFD_FORMAT_STRING) {
355014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return dataFormat;
355114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
355214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            for (int i = 1; i < entryValues.length; ++i) {
355314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                final Pair<Integer, Integer> guessDataFormat = guessDataFormat(entryValues[i]);
355414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                int first = -1, second = -1;
355589889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon                if (guessDataFormat.first.equals(dataFormat.first)
355689889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon                        || guessDataFormat.second.equals(dataFormat.first)) {
355714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    first = dataFormat.first;
355814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
355989889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon                if (dataFormat.second != -1 && (guessDataFormat.first.equals(dataFormat.second)
356089889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon                        || guessDataFormat.second.equals(dataFormat.second))) {
356114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    second = dataFormat.second;
356214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
356314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (first == -1 && second == -1) {
356414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return new Pair<>(IFD_FORMAT_STRING, -1);
356514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
356614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (first == -1) {
356714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataFormat = new Pair<>(second, -1);
356814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    continue;
356914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
357014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                if (second == -1) {
357114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    dataFormat = new Pair<>(first, -1);
357214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    continue;
357314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
357414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
357514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return dataFormat;
357614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
357714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
357814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (entryValue.contains("/")) {
357914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            String[] rationalNumber = entryValue.split("/");
358014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (rationalNumber.length == 2) {
358114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                try {
358277966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon                    long numerator = (long) Double.parseDouble(rationalNumber[0]);
358377966fe1cfca14edf5d1d95e1decb57cff9ccd47Hyundo Moon                    long denominator = (long) Double.parseDouble(rationalNumber[1]);
358414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (numerator < 0L || denominator < 0L) {
358514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return new Pair<>(IFD_FORMAT_SRATIONAL, -1);
358614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
358714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    if (numerator > Integer.MAX_VALUE || denominator > Integer.MAX_VALUE) {
358814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        return new Pair<>(IFD_FORMAT_URATIONAL, -1);
358914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    }
359014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    return new Pair<>(IFD_FORMAT_SRATIONAL, IFD_FORMAT_URATIONAL);
359114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                } catch (NumberFormatException e)  {
359214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    // Ignored
359314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                }
359414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
359514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return new Pair<>(IFD_FORMAT_STRING, -1);
359614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
359714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        try {
359814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Long longValue = Long.parseLong(entryValue);
359914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (longValue >= 0 && longValue <= 65535) {
360014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return new Pair<>(IFD_FORMAT_USHORT, IFD_FORMAT_ULONG);
360114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
360214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (longValue < 0) {
360314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return new Pair<>(IFD_FORMAT_SLONG, -1);
360414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
360514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return new Pair<>(IFD_FORMAT_ULONG, -1);
360614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } catch (NumberFormatException e) {
360714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Ignored
360814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
360914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        try {
361014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Double.parseDouble(entryValue);
361114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return new Pair<>(IFD_FORMAT_DOUBLE, -1);
361214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } catch (NumberFormatException e) {
361314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            // Ignored
361414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
361514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return new Pair<>(IFD_FORMAT_STRING, -1);
361614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
361714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
361814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // An input stream to parse EXIF data area, which can be written in either little or big endian
361914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // order.
362014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static class ByteOrderedDataInputStream extends InputStream implements DataInput {
362114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN;
362214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN;
362314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
362414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private DataInputStream mDataInputStream;
362514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
362614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private final int mLength;
362714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private int mPosition;
362814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
362914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public ByteOrderedDataInputStream(InputStream in) throws IOException {
363014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mDataInputStream = new DataInputStream(in);
363114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mLength = mDataInputStream.available();
363214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mPosition = 0;
363314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mDataInputStream.mark(mLength);
363414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
363514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
363614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public ByteOrderedDataInputStream(byte[] bytes) throws IOException {
363714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            this(new ByteArrayInputStream(bytes));
363814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
363914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
364014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void setByteOrder(ByteOrder byteOrder) {
364114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mByteOrder = byteOrder;
364214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
364314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
364414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void seek(long byteCount) throws IOException {
364514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mPosition > byteCount) {
364614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mPosition = 0;
364714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mDataInputStream.reset();
364814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mDataInputStream.mark(mLength);
364914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else {
365014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                byteCount -= mPosition;
365114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
365214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
365314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (skipBytes((int) byteCount) != (int) byteCount) {
365414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Couldn't seek up to the byteCount");
365514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
365614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
365714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
365814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public int peek() {
365914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return mPosition;
366014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
366114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
366214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
366314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public int available() throws IOException {
366414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return mDataInputStream.available();
366514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
366614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
366714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
366814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public int read() throws IOException {
366914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ++mPosition;
367014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return mDataInputStream.read();
367114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
367214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
367314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
367489889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon        public int read(byte[] b, int off, int len) throws IOException {
367589889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon            int bytesRead = mDataInputStream.read(b, off, len);
367689889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon            mPosition += bytesRead;
367789889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon            return bytesRead;
367889889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon        }
367989889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon
368089889c49482aed4e9dec66b33f733065e3e1580cHyundo Moon        @Override
368114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public int readUnsignedByte() throws IOException {
368214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ++mPosition;
368314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return mDataInputStream.readUnsignedByte();
368414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
368514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
368614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
368714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public String readLine() throws IOException {
368814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            Log.d(TAG, "Currently unsupported");
368914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return null;
369014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
369114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
369214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
369314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public boolean readBoolean() throws IOException {
369414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ++mPosition;
369514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return mDataInputStream.readBoolean();
369614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
369714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
369814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
369914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public char readChar() throws IOException {
370014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mPosition += 2;
370114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return mDataInputStream.readChar();
370214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
370314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
370414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
370514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public String readUTF() throws IOException {
370614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mPosition += 2;
370714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return mDataInputStream.readUTF();
370814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
370914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
371014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
371114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void readFully(byte[] buffer, int offset, int length) throws IOException {
371214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mPosition += length;
371314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mPosition > mLength) {
371414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
371514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
371614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mDataInputStream.read(buffer, offset, length) != length) {
371714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Couldn't read up to the length of buffer");
371814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
371914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
372014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
372114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
372214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void readFully(byte[] buffer) throws IOException {
372314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mPosition += buffer.length;
372414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mPosition > mLength) {
372514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
372614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
372714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mDataInputStream.read(buffer, 0, buffer.length) != buffer.length) {
372814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new IOException("Couldn't read up to the length of buffer");
372914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
373014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
373114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
373214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
373314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public byte readByte() throws IOException {
373414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            ++mPosition;
373514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mPosition > mLength) {
373614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
373714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
373814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch = mDataInputStream.read();
373914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (ch < 0) {
374014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
374114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
374214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return (byte) ch;
374314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
374414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
374514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
374614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public short readShort() throws IOException {
374714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mPosition += 2;
374814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mPosition > mLength) {
374914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
375014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
375114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch1 = mDataInputStream.read();
375214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch2 = mDataInputStream.read();
375314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if ((ch1 | ch2) < 0) {
375414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
375514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
375614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mByteOrder == LITTLE_ENDIAN) {
375714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return (short) ((ch2 << 8) + (ch1));
375814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else if (mByteOrder == BIG_ENDIAN) {
375914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return (short) ((ch1 << 8) + (ch2));
376014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
376114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("Invalid byte order: " + mByteOrder);
376214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
376314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
376414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
376514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public int readInt() throws IOException {
376614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mPosition += 4;
376714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mPosition > mLength) {
376814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
376914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
377014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch1 = mDataInputStream.read();
377114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch2 = mDataInputStream.read();
377214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch3 = mDataInputStream.read();
377314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch4 = mDataInputStream.read();
377414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if ((ch1 | ch2 | ch3 | ch4) < 0) {
377514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
377614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
377714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mByteOrder == LITTLE_ENDIAN) {
377814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + ch1);
377914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else if (mByteOrder == BIG_ENDIAN) {
378014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
378114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
378214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("Invalid byte order: " + mByteOrder);
378314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
378414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
378514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
378614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public int skipBytes(int byteCount) throws IOException {
378714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int totalSkip = Math.min(byteCount, mLength - mPosition);
378814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int skipped = 0;
378914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            while (skipped < totalSkip) {
379014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                skipped += mDataInputStream.skipBytes(totalSkip - skipped);
379114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
379214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mPosition += skipped;
379314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return skipped;
379414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
379514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
3796e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas        @Override
379714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public int readUnsignedShort() throws IOException {
379814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mPosition += 2;
379914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mPosition > mLength) {
380014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
380114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
380214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch1 = mDataInputStream.read();
380314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch2 = mDataInputStream.read();
380414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if ((ch1 | ch2) < 0) {
380514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
380614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
380714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mByteOrder == LITTLE_ENDIAN) {
380814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return ((ch2 << 8) + (ch1));
380914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else if (mByteOrder == BIG_ENDIAN) {
381014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return ((ch1 << 8) + (ch2));
381114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
381214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("Invalid byte order: " + mByteOrder);
381314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
381414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
381514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public long readUnsignedInt() throws IOException {
381614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return readInt() & 0xffffffffL;
381714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
381814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
381914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
382014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public long readLong() throws IOException {
382114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mPosition += 8;
382214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mPosition > mLength) {
382314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
382414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
382514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch1 = mDataInputStream.read();
382614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch2 = mDataInputStream.read();
382714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch3 = mDataInputStream.read();
382814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch4 = mDataInputStream.read();
382914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch5 = mDataInputStream.read();
383014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch6 = mDataInputStream.read();
383114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch7 = mDataInputStream.read();
383214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int ch8 = mDataInputStream.read();
383314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) {
383414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw new EOFException();
383514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
383614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mByteOrder == LITTLE_ENDIAN) {
383714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return (((long) ch8 << 56) + ((long) ch7 << 48) + ((long) ch6 << 40)
383814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + ((long) ch5 << 32) + ((long) ch4 << 24) + ((long) ch3 << 16)
383914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + ((long) ch2 << 8) + (long) ch1);
384014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else if (mByteOrder == BIG_ENDIAN) {
384114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                return (((long) ch1 << 56) + ((long) ch2 << 48) + ((long) ch3 << 40)
384214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + ((long) ch4 << 32) + ((long) ch5 << 24) + ((long) ch6 << 16)
384314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                        + ((long) ch7 << 8) + (long) ch8);
384414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
384514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throw new IOException("Invalid byte order: " + mByteOrder);
384614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
384714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
384814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
384914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public float readFloat() throws IOException {
385014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return Float.intBitsToFloat(readInt());
385114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
385214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
385314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        @Override
385414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public double readDouble() throws IOException {
385514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return Double.longBitsToDouble(readLong());
385614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
385714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
385814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
385914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // An output stream to write EXIF data area, which can be written in either little or big endian
386014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // order.
386114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static class ByteOrderedDataOutputStream extends FilterOutputStream {
386214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private final OutputStream mOutputStream;
386314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        private ByteOrder mByteOrder;
386414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
386514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public ByteOrderedDataOutputStream(OutputStream out, ByteOrder byteOrder) {
386614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            super(out);
386714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mOutputStream = out;
386814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mByteOrder = byteOrder;
386914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
387014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
387114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void setByteOrder(ByteOrder byteOrder) {
387214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mByteOrder = byteOrder;
387314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
387414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
3875e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas        @Override
387614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void write(byte[] bytes) throws IOException {
387714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mOutputStream.write(bytes);
387814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
387914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
3880e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas        @Override
388114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void write(byte[] bytes, int offset, int length) throws IOException {
388214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mOutputStream.write(bytes, offset, length);
388314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
388414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
388514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void writeByte(int val) throws IOException {
388614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            mOutputStream.write(val);
388714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
388814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
388914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void writeShort(short val) throws IOException {
389014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mByteOrder == ByteOrder.LITTLE_ENDIAN) {
389114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 0) & 0xFF);
389214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 8) & 0xFF);
389314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else if (mByteOrder == ByteOrder.BIG_ENDIAN) {
389414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 8) & 0xFF);
389514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 0) & 0xFF);
389614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
389714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
389814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
389914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void writeInt(int val) throws IOException {
390014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (mByteOrder == ByteOrder.LITTLE_ENDIAN) {
390114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 0) & 0xFF);
390214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 8) & 0xFF);
390314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 16) & 0xFF);
390414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 24) & 0xFF);
390514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } else if (mByteOrder == ByteOrder.BIG_ENDIAN) {
390614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 24) & 0xFF);
390714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 16) & 0xFF);
390814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 8) & 0xFF);
390914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mOutputStream.write((val >>> 0) & 0xFF);
391014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
391114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
391214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
391314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void writeUnsignedShort(int val) throws IOException {
391414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            writeShort((short) val);
391514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
391614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
391714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        public void writeUnsignedInt(long val) throws IOException {
391814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            writeInt((int) val);
391914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
392014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
392114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
392214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    // Swaps image data based on image size
392314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private void swapBasedOnImageSize(@IfdType int firstIfdType, @IfdType int secondIfdType)
392414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            throws IOException {
392514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (mAttributes[firstIfdType].isEmpty() || mAttributes[secondIfdType].isEmpty()) {
392614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (DEBUG) {
392714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.d(TAG, "Cannot perform swap since only one image data exists");
392814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
392914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            return;
393014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
393114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
393214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute firstImageLengthAttribute =
393314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[firstIfdType].get(TAG_IMAGE_LENGTH);
393414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute firstImageWidthAttribute =
393514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[firstIfdType].get(TAG_IMAGE_WIDTH);
393614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute secondImageLengthAttribute =
393714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[secondIfdType].get(TAG_IMAGE_LENGTH);
393814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        ExifAttribute secondImageWidthAttribute =
393914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                (ExifAttribute) mAttributes[secondIfdType].get(TAG_IMAGE_WIDTH);
394014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
394114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (firstImageLengthAttribute == null || firstImageWidthAttribute == null) {
394214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (DEBUG) {
394314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.d(TAG, "First image does not contain valid size information");
394414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
394514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else if (secondImageLengthAttribute == null || secondImageWidthAttribute == null) {
394614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (DEBUG) {
394714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                Log.d(TAG, "Second image does not contain valid size information");
394814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
394914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        } else {
395014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int firstImageLengthValue = firstImageLengthAttribute.getIntValue(mExifByteOrder);
395114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int firstImageWidthValue = firstImageWidthAttribute.getIntValue(mExifByteOrder);
395214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int secondImageLengthValue = secondImageLengthAttribute.getIntValue(mExifByteOrder);
395314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            int secondImageWidthValue = secondImageWidthAttribute.getIntValue(mExifByteOrder);
395414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
395514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            if (firstImageLengthValue < secondImageLengthValue &&
395614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                    firstImageWidthValue < secondImageWidthValue) {
3957abc73958d264e1eed7fd401a18be1d9ede8304ebAurimas Liutikas                HashMap<String, ExifAttribute> tempMap = mAttributes[firstIfdType];
395814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mAttributes[firstIfdType] = mAttributes[secondIfdType];
395914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                mAttributes[secondIfdType] = tempMap;
396014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
396114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
396214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
396314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
396414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
396514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null.
396614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
396714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static void closeQuietly(Closeable closeable) {
396814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        if (closeable != null) {
396914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            try {
397014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                closeable.close();
397114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } catch (RuntimeException rethrown) {
397214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon                throw rethrown;
397314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            } catch (Exception ignored) {
397414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            }
397514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
397614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
397714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon
397814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    /**
397914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Copies all of the bytes from {@code in} to {@code out}. Neither stream is closed.
398014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     * Returns the total number of bytes transferred.
398114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon     */
398214ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    private static int copy(InputStream in, OutputStream out) throws IOException {
398314ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int total = 0;
398414ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        byte[] buffer = new byte[8192];
398514ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        int c;
398614ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        while ((c = in.read(buffer)) != -1) {
398714ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            total += c;
398814ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon            out.write(buffer, 0, c);
398914ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        }
399014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon        return total;
399114ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon    }
3992f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon
3993f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon    /**
3994f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon     * Convert given int[] to long[]. If long[] is given, just return it.
3995f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon     * Return null for other types of input.
3996f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon     */
3997f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon    private static long[] convertToLongArray(Object inputObj) {
3998f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon        if (inputObj instanceof int[]) {
3999f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon            int[] input = (int[]) inputObj;
4000f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon            long[] result = new long[input.length];
4001f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon            for (int i = 0; i < input.length; i++) {
4002f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon                result[i] = input[i];
4003f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon            }
4004f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon            return result;
4005f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon        } else if (inputObj instanceof long[]) {
4006f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon            return (long[]) inputObj;
4007f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon        }
4008f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon        return null;
4009f96abe0f8ae38bbb9810d2205e050ebe4ef613a1Hyundo Moon    }
401014ea3100458369949fffba9978db2a51dde21bf2Hyundo Moon}
4011