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