1321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou/*
2321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou * Copyright (C) 2012 The Android Open Source Project
3321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou *
4321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou * Licensed under the Apache License, Version 2.0 (the "License");
5321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou * you may not use this file except in compliance with the License.
6321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou * You may obtain a copy of the License at
7321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou *
8321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou *      http://www.apache.org/licenses/LICENSE-2.0
9321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou *
10321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou * Unless required by applicable law or agreed to in writing, software
11321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou * distributed under the License is distributed on an "AS IS" BASIS,
12321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou * See the License for the specific language governing permissions and
14321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou * limitations under the License.
15321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou */
16321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou
17321e7c477a66df696b92d1617a33f6bafab7886dEarl Oupackage com.android.gallery3d.exif;
18d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou
1915438682a38ad2887426c100452a990b5e3f965dEarl Ouimport android.util.Log;
2015438682a38ad2887426c100452a990b5e3f965dEarl Ou
2115438682a38ad2887426c100452a990b5e3f965dEarl Ouimport java.io.UnsupportedEncodingException;
227973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ouimport java.nio.ByteOrder;
23d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ouimport java.util.ArrayList;
24cde6ac521216801e835df1c20b68dd21d4fd04a4Earl Ouimport java.util.Arrays;
256e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunkimport java.util.List;
26d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou
274ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou/**
286e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk * This class stores the EXIF header in IFDs according to the JPEG
296e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk * specification. It is the result produced by {@link ExifReader}.
306e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk *
316e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk * @see ExifReader
326e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk * @see IfdData
334ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou */
346e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunkclass ExifData {
3515438682a38ad2887426c100452a990b5e3f965dEarl Ou    private static final String TAG = "ExifData";
3615438682a38ad2887426c100452a990b5e3f965dEarl Ou    private static final byte[] USER_COMMENT_ASCII = {
376e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00
386e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    };
3915438682a38ad2887426c100452a990b5e3f965dEarl Ou    private static final byte[] USER_COMMENT_JIS = {
406e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00
416e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    };
4215438682a38ad2887426c100452a990b5e3f965dEarl Ou    private static final byte[] USER_COMMENT_UNICODE = {
436e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00
446e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    };
456c687a5fe5c5bad1c7c6aabceb7aec42eaed218aEarl Ou
464ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private final IfdData[] mIfdDatas = new IfdData[IfdId.TYPE_IFD_COUNT];
47d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    private byte[] mThumbnail;
48d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    private ArrayList<byte[]> mStripBytes = new ArrayList<byte[]>();
497973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou    private final ByteOrder mByteOrder;
507973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou
516e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    ExifData(ByteOrder order) {
527973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou        mByteOrder = order;
53321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou    }
54321e7c477a66df696b92d1617a33f6bafab7886dEarl Ou
554ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
566e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Gets the compressed thumbnail. Returns null if there is no compressed
576e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * thumbnail.
58d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     *
59d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     * @see #hasCompressedThumbnail()
60d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     */
616e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected byte[] getCompressedThumbnail() {
62d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou        return mThumbnail;
63d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    }
64d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou
65d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    /**
66d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     * Sets the compressed thumbnail.
67d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     */
686e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected void setCompressedThumbnail(byte[] thumbnail) {
69d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou        mThumbnail = thumbnail;
70d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    }
71d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou
72d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    /**
73d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     * Returns true it this header contains a compressed thumbnail.
74d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     */
756e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected boolean hasCompressedThumbnail() {
76d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou        return mThumbnail != null;
77d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    }
78d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou
79d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    /**
80d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     * Adds an uncompressed strip.
81d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     */
826e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected void setStripBytes(int index, byte[] strip) {
83d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou        if (index < mStripBytes.size()) {
84d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou            mStripBytes.set(index, strip);
85d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou        } else {
86d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou            for (int i = mStripBytes.size(); i < index; i++) {
87d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou                mStripBytes.add(null);
88d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou            }
89d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou            mStripBytes.add(strip);
90d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou        }
91d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    }
92d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou
93d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    /**
94e48c0f96ee3f9654c3538664dd59485927fb44d6Earl Ou     * Gets the strip count.
95d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     */
966e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int getStripCount() {
97d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou        return mStripBytes.size();
98d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    }
99d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou
100d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    /**
101d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     * Gets the strip at the specified index.
1026e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     *
103d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     * @exceptions #IndexOutOfBoundException
104d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou     */
1056e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected byte[] getStrip(int index) {
106d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou        return mStripBytes.get(index);
107d83a3749f50a8b493a12dfc96aaa0da2f9a6d08bEarl Ou    }
1087973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou
1097973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou    /**
1106e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Returns true if this header contains uncompressed strip.
1117973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou     */
1126e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected boolean hasUncompressedStrip() {
1136e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return mStripBytes.size() != 0;
1147973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou    }
115cde6ac521216801e835df1c20b68dd21d4fd04a4Earl Ou
1164f529e7cada294befb66a1fc9b72b1aa164597dfEarl Ou    /**
1176e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Gets the byte order.
1184f529e7cada294befb66a1fc9b72b1aa164597dfEarl Ou     */
1196e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected ByteOrder getByteOrder() {
1206e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return mByteOrder;
121cde6ac521216801e835df1c20b68dd21d4fd04a4Earl Ou    }
1223b8bd33be5041d77855f756fbba1993294cffac4Earl Ou
12389591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
1246e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Returns the {@link IfdData} object corresponding to a given IFD if it
1256e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * exists or null.
12689591324c5d1097e59217177ad3ea74598867584Earl Ou     */
1276e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected IfdData getIfdData(int ifdId) {
1286e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (ExifTag.isValidIfd(ifdId)) {
1296e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return mIfdDatas[ifdId];
1303b8bd33be5041d77855f756fbba1993294cffac4Earl Ou        }
1316e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return null;
1323b8bd33be5041d77855f756fbba1993294cffac4Earl Ou    }
1333b8bd33be5041d77855f756fbba1993294cffac4Earl Ou
1346c687a5fe5c5bad1c7c6aabceb7aec42eaed218aEarl Ou    /**
1356e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Adds IFD data. If IFD data of the same type already exists, it will be
1366e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * replaced by the new data.
1376c687a5fe5c5bad1c7c6aabceb7aec42eaed218aEarl Ou     */
1386e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected void addIfdData(IfdData data) {
1396e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        mIfdDatas[data.getId()] = data;
1406c687a5fe5c5bad1c7c6aabceb7aec42eaed218aEarl Ou    }
1416c687a5fe5c5bad1c7c6aabceb7aec42eaed218aEarl Ou
1426c687a5fe5c5bad1c7c6aabceb7aec42eaed218aEarl Ou    /**
1436e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Returns the {@link IfdData} object corresponding to a given IFD or
1446e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * generates one if none exist.
1456c687a5fe5c5bad1c7c6aabceb7aec42eaed218aEarl Ou     */
1466e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected IfdData getOrCreateIfdData(int ifdId) {
14789591324c5d1097e59217177ad3ea74598867584Earl Ou        IfdData ifdData = mIfdDatas[ifdId];
14889591324c5d1097e59217177ad3ea74598867584Earl Ou        if (ifdData == null) {
14989591324c5d1097e59217177ad3ea74598867584Earl Ou            ifdData = new IfdData(ifdId);
15089591324c5d1097e59217177ad3ea74598867584Earl Ou            mIfdDatas[ifdId] = ifdData;
15189591324c5d1097e59217177ad3ea74598867584Earl Ou        }
15289591324c5d1097e59217177ad3ea74598867584Earl Ou        return ifdData;
15389591324c5d1097e59217177ad3ea74598867584Earl Ou    }
15489591324c5d1097e59217177ad3ea74598867584Earl Ou
15589591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
1566e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Returns the tag with a given TID in the given IFD if the tag exists.
1576e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Otherwise returns null.
15889591324c5d1097e59217177ad3ea74598867584Earl Ou     */
1596e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected ExifTag getTag(short tag, int ifd) {
1606e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        IfdData ifdData = mIfdDatas[ifd];
1616e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return (ifdData == null) ? null : ifdData.getTag(tag);
16289591324c5d1097e59217177ad3ea74598867584Earl Ou    }
16389591324c5d1097e59217177ad3ea74598867584Earl Ou
16489591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
1656e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Adds the given ExifTag to its default IFD and returns an existing ExifTag
1666e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * with the same TID or null if none exist.
16789591324c5d1097e59217177ad3ea74598867584Earl Ou     */
1686e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected ExifTag addTag(ExifTag tag) {
1696e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (tag != null) {
1706e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            int ifd = tag.getIfd();
1716e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return addTag(tag, ifd);
1726e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
1736e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return null;
17489591324c5d1097e59217177ad3ea74598867584Earl Ou    }
17589591324c5d1097e59217177ad3ea74598867584Earl Ou
17689591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
1776e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Adds the given ExifTag to the given IFD and returns an existing ExifTag
1786e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * with the same TID or null if none exist.
179b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou     */
1806e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected ExifTag addTag(ExifTag tag, int ifdId) {
1816e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (tag != null && ExifTag.isValidIfd(ifdId)) {
1826e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            IfdData ifdData = getOrCreateIfdData(ifdId);
1836e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return ifdData.setTag(tag);
1846e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
1856e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return null;
186b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou    }
187b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou
1886e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected void clearThumbnailAndStrips() {
1896e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        mThumbnail = null;
1906e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        mStripBytes.clear();
19189591324c5d1097e59217177ad3ea74598867584Earl Ou    }
19289591324c5d1097e59217177ad3ea74598867584Earl Ou
19389591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
1946e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Removes the thumbnail and its related tags. IFD1 will be removed.
19589591324c5d1097e59217177ad3ea74598867584Earl Ou     */
1966e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected void removeThumbnailData() {
1976e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        clearThumbnailAndStrips();
1986e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        mIfdDatas[IfdId.TYPE_IFD_1] = null;
19989591324c5d1097e59217177ad3ea74598867584Earl Ou    }
200133c49e9bda0b3dcc005a0dfc7ab999926c0ef7fEarl Ou
20107ddc8ecc8a2bcc3f16bdfb712454a91726726feEarl Ou    /**
2026e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Removes the tag with a given TID and IFD.
20307ddc8ecc8a2bcc3f16bdfb712454a91726726feEarl Ou     */
2046e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected void removeTag(short tagId, int ifdId) {
2056e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        IfdData ifdData = mIfdDatas[ifdId];
2066e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (ifdData == null) {
2076e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return;
2086e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2096e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        ifdData.removeTag(tagId);
210133c49e9bda0b3dcc005a0dfc7ab999926c0ef7fEarl Ou    }
21115438682a38ad2887426c100452a990b5e3f965dEarl Ou
21215438682a38ad2887426c100452a990b5e3f965dEarl Ou    /**
2136e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Decodes the user comment tag into string as specified in the EXIF
2146e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * standard. Returns null if decoding failed.
21515438682a38ad2887426c100452a990b5e3f965dEarl Ou     */
2166e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected String getUserComment() {
21715438682a38ad2887426c100452a990b5e3f965dEarl Ou        IfdData ifdData = mIfdDatas[IfdId.TYPE_IFD_0];
2186e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (ifdData == null) {
2196e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return null;
2206e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2216e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        ExifTag tag = ifdData.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_USER_COMMENT));
2226e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (tag == null) {
2236e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return null;
2246e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2256e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (tag.getComponentCount() < 8) {
2266e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return null;
2276e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
22815438682a38ad2887426c100452a990b5e3f965dEarl Ou
22915438682a38ad2887426c100452a990b5e3f965dEarl Ou        byte[] buf = new byte[tag.getComponentCount()];
23015438682a38ad2887426c100452a990b5e3f965dEarl Ou        tag.getBytes(buf);
23115438682a38ad2887426c100452a990b5e3f965dEarl Ou
23215438682a38ad2887426c100452a990b5e3f965dEarl Ou        byte[] code = new byte[8];
23315438682a38ad2887426c100452a990b5e3f965dEarl Ou        System.arraycopy(buf, 0, code, 0, 8);
23415438682a38ad2887426c100452a990b5e3f965dEarl Ou
23515438682a38ad2887426c100452a990b5e3f965dEarl Ou        try {
23615438682a38ad2887426c100452a990b5e3f965dEarl Ou            if (Arrays.equals(code, USER_COMMENT_ASCII)) {
23715438682a38ad2887426c100452a990b5e3f965dEarl Ou                return new String(buf, 8, buf.length - 8, "US-ASCII");
23815438682a38ad2887426c100452a990b5e3f965dEarl Ou            } else if (Arrays.equals(code, USER_COMMENT_JIS)) {
23915438682a38ad2887426c100452a990b5e3f965dEarl Ou                return new String(buf, 8, buf.length - 8, "EUC-JP");
24015438682a38ad2887426c100452a990b5e3f965dEarl Ou            } else if (Arrays.equals(code, USER_COMMENT_UNICODE)) {
24115438682a38ad2887426c100452a990b5e3f965dEarl Ou                return new String(buf, 8, buf.length - 8, "UTF-16");
24215438682a38ad2887426c100452a990b5e3f965dEarl Ou            } else {
24315438682a38ad2887426c100452a990b5e3f965dEarl Ou                return null;
24415438682a38ad2887426c100452a990b5e3f965dEarl Ou            }
24515438682a38ad2887426c100452a990b5e3f965dEarl Ou        } catch (UnsupportedEncodingException e) {
24615438682a38ad2887426c100452a990b5e3f965dEarl Ou            Log.w(TAG, "Failed to decode the user comment");
24715438682a38ad2887426c100452a990b5e3f965dEarl Ou            return null;
24815438682a38ad2887426c100452a990b5e3f965dEarl Ou        }
2496e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    }
25015438682a38ad2887426c100452a990b5e3f965dEarl Ou
2516e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    /**
2526e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Returns a list of all {@link ExifTag}s in the ExifData or null if there
2536e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * are none.
2546e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     */
2556e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected List<ExifTag> getAllTags() {
2566e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
2576e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        for (IfdData d : mIfdDatas) {
2586e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            if (d != null) {
2596e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                ExifTag[] tags = d.getAllTags();
2606e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                if (tags != null) {
2616e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    for (ExifTag t : tags) {
2626e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        ret.add(t);
2636e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    }
2646e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                }
2656e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
2666e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2676e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (ret.size() == 0) {
2686e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return null;
2696e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2706e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return ret;
27115438682a38ad2887426c100452a990b5e3f965dEarl Ou    }
2726e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
2736e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    /**
2746e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Returns a list of all {@link ExifTag}s in a given IFD or null if there
2756e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * are none.
2766e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     */
2776e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected List<ExifTag> getAllTagsForIfd(int ifd) {
2786e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        IfdData d = mIfdDatas[ifd];
2796e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (d == null) {
2806e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return null;
2816e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2826e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        ExifTag[] tags = d.getAllTags();
2836e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (tags == null) {
2846e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return null;
2856e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2866e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        ArrayList<ExifTag> ret = new ArrayList<ExifTag>(tags.length);
2876e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        for (ExifTag t : tags) {
2886e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            ret.add(t);
2896e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2906e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (ret.size() == 0) {
2916e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return null;
2926e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2936e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return ret;
2946e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    }
2956e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
2966e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    /**
2976e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Returns a list of all {@link ExifTag}s with a given TID or null if there
2986e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * are none.
2996e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     */
3006e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected List<ExifTag> getAllTagsForTagId(short tag) {
3016e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
3026e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        for (IfdData d : mIfdDatas) {
3036e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            if (d != null) {
3046e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                ExifTag t = d.getTag(tag);
3056e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                if (t != null) {
3066e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    ret.add(t);
3076e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                }
3086e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
3096e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
3106e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (ret.size() == 0) {
3116e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return null;
3126e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
3136e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return ret;
3146e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    }
3156e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
3166e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    @Override
3176e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    public boolean equals(Object obj) {
3186e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (this == obj) {
3196e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return true;
3206e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
3216e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (obj == null) {
3226e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return false;
3236e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
3246e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (obj instanceof ExifData) {
3256e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            ExifData data = (ExifData) obj;
3266e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            if (data.mByteOrder != mByteOrder ||
3276e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    data.mStripBytes.size() != mStripBytes.size() ||
3286e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    !Arrays.equals(data.mThumbnail, mThumbnail)) {
3296e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                return false;
3306e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
3316e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            for (int i = 0; i < mStripBytes.size(); i++) {
3326e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                if (!Arrays.equals(data.mStripBytes.get(i), mStripBytes.get(i))) {
3336e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    return false;
3346e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                }
3356e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
3366e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
3376e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                IfdData ifd1 = data.getIfdData(i);
3386e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                IfdData ifd2 = getIfdData(i);
3396e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                if (ifd1 != ifd2 && ifd1 != null && !ifd1.equals(ifd2)) {
3406e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    return false;
3416e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                }
3426e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
3436e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return true;
3446e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
3456e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return false;
3466e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    }
3476e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
3483d8c7829f0cdaa452cf9aaf0e68538ccc8dcde2fEarl Ou}
349