1 /*
2  * Copyright 2014 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 #ifndef IMG_UTILS_TIFF_ENTRY_IMPL
18 #define IMG_UTILS_TIFF_ENTRY_IMPL
19 
20 #include <img_utils/TiffIfd.h>
21 #include <img_utils/TiffEntry.h>
22 #include <img_utils/TiffHelpers.h>
23 #include <img_utils/Output.h>
24 #include <img_utils/EndianUtils.h>
25 
26 #include <utils/Log.h>
27 #include <utils/Errors.h>
28 #include <utils/Vector.h>
29 #include <utils/StrongPointer.h>
30 #include <stdint.h>
31 
32 namespace android {
33 namespace img_utils {
34 
35 template<typename T>
36 class TiffEntryImpl : public TiffEntry {
37     public:
38         TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endianness end, const T* data);
39         virtual ~TiffEntryImpl();
40 
41         status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const;
42         status_t writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const;
43 
44         uint32_t getCount() const;
45         uint16_t getTag() const;
46         TagType getType() const;
47         Endianness getEndianness() const;
48         size_t getSize() const;
49         uint32_t getComparableValue() const;
50 
51     protected:
52         const void* getDataHelper() const;
53         uint32_t getActualSize() const;
54 
55         uint16_t mTag;
56         uint16_t mType;
57         uint32_t mCount;
58         Endianness mEnd;
59         Vector<T> mData;
60 
61 };
62 
63 template<typename T>
TiffEntryImpl(uint16_t tag,TagType type,uint32_t count,Endianness end,const T * data)64 TiffEntryImpl<T>::TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endianness end,
65         const T* data)
66         : mTag(tag), mType(static_cast<uint16_t>(type)), mCount(count), mEnd(end) {
67     count = (type == RATIONAL || type == SRATIONAL) ? count * 2 : count;
68     ssize_t index = mData.appendArray(data, count);
69     LOG_ALWAYS_FATAL_IF(index < 0, "%s: Could not allocate vector for data.", __FUNCTION__);
70 }
71 
72 template<typename T>
~TiffEntryImpl()73 TiffEntryImpl<T>::~TiffEntryImpl() {}
74 
75 template<typename T>
getCount()76 uint32_t TiffEntryImpl<T>::getCount() const {
77     return mCount;
78 }
79 
80 template<typename T>
getTag()81 uint16_t TiffEntryImpl<T>::getTag() const {
82     return mTag;
83 }
84 
85 template<typename T>
getType()86 TagType TiffEntryImpl<T>::getType() const {
87     return static_cast<TagType>(mType);
88 }
89 
90 template<typename T>
getDataHelper()91 const void* TiffEntryImpl<T>::getDataHelper() const {
92     return reinterpret_cast<const void*>(mData.array());
93 }
94 
95 template<typename T>
getSize()96 size_t TiffEntryImpl<T>::getSize() const {
97     uint32_t total = getActualSize();
98     WORD_ALIGN(total)
99     return (total <= OFFSET_SIZE) ? 0 : total;
100 }
101 
102 template<typename T>
getActualSize()103 uint32_t TiffEntryImpl<T>::getActualSize() const {
104     uint32_t total = sizeof(T) * mCount;
105     if (getType() == RATIONAL || getType() == SRATIONAL) {
106         // 2 ints stored for each rational, multiply by 2
107         total <<= 1;
108     }
109     return total;
110 }
111 
112 template<typename T>
getEndianness()113 Endianness TiffEntryImpl<T>::getEndianness() const {
114     return mEnd;
115 }
116 
117 template<typename T>
getComparableValue()118 uint32_t TiffEntryImpl<T>::getComparableValue() const {
119     return mTag;
120 }
121 
122 template<typename T>
writeTagInfo(uint32_t offset,EndianOutput * out)123 status_t TiffEntryImpl<T>::writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const {
124     assert((offset % TIFF_WORD_SIZE) == 0);
125     status_t ret = OK;
126     BAIL_ON_FAIL(out->write(&mTag, 0, 1), ret);
127     BAIL_ON_FAIL(out->write(&mType, 0, 1), ret);
128     BAIL_ON_FAIL(out->write(&mCount, 0, 1), ret);
129 
130     uint32_t dataSize = getActualSize();
131     if (dataSize > OFFSET_SIZE) {
132         BAIL_ON_FAIL(out->write(&offset, 0, 1), ret);
133     } else {
134         uint32_t count = mCount;
135         if (getType() == RATIONAL || getType() == SRATIONAL) {
136             /**
137              * Rationals are stored as an array of ints.  Each
138              * rational is represented by 2 ints.  To recover the
139              * size of the array here, multiply the count by 2.
140              */
141             count <<= 1;
142         }
143         BAIL_ON_FAIL(out->write(mData.array(), 0, count), ret);
144         ZERO_TILL_WORD(out, dataSize, ret);
145     }
146     return ret;
147 }
148 
149 template<typename T>
writeData(uint32_t,EndianOutput * out)150 status_t TiffEntryImpl<T>::writeData(uint32_t /*offset*/, EndianOutput* out) const {
151     status_t ret = OK;
152 
153     // Some tags have fixed-endian value output
154     Endianness tmp = UNDEFINED_ENDIAN;
155     if (mEnd != UNDEFINED_ENDIAN) {
156         tmp = out->getEndianness();
157         out->setEndianness(mEnd);
158     }
159 
160     uint32_t count = mCount;
161     if (getType() == RATIONAL || getType() == SRATIONAL) {
162         /**
163          * Rationals are stored as an array of ints.  Each
164          * rational is represented by 2 ints.  To recover the
165          * size of the array here, multiply the count by 2.
166          */
167         count <<= 1;
168     }
169 
170     BAIL_ON_FAIL(out->write(mData.array(), 0, count), ret);
171 
172     if (mEnd != UNDEFINED_ENDIAN) {
173         out->setEndianness(tmp);
174     }
175 
176     // Write to next word alignment
177     ZERO_TILL_WORD(out, sizeof(T) * count, ret);
178     return ret;
179 }
180 
181 template<>
writeTagInfo(uint32_t offset,EndianOutput * out)182 inline status_t TiffEntryImpl<sp<TiffIfd> >::writeTagInfo(uint32_t offset,
183         /*out*/EndianOutput* out) const {
184     assert((offset % TIFF_WORD_SIZE) == 0);
185     status_t ret = OK;
186     BAIL_ON_FAIL(out->write(&mTag, 0, 1), ret);
187     BAIL_ON_FAIL(out->write(&mType, 0, 1), ret);
188     BAIL_ON_FAIL(out->write(&mCount, 0, 1), ret);
189 
190     BAIL_ON_FAIL(out->write(&offset, 0, 1), ret);
191     return ret;
192 }
193 
194 template<>
getActualSize()195 inline uint32_t TiffEntryImpl<sp<TiffIfd> >::getActualSize() const {
196     uint32_t total = 0;
197     for (size_t i = 0; i < mData.size(); ++i) {
198         total += mData[i]->getSize();
199     }
200     return total;
201 }
202 
203 template<>
writeData(uint32_t offset,EndianOutput * out)204 inline status_t TiffEntryImpl<sp<TiffIfd> >::writeData(uint32_t offset, EndianOutput* out) const {
205     status_t ret = OK;
206     for (uint32_t i = 0; i < mCount; ++i) {
207         BAIL_ON_FAIL(mData[i]->writeData(offset, out), ret);
208         offset += mData[i]->getSize();
209     }
210     return ret;
211 }
212 
213 } /*namespace img_utils*/
214 } /*namespace android*/
215 
216 #endif /*IMG_UTILS_TIFF_ENTRY_IMPL*/
217 
218 
219