• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.mms.exif;
18 
19 import com.android.mms.LogTag;
20 
21 import android.util.Log;
22 
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.nio.ByteBuffer;
26 import java.nio.ByteOrder;
27 import java.util.ArrayList;
28 import java.util.List;
29 
30 class ExifModifier {
31     public static final String TAG = LogTag.TAG;
32     public static final boolean DEBUG = false;
33     private final ByteBuffer mByteBuffer;
34     private final ExifData mTagToModified;
35     private final List<TagOffset> mTagOffsets = new ArrayList<TagOffset>();
36     private final ExifInterface mInterface;
37     private int mOffsetBase;
38 
39     private static class TagOffset {
40         final int mOffset;
41         final ExifTag mTag;
42 
TagOffset(ExifTag tag, int offset)43         TagOffset(ExifTag tag, int offset) {
44             mTag = tag;
45             mOffset = offset;
46         }
47     }
48 
ExifModifier(ByteBuffer byteBuffer, ExifInterface iRef)49     protected ExifModifier(ByteBuffer byteBuffer, ExifInterface iRef) throws IOException,
50             ExifInvalidFormatException {
51         mByteBuffer = byteBuffer;
52         mOffsetBase = byteBuffer.position();
53         mInterface = iRef;
54         InputStream is = null;
55         try {
56             is = new ByteBufferInputStream(byteBuffer);
57             // Do not require any IFD;
58             ExifParser parser = ExifParser.parse(is, mInterface);
59             mTagToModified = new ExifData(parser.getByteOrder());
60             mOffsetBase += parser.getTiffStartPosition();
61             mByteBuffer.position(0);
62         } finally {
63             ExifInterface.closeSilently(is);
64         }
65     }
66 
getByteOrder()67     protected ByteOrder getByteOrder() {
68         return mTagToModified.getByteOrder();
69     }
70 
commit()71     protected boolean commit() throws IOException, ExifInvalidFormatException {
72         InputStream is = null;
73         try {
74             is = new ByteBufferInputStream(mByteBuffer);
75             int flag = 0;
76             IfdData[] ifdDatas = new IfdData[] {
77                     mTagToModified.getIfdData(IfdId.TYPE_IFD_0),
78                     mTagToModified.getIfdData(IfdId.TYPE_IFD_1),
79                     mTagToModified.getIfdData(IfdId.TYPE_IFD_EXIF),
80                     mTagToModified.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY),
81                     mTagToModified.getIfdData(IfdId.TYPE_IFD_GPS)
82             };
83 
84             if (ifdDatas[IfdId.TYPE_IFD_0] != null) {
85                 flag |= ExifParser.OPTION_IFD_0;
86             }
87             if (ifdDatas[IfdId.TYPE_IFD_1] != null) {
88                 flag |= ExifParser.OPTION_IFD_1;
89             }
90             if (ifdDatas[IfdId.TYPE_IFD_EXIF] != null) {
91                 flag |= ExifParser.OPTION_IFD_EXIF;
92             }
93             if (ifdDatas[IfdId.TYPE_IFD_GPS] != null) {
94                 flag |= ExifParser.OPTION_IFD_GPS;
95             }
96             if (ifdDatas[IfdId.TYPE_IFD_INTEROPERABILITY] != null) {
97                 flag |= ExifParser.OPTION_IFD_INTEROPERABILITY;
98             }
99 
100             ExifParser parser = ExifParser.parse(is, flag, mInterface);
101             int event = parser.next();
102             IfdData currIfd = null;
103             while (event != ExifParser.EVENT_END) {
104                 switch (event) {
105                     case ExifParser.EVENT_START_OF_IFD:
106                         currIfd = ifdDatas[parser.getCurrentIfd()];
107                         if (currIfd == null) {
108                             parser.skipRemainingTagsInCurrentIfd();
109                         }
110                         break;
111                     case ExifParser.EVENT_NEW_TAG:
112                         ExifTag oldTag = parser.getTag();
113                         ExifTag newTag = currIfd.getTag(oldTag.getTagId());
114                         if (newTag != null) {
115                             if (newTag.getComponentCount() != oldTag.getComponentCount()
116                                     || newTag.getDataType() != oldTag.getDataType()) {
117                                 return false;
118                             } else {
119                                 mTagOffsets.add(new TagOffset(newTag, oldTag.getOffset()));
120                                 currIfd.removeTag(oldTag.getTagId());
121                                 if (currIfd.getTagCount() == 0) {
122                                     parser.skipRemainingTagsInCurrentIfd();
123                                 }
124                             }
125                         }
126                         break;
127                 }
128                 event = parser.next();
129             }
130             for (IfdData ifd : ifdDatas) {
131                 if (ifd != null && ifd.getTagCount() > 0) {
132                     return false;
133                 }
134             }
135             modify();
136         } finally {
137             ExifInterface.closeSilently(is);
138         }
139         return true;
140     }
141 
modify()142     private void modify() {
143         mByteBuffer.order(getByteOrder());
144         for (TagOffset tagOffset : mTagOffsets) {
145             writeTagValue(tagOffset.mTag, tagOffset.mOffset);
146         }
147     }
148 
writeTagValue(ExifTag tag, int offset)149     private void writeTagValue(ExifTag tag, int offset) {
150         if (DEBUG) {
151             Log.v(TAG, "modifying tag to: \n" + tag.toString());
152             Log.v(TAG, "at offset: " + offset);
153         }
154         mByteBuffer.position(offset + mOffsetBase);
155         switch (tag.getDataType()) {
156             case ExifTag.TYPE_ASCII:
157                 byte buf[] = tag.getStringByte();
158                 if (buf.length == tag.getComponentCount()) {
159                     buf[buf.length - 1] = 0;
160                     mByteBuffer.put(buf);
161                 } else {
162                     mByteBuffer.put(buf);
163                     mByteBuffer.put((byte) 0);
164                 }
165                 break;
166             case ExifTag.TYPE_LONG:
167             case ExifTag.TYPE_UNSIGNED_LONG:
168                 for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
169                     mByteBuffer.putInt((int) tag.getValueAt(i));
170                 }
171                 break;
172             case ExifTag.TYPE_RATIONAL:
173             case ExifTag.TYPE_UNSIGNED_RATIONAL:
174                 for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
175                     Rational v = tag.getRational(i);
176                     mByteBuffer.putInt((int) v.getNumerator());
177                     mByteBuffer.putInt((int) v.getDenominator());
178                 }
179                 break;
180             case ExifTag.TYPE_UNDEFINED:
181             case ExifTag.TYPE_UNSIGNED_BYTE:
182                 buf = new byte[tag.getComponentCount()];
183                 tag.getBytes(buf);
184                 mByteBuffer.put(buf);
185                 break;
186             case ExifTag.TYPE_UNSIGNED_SHORT:
187                 for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
188                     mByteBuffer.putShort((short) tag.getValueAt(i));
189                 }
190                 break;
191         }
192     }
193 
modifyTag(ExifTag tag)194     public void modifyTag(ExifTag tag) {
195         mTagToModified.addTag(tag);
196     }
197 }
198