12523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan/*
22523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * Copyright (C) 2012 The Android Open Source Project
32523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *
42523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * Licensed under the Apache License, Version 2.0 (the "License");
52523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * you may not use this file except in compliance with the License.
62523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * You may obtain a copy of the License at
72523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *
82523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *      http://www.apache.org/licenses/LICENSE-2.0
92523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *
102523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * Unless required by applicable law or agreed to in writing, software
112523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * distributed under the License is distributed on an "AS IS" BASIS,
122523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * See the License for the specific language governing permissions and
142523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * limitations under the License.
152523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan */
162523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
17a16e7b50f3148f581439509279f242092e254309ztenghuipackage com.android.camera.exif;
182523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
19428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ouimport android.util.Log;
20428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou
21428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ouimport java.io.UnsupportedEncodingException;
222523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyanimport java.nio.ByteOrder;
232523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyanimport java.util.ArrayList;
242523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyanimport java.util.Arrays;
25c274ded801f745d6318186958107622e7a4fef33Ruben Brunkimport java.util.List;
262523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
272523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan/**
28c274ded801f745d6318186958107622e7a4fef33Ruben Brunk * This class stores the EXIF header in IFDs according to the JPEG
29c274ded801f745d6318186958107622e7a4fef33Ruben Brunk * specification. It is the result produced by {@link ExifReader}.
30c274ded801f745d6318186958107622e7a4fef33Ruben Brunk *
31c274ded801f745d6318186958107622e7a4fef33Ruben Brunk * @see ExifReader
32c274ded801f745d6318186958107622e7a4fef33Ruben Brunk * @see IfdData
332523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan */
34c274ded801f745d6318186958107622e7a4fef33Ruben Brunkclass ExifData {
35428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou    private static final String TAG = "ExifData";
36428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou    private static final byte[] USER_COMMENT_ASCII = {
37c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00
38c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    };
39428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou    private static final byte[] USER_COMMENT_JIS = {
40c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00
41c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    };
42428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou    private static final byte[] USER_COMMENT_UNICODE = {
43c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00
44c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    };
45670baca6f198f931be76f248b3ddcac7e2211ad4Earl Ou
462523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private final IfdData[] mIfdDatas = new IfdData[IfdId.TYPE_IFD_COUNT];
472523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private byte[] mThumbnail;
482523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private ArrayList<byte[]> mStripBytes = new ArrayList<byte[]>();
492523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private final ByteOrder mByteOrder;
502523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
51c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    ExifData(ByteOrder order) {
522523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        mByteOrder = order;
532523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
542523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
552523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
56c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Gets the compressed thumbnail. Returns null if there is no compressed
57c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * thumbnail.
582523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     *
592523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #hasCompressedThumbnail()
602523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
61c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected byte[] getCompressedThumbnail() {
622523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mThumbnail;
632523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
642523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
652523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
662523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Sets the compressed thumbnail.
672523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
68c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected void setCompressedThumbnail(byte[] thumbnail) {
692523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        mThumbnail = thumbnail;
702523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
712523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
722523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
732523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Returns true it this header contains a compressed thumbnail.
742523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
75c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected boolean hasCompressedThumbnail() {
762523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mThumbnail != null;
772523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
782523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
792523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
802523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Adds an uncompressed strip.
812523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
82c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected void setStripBytes(int index, byte[] strip) {
832523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        if (index < mStripBytes.size()) {
842523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            mStripBytes.set(index, strip);
852523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        } else {
862523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            for (int i = mStripBytes.size(); i < index; i++) {
872523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                mStripBytes.add(null);
882523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            }
892523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            mStripBytes.add(strip);
902523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
912523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
922523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
932523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
942523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Gets the strip count.
952523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
96c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int getStripCount() {
972523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mStripBytes.size();
982523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
992523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1002523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
1012523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Gets the strip at the specified index.
102c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     *
1032523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @exceptions #IndexOutOfBoundException
1042523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
105c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected byte[] getStrip(int index) {
1062523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mStripBytes.get(index);
1072523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
1082523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1092523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
110c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Returns true if this header contains uncompressed strip.
1112523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
112c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected boolean hasUncompressedStrip() {
113c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return mStripBytes.size() != 0;
1142523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
1152523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1162523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
117c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Gets the byte order.
1182523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
119c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected ByteOrder getByteOrder() {
120c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return mByteOrder;
1212523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
1222523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1232523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
124c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Returns the {@link IfdData} object corresponding to a given IFD if it
125c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * exists or null.
1262523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
127c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected IfdData getIfdData(int ifdId) {
128c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (ExifTag.isValidIfd(ifdId)) {
129c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return mIfdDatas[ifdId];
1302523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
131c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return null;
1322523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
1332523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
134670baca6f198f931be76f248b3ddcac7e2211ad4Earl Ou    /**
135c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Adds IFD data. If IFD data of the same type already exists, it will be
136c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * replaced by the new data.
137670baca6f198f931be76f248b3ddcac7e2211ad4Earl Ou     */
138c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected void addIfdData(IfdData data) {
139c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        mIfdDatas[data.getId()] = data;
140670baca6f198f931be76f248b3ddcac7e2211ad4Earl Ou    }
141670baca6f198f931be76f248b3ddcac7e2211ad4Earl Ou
142670baca6f198f931be76f248b3ddcac7e2211ad4Earl Ou    /**
143c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Returns the {@link IfdData} object corresponding to a given IFD or
144c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * generates one if none exist.
145670baca6f198f931be76f248b3ddcac7e2211ad4Earl Ou     */
146c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected IfdData getOrCreateIfdData(int ifdId) {
1472523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        IfdData ifdData = mIfdDatas[ifdId];
1482523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        if (ifdData == null) {
1492523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            ifdData = new IfdData(ifdId);
1502523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            mIfdDatas[ifdId] = ifdData;
1512523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
1522523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return ifdData;
1532523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
1542523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1552523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
156c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Returns the tag with a given TID in the given IFD if the tag exists.
157c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Otherwise returns null.
1582523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
159c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected ExifTag getTag(short tag, int ifd) {
160c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        IfdData ifdData = mIfdDatas[ifd];
161c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return (ifdData == null) ? null : ifdData.getTag(tag);
1622523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
1632523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1642523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
165c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Adds the given ExifTag to its default IFD and returns an existing ExifTag
166c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * with the same TID or null if none exist.
1672523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
168c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected ExifTag addTag(ExifTag tag) {
169c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (tag != null) {
170c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            int ifd = tag.getIfd();
171c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return addTag(tag, ifd);
172c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
173c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return null;
1742523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
1752523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1762523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
177c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Adds the given ExifTag to the given IFD and returns an existing ExifTag
178c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * with the same TID or null if none exist.
179c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou     */
180c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected ExifTag addTag(ExifTag tag, int ifdId) {
181c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (tag != null && ExifTag.isValidIfd(ifdId)) {
182c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            IfdData ifdData = getOrCreateIfdData(ifdId);
183c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return ifdData.setTag(tag);
184c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
185c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return null;
186c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou    }
187c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou
188c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected void clearThumbnailAndStrips() {
189c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        mThumbnail = null;
190c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        mStripBytes.clear();
1912523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
1922523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1932523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
194c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Removes the thumbnail and its related tags. IFD1 will be removed.
1952523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
196c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected void removeThumbnailData() {
197c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        clearThumbnailAndStrips();
198c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        mIfdDatas[IfdId.TYPE_IFD_1] = null;
1992523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
2002523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
201cdeb78889a0a69de640fecabc40e00b106417ab8Earl Ou    /**
202c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Removes the tag with a given TID and IFD.
203cdeb78889a0a69de640fecabc40e00b106417ab8Earl Ou     */
204c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected void removeTag(short tagId, int ifdId) {
205c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        IfdData ifdData = mIfdDatas[ifdId];
206c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (ifdData == null) {
207c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return;
208c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
209c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        ifdData.removeTag(tagId);
2102523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
211428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou
212428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou    /**
213c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Decodes the user comment tag into string as specified in the EXIF
214c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * standard. Returns null if decoding failed.
215428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou     */
216c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected String getUserComment() {
217428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou        IfdData ifdData = mIfdDatas[IfdId.TYPE_IFD_0];
218c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (ifdData == null) {
219c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return null;
220c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
221c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        ExifTag tag = ifdData.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_USER_COMMENT));
222c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (tag == null) {
223c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return null;
224c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
225c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (tag.getComponentCount() < 8) {
226c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return null;
227c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
228428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou
229428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou        byte[] buf = new byte[tag.getComponentCount()];
230428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou        tag.getBytes(buf);
231428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou
232428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou        byte[] code = new byte[8];
233428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou        System.arraycopy(buf, 0, code, 0, 8);
234428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou
235428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou        try {
236428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou            if (Arrays.equals(code, USER_COMMENT_ASCII)) {
237428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou                return new String(buf, 8, buf.length - 8, "US-ASCII");
238428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou            } else if (Arrays.equals(code, USER_COMMENT_JIS)) {
239428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou                return new String(buf, 8, buf.length - 8, "EUC-JP");
240428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou            } else if (Arrays.equals(code, USER_COMMENT_UNICODE)) {
241428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou                return new String(buf, 8, buf.length - 8, "UTF-16");
242428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou            } else {
243428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou                return null;
244428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou            }
245428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou        } catch (UnsupportedEncodingException e) {
246428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou            Log.w(TAG, "Failed to decode the user comment");
247428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou            return null;
248428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou        }
249c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    }
250428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou
251c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    /**
252c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Returns a list of all {@link ExifTag}s in the ExifData or null if there
253c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * are none.
254c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     */
255c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected List<ExifTag> getAllTags() {
256c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
257c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        for (IfdData d : mIfdDatas) {
258c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            if (d != null) {
259c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                ExifTag[] tags = d.getAllTags();
260c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                if (tags != null) {
261c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    for (ExifTag t : tags) {
262c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                        ret.add(t);
263c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    }
264c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                }
265c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
266c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
267c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (ret.size() == 0) {
268c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return null;
269c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
270c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return ret;
271428afc0b79d1fa911df89b94c6b1517688667c2dEarl Ou    }
272c274ded801f745d6318186958107622e7a4fef33Ruben Brunk
273c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    /**
274c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Returns a list of all {@link ExifTag}s in a given IFD or null if there
275c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * are none.
276c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     */
277c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected List<ExifTag> getAllTagsForIfd(int ifd) {
278c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        IfdData d = mIfdDatas[ifd];
279c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (d == null) {
280c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return null;
281c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
282c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        ExifTag[] tags = d.getAllTags();
283c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (tags == null) {
284c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return null;
285c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
286c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        ArrayList<ExifTag> ret = new ArrayList<ExifTag>(tags.length);
287c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        for (ExifTag t : tags) {
288c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            ret.add(t);
289c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
290c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (ret.size() == 0) {
291c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return null;
292c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
293c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return ret;
294c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    }
295c274ded801f745d6318186958107622e7a4fef33Ruben Brunk
296c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    /**
297c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Returns a list of all {@link ExifTag}s with a given TID or null if there
298c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * are none.
299c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     */
300c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected List<ExifTag> getAllTagsForTagId(short tag) {
301c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
302c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        for (IfdData d : mIfdDatas) {
303c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            if (d != null) {
304c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                ExifTag t = d.getTag(tag);
305c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                if (t != null) {
306c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    ret.add(t);
307c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                }
308c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
309c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
310c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (ret.size() == 0) {
311c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return null;
312c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
313c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return ret;
314c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    }
315c274ded801f745d6318186958107622e7a4fef33Ruben Brunk
316c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    @Override
317c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    public boolean equals(Object obj) {
318c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (this == obj) {
319c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return true;
320c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
321c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (obj == null) {
322c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return false;
323c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
324c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (obj instanceof ExifData) {
325c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            ExifData data = (ExifData) obj;
326c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            if (data.mByteOrder != mByteOrder ||
327c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    data.mStripBytes.size() != mStripBytes.size() ||
328c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    !Arrays.equals(data.mThumbnail, mThumbnail)) {
329c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                return false;
330c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
331c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            for (int i = 0; i < mStripBytes.size(); i++) {
332c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                if (!Arrays.equals(data.mStripBytes.get(i), mStripBytes.get(i))) {
333c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    return false;
334c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                }
335c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
336c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
337c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                IfdData ifd1 = data.getIfdData(i);
338c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                IfdData ifd2 = getIfdData(i);
339c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                if (ifd1 != ifd2 && ifd1 != null && !ifd1.equals(ifd2)) {
340c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    return false;
341c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                }
342c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
343c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return true;
344c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
345c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return false;
346c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    }
347c274ded801f745d6318186958107622e7a4fef33Ruben Brunk
3481c515f1aed514638cc030cd5cba5258231e74bb5Hung-ying Tyan}
349