1e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor/*
2e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * Copyright (C) 2012 The Android Open Source Project
3e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor *
4e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * Licensed under the Apache License, Version 2.0 (the "License");
5e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * you may not use this file except in compliance with the License.
6e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * You may obtain a copy of the License at
7e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor *
8e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor *      http://www.apache.org/licenses/LICENSE-2.0
9e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor *
10e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * Unless required by applicable law or agreed to in writing, software
11e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * distributed under the License is distributed on an "AS IS" BASIS,
12e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * See the License for the specific language governing permissions and
14e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * limitations under the License.
15e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor */
16e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
17e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylorpackage com.android.mms.exif;
18e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
19e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylorimport android.util.Log;
20e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
21e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylorimport java.io.UnsupportedEncodingException;
22e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylorimport java.nio.ByteOrder;
23e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylorimport java.util.ArrayList;
24e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylorimport java.util.Arrays;
25e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylorimport java.util.List;
26e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
27e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor/**
28e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * This class stores the EXIF header in IFDs according to the JPEG
29e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * specification. It is the result produced by {@link ExifReader}.
30e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor *
31e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * @see ExifReader
32e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor * @see IfdData
33e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor */
34e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylorclass ExifData {
35e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    private static final String TAG = "ExifData";
36e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    private static final byte[] USER_COMMENT_ASCII = {
37e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00
38e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    };
39e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    private static final byte[] USER_COMMENT_JIS = {
40e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00
41e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    };
42e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    private static final byte[] USER_COMMENT_UNICODE = {
43e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00
44e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    };
45e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
46e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    private final IfdData[] mIfdDatas = new IfdData[IfdId.TYPE_IFD_COUNT];
47e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    private byte[] mThumbnail;
48e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    private final ArrayList<byte[]> mStripBytes = new ArrayList<byte[]>();
49e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    private final ByteOrder mByteOrder;
50e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
51e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    ExifData(ByteOrder order) {
52e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        mByteOrder = order;
53e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
54e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
55e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
56e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Gets the compressed thumbnail. Returns null if there is no compressed
57e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * thumbnail.
58e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     *
59e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * @see #hasCompressedThumbnail()
60e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
61e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected byte[] getCompressedThumbnail() {
62e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return mThumbnail;
63e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
64e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
65e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
66e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Sets the compressed thumbnail.
67e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
68e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected void setCompressedThumbnail(byte[] thumbnail) {
69e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        mThumbnail = thumbnail;
70e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
71e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
72e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
73e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Returns true it this header contains a compressed thumbnail.
74e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
75e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected boolean hasCompressedThumbnail() {
76e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return mThumbnail != null;
77e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
78e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
79e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
80e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Adds an uncompressed strip.
81e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
82e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected void setStripBytes(int index, byte[] strip) {
83e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (index < mStripBytes.size()) {
84e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            mStripBytes.set(index, strip);
85e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        } else {
86e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            for (int i = mStripBytes.size(); i < index; i++) {
87e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                mStripBytes.add(null);
88e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            }
89e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            mStripBytes.add(strip);
90e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
91e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
92e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
93e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
94e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Gets the strip count.
95e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
96e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected int getStripCount() {
97e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return mStripBytes.size();
98e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
99e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
100e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
101e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Gets the strip at the specified index.
102e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     *
103e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * @exceptions #IndexOutOfBoundException
104e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
105e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected byte[] getStrip(int index) {
106e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return mStripBytes.get(index);
107e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
108e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
109e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
110e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Returns true if this header contains uncompressed strip.
111e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
112e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected boolean hasUncompressedStrip() {
113e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return mStripBytes.size() != 0;
114e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
115e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
116e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
117e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Gets the byte order.
118e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
119e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected ByteOrder getByteOrder() {
120e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return mByteOrder;
121e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
122e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
123e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
124e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Returns the {@link IfdData} object corresponding to a given IFD if it
125e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * exists or null.
126e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
127e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected IfdData getIfdData(int ifdId) {
128e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (ExifTag.isValidIfd(ifdId)) {
129e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return mIfdDatas[ifdId];
130e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
131e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return null;
132e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
133e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
134e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
135e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Adds IFD data. If IFD data of the same type already exists, it will be
136e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * replaced by the new data.
137e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
138e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected void addIfdData(IfdData data) {
139e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        mIfdDatas[data.getId()] = data;
140e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
141e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
142e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
143e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Returns the {@link IfdData} object corresponding to a given IFD or
144e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * generates one if none exist.
145e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
146e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected IfdData getOrCreateIfdData(int ifdId) {
147e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        IfdData ifdData = mIfdDatas[ifdId];
148e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (ifdData == null) {
149e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            ifdData = new IfdData(ifdId);
150e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            mIfdDatas[ifdId] = ifdData;
151e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
152e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return ifdData;
153e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
154e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
155e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
156e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Returns the tag with a given TID in the given IFD if the tag exists.
157e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Otherwise returns null.
158e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
159e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected ExifTag getTag(short tag, int ifd) {
160e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        IfdData ifdData = mIfdDatas[ifd];
161e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return (ifdData == null) ? null : ifdData.getTag(tag);
162e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
163e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
164e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
165e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Adds the given ExifTag to its default IFD and returns an existing ExifTag
166e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * with the same TID or null if none exist.
167e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
168e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected ExifTag addTag(ExifTag tag) {
169e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (tag != null) {
170e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            int ifd = tag.getIfd();
171e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return addTag(tag, ifd);
172e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
173e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return null;
174e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
175e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
176e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
177e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Adds the given ExifTag to the given IFD and returns an existing ExifTag
178e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * with the same TID or null if none exist.
179e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
180e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected ExifTag addTag(ExifTag tag, int ifdId) {
181e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (tag != null && ExifTag.isValidIfd(ifdId)) {
182e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            IfdData ifdData = getOrCreateIfdData(ifdId);
183e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return ifdData.setTag(tag);
184e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
185e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return null;
186e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
187e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
188e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected void clearThumbnailAndStrips() {
189e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        mThumbnail = null;
190e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        mStripBytes.clear();
191e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
192e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
193e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
194e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Removes the thumbnail and its related tags. IFD1 will be removed.
195e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
196e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected void removeThumbnailData() {
197e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        clearThumbnailAndStrips();
198e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        mIfdDatas[IfdId.TYPE_IFD_1] = null;
199e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
200e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
201e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
202e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Removes the tag with a given TID and IFD.
203e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
204e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected void removeTag(short tagId, int ifdId) {
205e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        IfdData ifdData = mIfdDatas[ifdId];
206e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (ifdData == null) {
207e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return;
208e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
209e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        ifdData.removeTag(tagId);
210e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
211e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
212e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
213e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Decodes the user comment tag into string as specified in the EXIF
214e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * standard. Returns null if decoding failed.
215e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
216e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected String getUserComment() {
217e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        IfdData ifdData = mIfdDatas[IfdId.TYPE_IFD_0];
218e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (ifdData == null) {
219e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return null;
220e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
221e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        ExifTag tag = ifdData.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_USER_COMMENT));
222e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (tag == null) {
223e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return null;
224e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
225e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (tag.getComponentCount() < 8) {
226e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return null;
227e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
228e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
229e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        byte[] buf = new byte[tag.getComponentCount()];
230e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        tag.getBytes(buf);
231e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
232e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        byte[] code = new byte[8];
233e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        System.arraycopy(buf, 0, code, 0, 8);
234e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
235e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        try {
236e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            if (Arrays.equals(code, USER_COMMENT_ASCII)) {
237e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                return new String(buf, 8, buf.length - 8, "US-ASCII");
238e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            } else if (Arrays.equals(code, USER_COMMENT_JIS)) {
239e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                return new String(buf, 8, buf.length - 8, "EUC-JP");
240e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            } else if (Arrays.equals(code, USER_COMMENT_UNICODE)) {
241e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                return new String(buf, 8, buf.length - 8, "UTF-16");
242e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            } else {
243e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                return null;
244e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            }
245e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        } catch (UnsupportedEncodingException e) {
246e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            Log.w(TAG, "Failed to decode the user comment");
247e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return null;
248e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
249e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
250e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
251e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
252e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Returns a list of all {@link ExifTag}s in the ExifData or null if there
253e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * are none.
254e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
255e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected List<ExifTag> getAllTags() {
256e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
257e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        for (IfdData d : mIfdDatas) {
258e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            if (d != null) {
259e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                ExifTag[] tags = d.getAllTags();
260e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                if (tags != null) {
261e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                    for (ExifTag t : tags) {
262e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                        ret.add(t);
263e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                    }
264e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                }
265e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            }
266e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
267e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (ret.size() == 0) {
268e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return null;
269e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
270e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return ret;
271e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
272e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
273e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
274e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Returns a list of all {@link ExifTag}s in a given IFD or null if there
275e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * are none.
276e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
277e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected List<ExifTag> getAllTagsForIfd(int ifd) {
278e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        IfdData d = mIfdDatas[ifd];
279e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (d == null) {
280e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return null;
281e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
282e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        ExifTag[] tags = d.getAllTags();
283e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (tags == null) {
284e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return null;
285e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
286e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        ArrayList<ExifTag> ret = new ArrayList<ExifTag>(tags.length);
287e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        for (ExifTag t : tags) {
288e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            ret.add(t);
289e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
290e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (ret.size() == 0) {
291e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return null;
292e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
293e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return ret;
294e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
295e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
296e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    /**
297e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * Returns a list of all {@link ExifTag}s with a given TID or null if there
298e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     * are none.
299e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor     */
300e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    protected List<ExifTag> getAllTagsForTagId(short tag) {
301e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
302e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        for (IfdData d : mIfdDatas) {
303e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            if (d != null) {
304e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                ExifTag t = d.getTag(tag);
305e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                if (t != null) {
306e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                    ret.add(t);
307e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                }
308e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            }
309e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
310e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (ret.size() == 0) {
311e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return null;
312e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
313e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return ret;
314e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
315e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
316e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    @Override
317e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    public boolean equals(Object obj) {
318e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (this == obj) {
319e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return true;
320e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
321e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (obj == null) {
322e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return false;
323e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
324e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        if (obj instanceof ExifData) {
325e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            ExifData data = (ExifData) obj;
326e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            if (data.mByteOrder != mByteOrder ||
327e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                    data.mStripBytes.size() != mStripBytes.size() ||
328e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                    !Arrays.equals(data.mThumbnail, mThumbnail)) {
329e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                return false;
330e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            }
331e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            for (int i = 0; i < mStripBytes.size(); i++) {
332e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                if (!Arrays.equals(data.mStripBytes.get(i), mStripBytes.get(i))) {
333e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                    return false;
334e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                }
335e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            }
336e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
337e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                IfdData ifd1 = data.getIfdData(i);
338e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                IfdData ifd2 = getIfdData(i);
339e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                if (ifd1 != ifd2 && ifd1 != null && !ifd1.equals(ifd2)) {
340e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                    return false;
341e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor                }
342e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            }
343e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor            return true;
344e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        }
345e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor        return false;
346e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor    }
347e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor
348e8a0d786fba1960818cb3da938cdbf2b2b11b340Tom Taylor}
349