blob: 1b3b40d7b386aa6692daef9b93881b1f7f2cf1d1 [file] [log] [blame]
Ruben Brunke5077212014-04-28 16:39:12 -07001/*
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#include <img_utils/TiffIfd.h>
18#include <img_utils/TiffHelpers.h>
19
20#include <utils/Log.h>
21
22namespace android {
23namespace img_utils {
24
25TiffIfd::TiffIfd(uint32_t ifdId)
26 : mNextIfd(), mIfdId(ifdId) {}
27
28TiffIfd::~TiffIfd() {}
29
30status_t TiffIfd::addEntry(const sp<TiffEntry>& entry) {
31 size_t size = mEntries.size();
32 if (size >= MAX_IFD_ENTRIES) {
Ruben Brunk272b7f22014-05-17 01:09:04 -070033 ALOGW("%s: Failed to add entry for tag 0x%x to IFD %u, too many entries in IFD!",
Ruben Brunke5077212014-04-28 16:39:12 -070034 __FUNCTION__, entry->getTag(), mIfdId);
35 return BAD_INDEX;
36 }
37
38 if (mEntries.add(entry) < 0) {
Ruben Brunk272b7f22014-05-17 01:09:04 -070039 ALOGW("%s: Failed to add entry for tag 0x%x to ifd %u.", __FUNCTION__, entry->getTag(),
Ruben Brunke5077212014-04-28 16:39:12 -070040 mIfdId);
41 return BAD_INDEX;
42 }
43 return OK;
44}
45
46sp<TiffEntry> TiffIfd::getEntry(uint16_t tag) const {
47 ssize_t index = mEntries.indexOfTag(tag);
48 if (index < 0) {
Ruben Brunk272b7f22014-05-17 01:09:04 -070049 ALOGW("%s: No entry for tag 0x%x in ifd %u.", __FUNCTION__, tag, mIfdId);
Ruben Brunke5077212014-04-28 16:39:12 -070050 return NULL;
51 }
52 return mEntries[index];
53}
54
55void TiffIfd::setNextIfd(const sp<TiffIfd>& ifd) {
56 mNextIfd = ifd;
57}
58
59sp<TiffIfd> TiffIfd::getNextIfd() const {
60 return mNextIfd;
61}
62
63uint32_t TiffIfd::checkAndGetOffset(uint32_t offset) const {
64 size_t size = mEntries.size();
65
66 if (size > MAX_IFD_ENTRIES) {
Ruben Brunk272b7f22014-05-17 01:09:04 -070067 ALOGW("%s: Could not calculate IFD offsets, IFD %u contains too many entries.",
Ruben Brunke5077212014-04-28 16:39:12 -070068 __FUNCTION__, mIfdId);
69 return BAD_OFFSET;
70 }
71
72 if (size <= 0) {
Ruben Brunk272b7f22014-05-17 01:09:04 -070073 ALOGW("%s: Could not calculate IFD offsets, IFD %u contains no entries.", __FUNCTION__,
Ruben Brunke5077212014-04-28 16:39:12 -070074 mIfdId);
75 return BAD_OFFSET;
76 }
77
78 if (offset == BAD_OFFSET) {
Ruben Brunk272b7f22014-05-17 01:09:04 -070079 ALOGW("%s: Could not calculate IFD offsets, IFD %u had a bad initial offset.",
Ruben Brunke5077212014-04-28 16:39:12 -070080 __FUNCTION__, mIfdId);
81 return BAD_OFFSET;
82 }
83
84 uint32_t ifdSize = calculateIfdSize(size);
85 WORD_ALIGN(ifdSize);
86 return offset + ifdSize;
87}
88
89status_t TiffIfd::writeData(uint32_t offset, /*out*/EndianOutput* out) const {
90 assert((offset % TIFF_WORD_SIZE) == 0);
91 status_t ret = OK;
92
93 ALOGV("%s: IFD %u written to offset %u", __FUNCTION__, mIfdId, offset );
94 uint32_t valueOffset = checkAndGetOffset(offset);
95 if (valueOffset == 0) {
96 return BAD_VALUE;
97 }
98
99 size_t size = mEntries.size();
100
101 // Writer IFD header (2 bytes, number of entries).
102 uint16_t header = static_cast<uint16_t>(size);
103 BAIL_ON_FAIL(out->write(&header, 0, 1), ret);
104
105 // Write tag entries
106 for (size_t i = 0; i < size; ++i) {
107 BAIL_ON_FAIL(mEntries[i]->writeTagInfo(valueOffset, out), ret);
108 valueOffset += mEntries[i]->getSize();
109 }
110
111 // Writer IFD footer (4 bytes, offset to next IFD).
112 uint32_t footer = (mNextIfd != NULL) ? offset + getSize() : 0;
113 BAIL_ON_FAIL(out->write(&footer, 0, 1), ret);
114
115 assert(out->getCurrentOffset() == offset + calculateIfdSize(size));
116
117 // Write zeroes till word aligned
118 ZERO_TILL_WORD(out, calculateIfdSize(size), ret);
119
120 // Write values for each tag entry
121 for (size_t i = 0; i < size; ++i) {
122 size_t last = out->getCurrentOffset();
123 // Only write values that are too large to fit in the 12-byte TIFF entry
124 if (mEntries[i]->getSize() > OFFSET_SIZE) {
125 BAIL_ON_FAIL(mEntries[i]->writeData(out->getCurrentOffset(), out), ret);
126 }
127 size_t next = out->getCurrentOffset();
128 size_t diff = (next - last);
129 size_t actual = mEntries[i]->getSize();
130 if (diff != actual) {
Ruben Brunk272b7f22014-05-17 01:09:04 -0700131 ALOGW("Sizes do not match for tag %x. Expected %zu, received %zu",
Ruben Brunke5077212014-04-28 16:39:12 -0700132 mEntries[i]->getTag(), actual, diff);
133 }
134 }
135
136 assert(out->getCurrentOffset() == offset + getSize());
137
138 return ret;
139}
140
Ruben Brunk272b7f22014-05-17 01:09:04 -0700141size_t TiffIfd::getSize() const {
Ruben Brunke5077212014-04-28 16:39:12 -0700142 size_t size = mEntries.size();
143 uint32_t total = calculateIfdSize(size);
144 WORD_ALIGN(total);
145 for (size_t i = 0; i < size; ++i) {
146 total += mEntries[i]->getSize();
147 }
148 return total;
149}
150
151uint32_t TiffIfd::getId() const {
152 return mIfdId;
153}
154
155uint32_t TiffIfd::getComparableValue() const {
156 return mIfdId;
157}
158
159String8 TiffIfd::toString() const {
160 size_t s = mEntries.size();
161 String8 output;
Ruben Brunk272b7f22014-05-17 01:09:04 -0700162 output.appendFormat("[ifd: %x, num_entries: %zu, entries:\n", getId(), s);
Ruben Brunke5077212014-04-28 16:39:12 -0700163 for(size_t i = 0; i < mEntries.size(); ++i) {
164 output.append("\t");
165 output.append(mEntries[i]->toString());
166 output.append("\n");
167 }
168 output.append(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0));
169 return output;
170}
171
172void TiffIfd::log() const {
173 size_t s = mEntries.size();
Ruben Brunk272b7f22014-05-17 01:09:04 -0700174 ALOGI("[ifd: %x, num_entries: %zu, entries:\n", getId(), s);
Ruben Brunke5077212014-04-28 16:39:12 -0700175 for(size_t i = 0; i < s; ++i) {
176 ALOGI("\t%s", mEntries[i]->toString().string());
177 }
178 ALOGI(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0));
179}
180
181} /*namespace img_utils*/
182} /*namespace android*/