1e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk/*
2e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * Copyright 2014 The Android Open Source Project
3e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk *
4e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
5e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * you may not use this file except in compliance with the License.
6e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * You may obtain a copy of the License at
7e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk *
8e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
9e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk *
10e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * Unless required by applicable law or agreed to in writing, software
11e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
12e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * See the License for the specific language governing permissions and
14e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * limitations under the License.
15e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk */
16e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
174510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk#define LOG_TAG "TiffWriter"
184510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
19e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk#include <img_utils/TiffHelpers.h>
20e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk#include <img_utils/TiffWriter.h>
21e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk#include <img_utils/TagDefinitions.h>
22e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
23e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk#include <assert.h>
24e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
25e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunknamespace android {
26e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunknamespace img_utils {
27e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
28e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben BrunkKeyedVector<uint16_t, const TagDefinition_t*> TiffWriter::buildTagMap(
29e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk            const TagDefinition_t* definitions, size_t length) {
30e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    KeyedVector<uint16_t, const TagDefinition_t*> map;
31e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    for(size_t i = 0; i < length; ++i) {
32e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        map.add(definitions[i].tagId, definitions + i);
33e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
34e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return map;
35e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
36e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
37e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk#define COMPARE(op) \
38e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkbool Orderable::operator op (const Orderable& orderable) const { \
39e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return getComparableValue() op orderable.getComparableValue(); \
40e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
41e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
42e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk#define ARRAY_SIZE(array) \
43e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    (sizeof(array) / sizeof(array[0]))
44e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
45e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben BrunkKeyedVector<uint16_t, const TagDefinition_t*> TiffWriter::sTagMaps[] = {
46e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    buildTagMap(TIFF_EP_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_EP_TAG_DEFINITIONS)),
47e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    buildTagMap(DNG_TAG_DEFINITIONS, ARRAY_SIZE(DNG_TAG_DEFINITIONS)),
48e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    buildTagMap(EXIF_2_3_TAG_DEFINITIONS, ARRAY_SIZE(EXIF_2_3_TAG_DEFINITIONS)),
49e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    buildTagMap(TIFF_6_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_6_TAG_DEFINITIONS))
50e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk};
51e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
52e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben BrunkTiffWriter::TiffWriter() : mTagMaps(sTagMaps), mNumTagMaps(DEFAULT_NUM_TAG_MAPS) {}
53e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
54e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben BrunkTiffWriter::TiffWriter(KeyedVector<uint16_t, const TagDefinition_t*>* enabledDefinitions,
55e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        size_t length) : mTagMaps(enabledDefinitions), mNumTagMaps(length) {}
56e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
57e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben BrunkTiffWriter::~TiffWriter() {}
58e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
594510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkstatus_t TiffWriter::write(Output* out, StripSource** sources, size_t sourcesCount,
604510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        Endianness end) {
614510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    status_t ret = OK;
624510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    EndianOutput endOut(out, end);
634510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
644510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (mIfd == NULL) {
654510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Tiff header is empty.", __FUNCTION__);
664510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
674510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
684510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
694510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint32_t totalSize = getTotalSize();
704510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
714510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    KeyedVector<uint32_t, uint32_t> offsetVector;
724510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
734510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    for (size_t i = 0; i < mNamedIfds.size(); ++i) {
744510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        if (mNamedIfds[i]->uninitializedOffsets()) {
754510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            uint32_t stripSize = mNamedIfds[i]->getStripSize();
764510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            if (mNamedIfds[i]->setStripOffset(totalSize) != OK) {
774510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                ALOGE("%s: Could not set strip offsets.", __FUNCTION__);
784510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                return BAD_VALUE;
794510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            }
804510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            totalSize += stripSize;
814510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            WORD_ALIGN(totalSize);
824510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            offsetVector.add(mNamedIfds.keyAt(i), totalSize);
834510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        }
844510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
854510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
864510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    size_t offVecSize = offsetVector.size();
874510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (offVecSize != sourcesCount) {
884510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Mismatch between number of IFDs with uninitialized strips (%zu) and"
894510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                " sources (%zu).", __FUNCTION__, offVecSize, sourcesCount);
904510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
914510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
924510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
934510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    BAIL_ON_FAIL(writeFileHeader(endOut), ret);
944510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
954510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint32_t offset = FILE_HEADER_SIZE;
964510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffIfd> ifd = mIfd;
974510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    while(ifd != NULL) {
984510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        BAIL_ON_FAIL(ifd->writeData(offset, &endOut), ret);
994510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        offset += ifd->getSize();
1004510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ifd = ifd->getNextIfd();
1014510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
1024510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
103ca73159becc0fc0098530929e467a3d92e470571Ruben Brunk    if (LOG_NDEBUG == 0) {
104ca73159becc0fc0098530929e467a3d92e470571Ruben Brunk        log();
105ca73159becc0fc0098530929e467a3d92e470571Ruben Brunk    }
1064510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
1074510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    for (size_t i = 0; i < offVecSize; ++i) {
1084510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        uint32_t ifdKey = offsetVector.keyAt(i);
1094510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        uint32_t sizeToWrite = mNamedIfds[ifdKey]->getStripSize();
1104510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        bool found = false;
1114510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        for (size_t j = 0; j < sourcesCount; ++j) {
1124510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            if (sources[j]->getIfd() == ifdKey) {
1134510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                if ((ret = sources[i]->writeToStream(endOut, sizeToWrite)) != OK) {
1144510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                    ALOGE("%s: Could not write to stream, received %d.", __FUNCTION__, ret);
1154510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                    return ret;
1164510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                }
1174510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                ZERO_TILL_WORD(&endOut, sizeToWrite, ret);
1184510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                found = true;
1194510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                break;
1204510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            }
1214510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        }
1224510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        if (!found) {
1234510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            ALOGE("%s: No stream for byte strips for IFD %u", __FUNCTION__, ifdKey);
1244510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            return BAD_VALUE;
1254510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        }
1266c955eb0b4777eeade077f99bfa50e462906819aBernhard Rosenkränzer        assert(offsetVector[i] == endOut.getCurrentOffset());
1274510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
1284510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
1294510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    return ret;
1304510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk}
1314510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
132e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkstatus_t TiffWriter::write(Output* out, Endianness end) {
133e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    status_t ret = OK;
134e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    EndianOutput endOut(out, end);
135e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
136e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (mIfd == NULL) {
137e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        ALOGE("%s: Tiff header is empty.", __FUNCTION__);
138e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return BAD_VALUE;
139e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
140e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    BAIL_ON_FAIL(writeFileHeader(endOut), ret);
141e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
142e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    uint32_t offset = FILE_HEADER_SIZE;
143e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    sp<TiffIfd> ifd = mIfd;
144e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    while(ifd != NULL) {
145e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        BAIL_ON_FAIL(ifd->writeData(offset, &endOut), ret);
146e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        offset += ifd->getSize();
147e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        ifd = ifd->getNextIfd();
148e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
149e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return ret;
150e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
151e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
152e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
153e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkconst TagDefinition_t* TiffWriter::lookupDefinition(uint16_t tag) const {
154e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    const TagDefinition_t* definition = NULL;
155e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    for (size_t i = 0; i < mNumTagMaps; ++i) {
156e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        ssize_t index = mTagMaps[i].indexOfKey(tag);
157e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        if (index >= 0) {
158e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk            definition = mTagMaps[i][index];
159e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk            break;
160e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        }
161e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
162e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
163e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (definition == NULL) {
164e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        ALOGE("%s: No definition exists for tag with id %x.", __FUNCTION__, tag);
165e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
166e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return definition;
167e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
168e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
169e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunksp<TiffEntry> TiffWriter::getEntry(uint16_t tag, uint32_t ifd) const {
170e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    ssize_t index = mNamedIfds.indexOfKey(ifd);
171e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (index < 0) {
172e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        ALOGE("%s: No IFD %d set for this writer.", __FUNCTION__, ifd);
173e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return NULL;
174e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
175e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return mNamedIfds[index]->getEntry(tag);
176e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
177e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
1784510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkvoid TiffWriter::removeEntry(uint16_t tag, uint32_t ifd) {
1794510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    ssize_t index = mNamedIfds.indexOfKey(ifd);
1804510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (index >= 0) {
1814510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        mNamedIfds[index]->removeEntry(tag);
1824510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
1834510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk}
184e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
1854510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkstatus_t TiffWriter::addEntry(const sp<TiffEntry>& entry, uint32_t ifd) {
186e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    uint16_t tag = entry->getTag();
187e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
188e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    const TagDefinition_t* definition = lookupDefinition(tag);
189e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
190e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (definition == NULL) {
1914510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: No definition exists for tag 0x%x.", __FUNCTION__, tag);
192e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return BAD_INDEX;
193e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
194e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
1954510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    ssize_t index = mNamedIfds.indexOfKey(ifd);
196e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
197e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    // Add a new IFD if necessary
198e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (index < 0) {
1994510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: No IFD %u exists.", __FUNCTION__, ifd);
2004510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return NAME_NOT_FOUND;
201e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
202e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
203e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    sp<TiffIfd> selectedIfd  = mNamedIfds[index];
204e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return selectedIfd->addEntry(entry);
205e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
206e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
2074510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkstatus_t TiffWriter::addStrip(uint32_t ifd) {
2084510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    ssize_t index = mNamedIfds.indexOfKey(ifd);
2094510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (index < 0) {
2104510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Ifd %u doesn't exist, cannot add strip entries.", __FUNCTION__, ifd);
2114510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
212e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
2134510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffIfd> selected = mNamedIfds[index];
2144510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    return selected->validateAndSetStripTags();
215e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
216e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
217e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkstatus_t TiffWriter::addIfd(uint32_t ifd) {
218e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    ssize_t index = mNamedIfds.indexOfKey(ifd);
219e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (index >= 0) {
220e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd);
221e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return BAD_VALUE;
222e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
2234510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
224e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    sp<TiffIfd> newIfd = new TiffIfd(ifd);
225e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (mIfd == NULL) {
226e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        mIfd = newIfd;
227e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    } else {
228e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        sp<TiffIfd> last = findLastIfd();
229e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        last->setNextIfd(newIfd);
230e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
2314510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2324510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if(mNamedIfds.add(ifd, newIfd) < 0) {
2334510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Failed to add new IFD 0x%x.", __FUNCTION__, ifd);
2344510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2354510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2364510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2374510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    return OK;
2384510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk}
2394510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2404510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkstatus_t TiffWriter::addSubIfd(uint32_t parentIfd, uint32_t ifd, SubIfdType type) {
2414510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    ssize_t index = mNamedIfds.indexOfKey(ifd);
2424510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (index >= 0) {
2434510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd);
2444510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2454510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2464510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2474510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    ssize_t parentIndex = mNamedIfds.indexOfKey(parentIfd);
2484510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (parentIndex < 0) {
2494510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Parent IFD with ID 0x%x does not exist.", __FUNCTION__, parentIfd);
2504510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2514510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2524510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2534510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffIfd> parent = mNamedIfds[parentIndex];
2544510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffIfd> newIfd = new TiffIfd(ifd);
2554510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2564510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint16_t subIfdTag;
2574510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (type == SUBIFD) {
2584510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        subIfdTag = TAG_SUBIFDS;
2594510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    } else if (type == GPSINFO) {
2604510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        subIfdTag = TAG_GPSINFO;
2614510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    } else {
2624510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Unknown SubIFD type %d.", __FUNCTION__, type);
2634510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2644510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2654510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2664510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> subIfds = parent->getEntry(subIfdTag);
2674510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (subIfds == NULL) {
2684510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        if (buildEntry(subIfdTag, 1, &newIfd, &subIfds) < 0) {
2694510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd);
2704510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            return BAD_VALUE;
2714510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        }
2724510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    } else {
2734510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        if (type == GPSINFO) {
2744510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            ALOGE("%s: Cannot add GPSInfo SubIFD to IFD %u, one already exists.", __FUNCTION__,
2754510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                    ifd);
2764510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            return BAD_VALUE;
2774510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        }
2784510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2794510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        Vector<sp<TiffIfd> > subIfdList;
2804510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        const sp<TiffIfd>* oldIfdArray = subIfds->getData<sp<TiffIfd> >();
2814510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        if (subIfdList.appendArray(oldIfdArray, subIfds->getCount()) < 0) {
2824510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd);
2834510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            return BAD_VALUE;
2844510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        }
2854510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2864510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        if (subIfdList.add(newIfd) < 0) {
2874510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd);
2884510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            return BAD_VALUE;
2894510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        }
2904510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2914510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        uint32_t count = subIfdList.size();
2924510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        if (buildEntry(subIfdTag, count, subIfdList.array(), &subIfds) < 0) {
2934510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd);
2944510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            return BAD_VALUE;
2954510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        }
2964510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2974510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2984510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (parent->addEntry(subIfds) < 0) {
2994510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Failed to add SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd);
3004510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
3014510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
3024510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3034510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if(mNamedIfds.add(ifd, newIfd) < 0) {
3044510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Failed to add new IFD 0x%x.", __FUNCTION__, ifd);
3054510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
3064510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
3074510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
308e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return OK;
309e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
310e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
311e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben BrunkTagType TiffWriter::getDefaultType(uint16_t tag) const {
312e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    const TagDefinition_t* definition = lookupDefinition(tag);
313e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (definition == NULL) {
314e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag);
315e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return UNKNOWN_TAGTYPE;
316e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
317e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return definition->defaultType;
318e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
319e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
320e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkuint32_t TiffWriter::getDefaultCount(uint16_t tag) const {
321e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    const TagDefinition_t* definition = lookupDefinition(tag);
322e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (definition == NULL) {
323e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag);
324e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return 0;
325e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
326e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return definition->fixedCount;
327e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
328e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
3294510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkbool TiffWriter::hasIfd(uint32_t ifd) const {
3304510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    ssize_t index = mNamedIfds.indexOfKey(ifd);
3314510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    return index >= 0;
3324510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk}
3334510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
334e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkbool TiffWriter::checkIfDefined(uint16_t tag) const {
335e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return lookupDefinition(tag) != NULL;
336e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
337e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
3384510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkconst char* TiffWriter::getTagName(uint16_t tag) const {
3394510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    const TagDefinition_t* definition = lookupDefinition(tag);
3404510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (definition == NULL) {
3414510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return NULL;
3424510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
3434510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    return definition->tagName;
3444510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk}
3454510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
346e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunksp<TiffIfd> TiffWriter::findLastIfd() {
347e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    sp<TiffIfd> ifd = mIfd;
348e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    while(ifd != NULL) {
349e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        sp<TiffIfd> nextIfd = ifd->getNextIfd();
350e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        if (nextIfd == NULL) {
351e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk            break;
352e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        }
353e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        ifd = nextIfd;
354e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
355e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return ifd;
356e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
357e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
358e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkstatus_t TiffWriter::writeFileHeader(EndianOutput& out) {
359e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    status_t ret = OK;
360e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    uint16_t endMarker = (out.getEndianness() == BIG) ? BIG_ENDIAN_MARKER : LITTLE_ENDIAN_MARKER;
361e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    BAIL_ON_FAIL(out.write(&endMarker, 0, 1), ret);
362e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
363e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    uint16_t tiffMarker = TIFF_FILE_MARKER;
364e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    BAIL_ON_FAIL(out.write(&tiffMarker, 0, 1), ret);
365e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
366e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    uint32_t offsetMarker = FILE_HEADER_SIZE;
367e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    BAIL_ON_FAIL(out.write(&offsetMarker, 0, 1), ret);
368e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return ret;
369e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
370e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
371e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkuint32_t TiffWriter::getTotalSize() const {
372e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    uint32_t totalSize = FILE_HEADER_SIZE;
373e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    sp<TiffIfd> ifd = mIfd;
374e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    while(ifd != NULL) {
375e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        totalSize += ifd->getSize();
376e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        ifd = ifd->getNextIfd();
377e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
378e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return totalSize;
379e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
380e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
381e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkvoid TiffWriter::log() const {
382e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    ALOGI("%s: TiffWriter:", __FUNCTION__);
3834510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    size_t length = mNamedIfds.size();
3844510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    for (size_t i = 0; i < length; ++i) {
3854510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        mNamedIfds[i]->log();
386e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
387e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
388e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
389e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk} /*namespace img_utils*/
390e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk} /*namespace android*/
391