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
32namespace android {
33namespace img_utils {
34
35template<typename T>
36class 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
63template<typename T>
64TiffEntryImpl<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
72template<typename T>
73TiffEntryImpl<T>::~TiffEntryImpl() {}
74
75template<typename T>
76uint32_t TiffEntryImpl<T>::getCount() const {
77    return mCount;
78}
79
80template<typename T>
81uint16_t TiffEntryImpl<T>::getTag() const {
82    return mTag;
83}
84
85template<typename T>
86TagType TiffEntryImpl<T>::getType() const {
87    return static_cast<TagType>(mType);
88}
89
90template<typename T>
91const void* TiffEntryImpl<T>::getDataHelper() const {
92    return reinterpret_cast<const void*>(mData.array());
93}
94
95template<typename T>
96size_t TiffEntryImpl<T>::getSize() const {
97    uint32_t total = getActualSize();
98    WORD_ALIGN(total)
99    return (total <= OFFSET_SIZE) ? 0 : total;
100}
101
102template<typename T>
103uint32_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
112template<typename T>
113Endianness TiffEntryImpl<T>::getEndianness() const {
114    return mEnd;
115}
116
117template<typename T>
118uint32_t TiffEntryImpl<T>::getComparableValue() const {
119    return mTag;
120}
121
122template<typename T>
123status_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
149template<typename T>
150status_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
181template<>
182inline 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
194template<>
195inline 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
203template<>
204inline 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