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// #define LOG_NDEBUG 0
18
19#define LOG_TAG "Camera2-Metadata"
20#include <utils/Log.h>
21#include <utils/Errors.h>
22
23#include <binder/Parcel.h>
24#include <camera/CameraMetadata.h>
25#include <camera/VendorTagDescriptor.h>
26
27namespace android {
28
29#define ALIGN_TO(val, alignment) \
30    (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1))
31
32typedef Parcel::WritableBlob WritableBlob;
33typedef Parcel::ReadableBlob ReadableBlob;
34
35CameraMetadata::CameraMetadata() :
36        mBuffer(NULL), mLocked(false) {
37}
38
39CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) :
40        mLocked(false)
41{
42    mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
43}
44
45CameraMetadata::CameraMetadata(const CameraMetadata &other) :
46        mLocked(false) {
47    mBuffer = clone_camera_metadata(other.mBuffer);
48}
49
50CameraMetadata::CameraMetadata(camera_metadata_t *buffer) :
51        mBuffer(NULL), mLocked(false) {
52    acquire(buffer);
53}
54
55CameraMetadata &CameraMetadata::operator=(const CameraMetadata &other) {
56    return operator=(other.mBuffer);
57}
58
59CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) {
60    if (mLocked) {
61        ALOGE("%s: Assignment to a locked CameraMetadata!", __FUNCTION__);
62        return *this;
63    }
64
65    if (CC_LIKELY(buffer != mBuffer)) {
66        camera_metadata_t *newBuffer = clone_camera_metadata(buffer);
67        clear();
68        mBuffer = newBuffer;
69    }
70    return *this;
71}
72
73CameraMetadata::~CameraMetadata() {
74    mLocked = false;
75    clear();
76}
77
78const camera_metadata_t* CameraMetadata::getAndLock() const {
79    mLocked = true;
80    return mBuffer;
81}
82
83status_t CameraMetadata::unlock(const camera_metadata_t *buffer) const {
84    if (!mLocked) {
85        ALOGE("%s: Can't unlock a non-locked CameraMetadata!", __FUNCTION__);
86        return INVALID_OPERATION;
87    }
88    if (buffer != mBuffer) {
89        ALOGE("%s: Can't unlock CameraMetadata with wrong pointer!",
90                __FUNCTION__);
91        return BAD_VALUE;
92    }
93    mLocked = false;
94    return OK;
95}
96
97camera_metadata_t* CameraMetadata::release() {
98    if (mLocked) {
99        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
100        return NULL;
101    }
102    camera_metadata_t *released = mBuffer;
103    mBuffer = NULL;
104    return released;
105}
106
107void CameraMetadata::clear() {
108    if (mLocked) {
109        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
110        return;
111    }
112    if (mBuffer) {
113        free_camera_metadata(mBuffer);
114        mBuffer = NULL;
115    }
116}
117
118void CameraMetadata::acquire(camera_metadata_t *buffer) {
119    if (mLocked) {
120        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
121        return;
122    }
123    clear();
124    mBuffer = buffer;
125
126    ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) != OK,
127             "%s: Failed to validate metadata structure %p",
128             __FUNCTION__, buffer);
129}
130
131void CameraMetadata::acquire(CameraMetadata &other) {
132    if (mLocked) {
133        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
134        return;
135    }
136    acquire(other.release());
137}
138
139status_t CameraMetadata::append(const CameraMetadata &other) {
140    return append(other.mBuffer);
141}
142
143status_t CameraMetadata::append(const camera_metadata_t* other) {
144    if (mLocked) {
145        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
146        return INVALID_OPERATION;
147    }
148    size_t extraEntries = get_camera_metadata_entry_count(other);
149    size_t extraData = get_camera_metadata_data_count(other);
150    resizeIfNeeded(extraEntries, extraData);
151
152    return append_camera_metadata(mBuffer, other);
153}
154
155size_t CameraMetadata::entryCount() const {
156    return (mBuffer == NULL) ? 0 :
157            get_camera_metadata_entry_count(mBuffer);
158}
159
160bool CameraMetadata::isEmpty() const {
161    return entryCount() == 0;
162}
163
164status_t CameraMetadata::sort() {
165    if (mLocked) {
166        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
167        return INVALID_OPERATION;
168    }
169    return sort_camera_metadata(mBuffer);
170}
171
172status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) {
173    int tagType = get_camera_metadata_tag_type(tag);
174    if ( CC_UNLIKELY(tagType == -1)) {
175        ALOGE("Update metadata entry: Unknown tag %d", tag);
176        return INVALID_OPERATION;
177    }
178    if ( CC_UNLIKELY(tagType != expectedType) ) {
179        ALOGE("Mismatched tag type when updating entry %s (%d) of type %s; "
180                "got type %s data instead ",
181                get_camera_metadata_tag_name(tag), tag,
182                camera_metadata_type_names[tagType],
183                camera_metadata_type_names[expectedType]);
184        return INVALID_OPERATION;
185    }
186    return OK;
187}
188
189status_t CameraMetadata::update(uint32_t tag,
190        const int32_t *data, size_t data_count) {
191    status_t res;
192    if (mLocked) {
193        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
194        return INVALID_OPERATION;
195    }
196    if ( (res = checkType(tag, TYPE_INT32)) != OK) {
197        return res;
198    }
199    return updateImpl(tag, (const void*)data, data_count);
200}
201
202status_t CameraMetadata::update(uint32_t tag,
203        const uint8_t *data, size_t data_count) {
204    status_t res;
205    if (mLocked) {
206        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
207        return INVALID_OPERATION;
208    }
209    if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
210        return res;
211    }
212    return updateImpl(tag, (const void*)data, data_count);
213}
214
215status_t CameraMetadata::update(uint32_t tag,
216        const float *data, size_t data_count) {
217    status_t res;
218    if (mLocked) {
219        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
220        return INVALID_OPERATION;
221    }
222    if ( (res = checkType(tag, TYPE_FLOAT)) != OK) {
223        return res;
224    }
225    return updateImpl(tag, (const void*)data, data_count);
226}
227
228status_t CameraMetadata::update(uint32_t tag,
229        const int64_t *data, size_t data_count) {
230    status_t res;
231    if (mLocked) {
232        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
233        return INVALID_OPERATION;
234    }
235    if ( (res = checkType(tag, TYPE_INT64)) != OK) {
236        return res;
237    }
238    return updateImpl(tag, (const void*)data, data_count);
239}
240
241status_t CameraMetadata::update(uint32_t tag,
242        const double *data, size_t data_count) {
243    status_t res;
244    if (mLocked) {
245        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
246        return INVALID_OPERATION;
247    }
248    if ( (res = checkType(tag, TYPE_DOUBLE)) != OK) {
249        return res;
250    }
251    return updateImpl(tag, (const void*)data, data_count);
252}
253
254status_t CameraMetadata::update(uint32_t tag,
255        const camera_metadata_rational_t *data, size_t data_count) {
256    status_t res;
257    if (mLocked) {
258        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
259        return INVALID_OPERATION;
260    }
261    if ( (res = checkType(tag, TYPE_RATIONAL)) != OK) {
262        return res;
263    }
264    return updateImpl(tag, (const void*)data, data_count);
265}
266
267status_t CameraMetadata::update(uint32_t tag,
268        const String8 &string) {
269    status_t res;
270    if (mLocked) {
271        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
272        return INVALID_OPERATION;
273    }
274    if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
275        return res;
276    }
277    // string.size() doesn't count the null termination character.
278    return updateImpl(tag, (const void*)string.string(), string.size() + 1);
279}
280
281status_t CameraMetadata::update(const camera_metadata_ro_entry &entry) {
282    status_t res;
283    if (mLocked) {
284        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
285        return INVALID_OPERATION;
286    }
287    if ( (res = checkType(entry.tag, entry.type)) != OK) {
288        return res;
289    }
290    return updateImpl(entry.tag, (const void*)entry.data.u8, entry.count);
291}
292
293status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
294        size_t data_count) {
295    status_t res;
296    if (mLocked) {
297        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
298        return INVALID_OPERATION;
299    }
300    int type = get_camera_metadata_tag_type(tag);
301    if (type == -1) {
302        ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
303        return BAD_VALUE;
304    }
305    // Safety check - ensure that data isn't pointing to this metadata, since
306    // that would get invalidated if a resize is needed
307    size_t bufferSize = get_camera_metadata_size(mBuffer);
308    uintptr_t bufAddr = reinterpret_cast<uintptr_t>(mBuffer);
309    uintptr_t dataAddr = reinterpret_cast<uintptr_t>(data);
310    if (dataAddr > bufAddr && dataAddr < (bufAddr + bufferSize)) {
311        ALOGE("%s: Update attempted with data from the same metadata buffer!",
312                __FUNCTION__);
313        return INVALID_OPERATION;
314    }
315
316    size_t data_size = calculate_camera_metadata_entry_data_size(type,
317            data_count);
318
319    res = resizeIfNeeded(1, data_size);
320
321    if (res == OK) {
322        camera_metadata_entry_t entry;
323        res = find_camera_metadata_entry(mBuffer, tag, &entry);
324        if (res == NAME_NOT_FOUND) {
325            res = add_camera_metadata_entry(mBuffer,
326                    tag, data, data_count);
327        } else if (res == OK) {
328            res = update_camera_metadata_entry(mBuffer,
329                    entry.index, data, data_count, NULL);
330        }
331    }
332
333    if (res != OK) {
334        ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)",
335                __FUNCTION__, get_camera_metadata_section_name(tag),
336                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
337    }
338
339    IF_ALOGV() {
340        ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) !=
341                 OK,
342
343                 "%s: Failed to validate metadata structure after update %p",
344                 __FUNCTION__, mBuffer);
345    }
346
347    return res;
348}
349
350bool CameraMetadata::exists(uint32_t tag) const {
351    camera_metadata_ro_entry entry;
352    return find_camera_metadata_ro_entry(mBuffer, tag, &entry) == 0;
353}
354
355camera_metadata_entry_t CameraMetadata::find(uint32_t tag) {
356    status_t res;
357    camera_metadata_entry entry;
358    if (mLocked) {
359        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
360        entry.count = 0;
361        return entry;
362    }
363    res = find_camera_metadata_entry(mBuffer, tag, &entry);
364    if (CC_UNLIKELY( res != OK )) {
365        entry.count = 0;
366        entry.data.u8 = NULL;
367    }
368    return entry;
369}
370
371camera_metadata_ro_entry_t CameraMetadata::find(uint32_t tag) const {
372    status_t res;
373    camera_metadata_ro_entry entry;
374    res = find_camera_metadata_ro_entry(mBuffer, tag, &entry);
375    if (CC_UNLIKELY( res != OK )) {
376        entry.count = 0;
377        entry.data.u8 = NULL;
378    }
379    return entry;
380}
381
382status_t CameraMetadata::erase(uint32_t tag) {
383    camera_metadata_entry_t entry;
384    status_t res;
385    if (mLocked) {
386        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
387        return INVALID_OPERATION;
388    }
389    res = find_camera_metadata_entry(mBuffer, tag, &entry);
390    if (res == NAME_NOT_FOUND) {
391        return OK;
392    } else if (res != OK) {
393        ALOGE("%s: Error looking for entry %s.%s (%x): %s %d",
394                __FUNCTION__,
395                get_camera_metadata_section_name(tag),
396                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
397        return res;
398    }
399    res = delete_camera_metadata_entry(mBuffer, entry.index);
400    if (res != OK) {
401        ALOGE("%s: Error deleting entry %s.%s (%x): %s %d",
402                __FUNCTION__,
403                get_camera_metadata_section_name(tag),
404                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
405    }
406    return res;
407}
408
409void CameraMetadata::dump(int fd, int verbosity, int indentation) const {
410    dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation);
411}
412
413status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) {
414    if (mBuffer == NULL) {
415        mBuffer = allocate_camera_metadata(extraEntries * 2, extraData * 2);
416        if (mBuffer == NULL) {
417            ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
418            return NO_MEMORY;
419        }
420    } else {
421        size_t currentEntryCount = get_camera_metadata_entry_count(mBuffer);
422        size_t currentEntryCap = get_camera_metadata_entry_capacity(mBuffer);
423        size_t newEntryCount = currentEntryCount +
424                extraEntries;
425        newEntryCount = (newEntryCount > currentEntryCap) ?
426                newEntryCount * 2 : currentEntryCap;
427
428        size_t currentDataCount = get_camera_metadata_data_count(mBuffer);
429        size_t currentDataCap = get_camera_metadata_data_capacity(mBuffer);
430        size_t newDataCount = currentDataCount +
431                extraData;
432        newDataCount = (newDataCount > currentDataCap) ?
433                newDataCount * 2 : currentDataCap;
434
435        if (newEntryCount > currentEntryCap ||
436                newDataCount > currentDataCap) {
437            camera_metadata_t *oldBuffer = mBuffer;
438            mBuffer = allocate_camera_metadata(newEntryCount,
439                    newDataCount);
440            if (mBuffer == NULL) {
441                ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
442                return NO_MEMORY;
443            }
444            append_camera_metadata(mBuffer, oldBuffer);
445            free_camera_metadata(oldBuffer);
446        }
447    }
448    return OK;
449}
450
451status_t CameraMetadata::readFromParcel(const Parcel& data,
452                                        camera_metadata_t** out) {
453
454    status_t err = OK;
455
456    camera_metadata_t* metadata = NULL;
457
458    if (out) {
459        *out = NULL;
460    }
461
462    // See CameraMetadata::writeToParcel for parcel data layout diagram and explanation.
463    // arg0 = blobSize (int32)
464    int32_t blobSizeTmp = -1;
465    if ((err = data.readInt32(&blobSizeTmp)) != OK) {
466        ALOGE("%s: Failed to read metadata size (error %d %s)",
467              __FUNCTION__, err, strerror(-err));
468        return err;
469    }
470    const size_t blobSize = static_cast<size_t>(blobSizeTmp);
471    const size_t alignment = get_camera_metadata_alignment();
472
473    // Special case: zero blob size means zero sized (NULL) metadata.
474    if (blobSize == 0) {
475        ALOGV("%s: Read 0-sized metadata", __FUNCTION__);
476        return OK;
477    }
478
479    if (blobSize <= alignment) {
480        ALOGE("%s: metadata blob is malformed, blobSize(%zu) should be larger than alignment(%zu)",
481                __FUNCTION__, blobSize, alignment);
482        return BAD_VALUE;
483    }
484
485    const size_t metadataSize = blobSize - alignment;
486
487    // NOTE: this doesn't make sense to me. shouldn't the blob
488    // know how big it is? why do we have to specify the size
489    // to Parcel::readBlob ?
490    ReadableBlob blob;
491    // arg1 = metadata (blob)
492    do {
493        if ((err = data.readBlob(blobSize, &blob)) != OK) {
494            ALOGE("%s: Failed to read metadata blob (sized %zu). Possible "
495                  " serialization bug. Error %d %s",
496                  __FUNCTION__, blobSize, err, strerror(-err));
497            break;
498        }
499
500        // arg2 = offset (blob)
501        // Must be after blob since we don't know offset until after writeBlob.
502        int32_t offsetTmp;
503        if ((err = data.readInt32(&offsetTmp)) != OK) {
504            ALOGE("%s: Failed to read metadata offsetTmp (error %d %s)",
505                  __FUNCTION__, err, strerror(-err));
506            break;
507        }
508        const size_t offset = static_cast<size_t>(offsetTmp);
509        if (offset >= alignment) {
510            ALOGE("%s: metadata offset(%zu) should be less than alignment(%zu)",
511                    __FUNCTION__, blobSize, alignment);
512            err = BAD_VALUE;
513            break;
514        }
515
516        const uintptr_t metadataStart = reinterpret_cast<uintptr_t>(blob.data()) + offset;
517        const camera_metadata_t* tmp =
518                       reinterpret_cast<const camera_metadata_t*>(metadataStart);
519        ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu",
520                __FUNCTION__, alignment, tmp, offset);
521        metadata = allocate_copy_camera_metadata_checked(tmp, metadataSize);
522        if (metadata == NULL) {
523            // We consider that allocation only fails if the validation
524            // also failed, therefore the readFromParcel was a failure.
525            ALOGE("%s: metadata allocation and copy failed", __FUNCTION__);
526            err = BAD_VALUE;
527        }
528    } while(0);
529    blob.release();
530
531    if (out) {
532        ALOGV("%s: Set out metadata to %p", __FUNCTION__, metadata);
533        *out = metadata;
534    } else if (metadata != NULL) {
535        ALOGV("%s: Freed camera metadata at %p", __FUNCTION__, metadata);
536        free_camera_metadata(metadata);
537    }
538
539    return err;
540}
541
542status_t CameraMetadata::writeToParcel(Parcel& data,
543                                       const camera_metadata_t* metadata) {
544    status_t res = OK;
545
546    /**
547     * Below is the camera metadata parcel layout:
548     *
549     * |--------------------------------------------|
550     * |             arg0: blobSize                 |
551     * |              (length = 4)                  |
552     * |--------------------------------------------|<--Skip the rest if blobSize == 0.
553     * |                                            |
554     * |                                            |
555     * |              arg1: blob                    |
556     * | (length = variable, see arg1 layout below) |
557     * |                                            |
558     * |                                            |
559     * |--------------------------------------------|
560     * |              arg2: offset                  |
561     * |              (length = 4)                  |
562     * |--------------------------------------------|
563     */
564
565    // arg0 = blobSize (int32)
566    if (metadata == NULL) {
567        // Write zero blobSize for null metadata.
568        return data.writeInt32(0);
569    }
570
571    /**
572     * Always make the blob size sufficiently larger, as we need put alignment
573     * padding and metadata into the blob. Since we don't know the alignment
574     * offset before writeBlob. Then write the metadata to aligned offset.
575     */
576    const size_t metadataSize = get_camera_metadata_compact_size(metadata);
577    const size_t alignment = get_camera_metadata_alignment();
578    const size_t blobSize = metadataSize + alignment;
579    res = data.writeInt32(static_cast<int32_t>(blobSize));
580    if (res != OK) {
581        return res;
582    }
583
584    size_t offset = 0;
585    /**
586     * arg1 = metadata (blob).
587     *
588     * The blob size is the sum of front padding size, metadata size and back padding
589     * size, which is equal to metadataSize + alignment.
590     *
591     * The blob layout is:
592     * |------------------------------------|<----Start address of the blob (unaligned).
593     * |           front padding            |
594     * |          (size = offset)           |
595     * |------------------------------------|<----Aligned start address of metadata.
596     * |                                    |
597     * |                                    |
598     * |            metadata                |
599     * |       (size = metadataSize)        |
600     * |                                    |
601     * |                                    |
602     * |------------------------------------|
603     * |           back padding             |
604     * |     (size = alignment - offset)    |
605     * |------------------------------------|<----End address of blob.
606     *                                            (Blob start address + blob size).
607     */
608    WritableBlob blob;
609    do {
610        res = data.writeBlob(blobSize, false, &blob);
611        if (res != OK) {
612            break;
613        }
614        const uintptr_t metadataStart = ALIGN_TO(blob.data(), alignment);
615        offset = metadataStart - reinterpret_cast<uintptr_t>(blob.data());
616        ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu",
617                __FUNCTION__, alignment,
618                reinterpret_cast<const void *>(metadataStart), offset);
619        copy_camera_metadata(reinterpret_cast<void*>(metadataStart), metadataSize, metadata);
620
621        // Not too big of a problem since receiving side does hard validation
622        // Don't check the size since the compact size could be larger
623        if (validate_camera_metadata_structure(metadata, /*size*/NULL) != OK) {
624            ALOGW("%s: Failed to validate metadata %p before writing blob",
625                   __FUNCTION__, metadata);
626        }
627
628    } while(false);
629    blob.release();
630
631    // arg2 = offset (int32)
632    res = data.writeInt32(static_cast<int32_t>(offset));
633
634    return res;
635}
636
637status_t CameraMetadata::readFromParcel(const Parcel *parcel) {
638
639    ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
640
641    status_t res = OK;
642
643    if (parcel == NULL) {
644        ALOGE("%s: parcel is null", __FUNCTION__);
645        return BAD_VALUE;
646    }
647
648    if (mLocked) {
649        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
650        return INVALID_OPERATION;
651    }
652
653    camera_metadata *buffer = NULL;
654    // TODO: reading should return a status code, in case validation fails
655    res = CameraMetadata::readFromParcel(*parcel, &buffer);
656
657    if (res != NO_ERROR) {
658        ALOGE("%s: Failed to read from parcel. Metadata is unchanged.",
659              __FUNCTION__);
660        return res;
661    }
662
663    clear();
664    mBuffer = buffer;
665
666    return OK;
667}
668
669status_t CameraMetadata::writeToParcel(Parcel *parcel) const {
670
671    ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
672
673    if (parcel == NULL) {
674        ALOGE("%s: parcel is null", __FUNCTION__);
675        return BAD_VALUE;
676    }
677
678    return CameraMetadata::writeToParcel(*parcel, mBuffer);
679}
680
681void CameraMetadata::swap(CameraMetadata& other) {
682    if (mLocked) {
683        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
684        return;
685    } else if (other.mLocked) {
686        ALOGE("%s: Other CameraMetadata is locked", __FUNCTION__);
687        return;
688    }
689
690    camera_metadata* thisBuf = mBuffer;
691    camera_metadata* otherBuf = other.mBuffer;
692
693    other.mBuffer = thisBuf;
694    mBuffer = otherBuf;
695}
696
697status_t CameraMetadata::getTagFromName(const char *name,
698        const VendorTagDescriptor* vTags, uint32_t *tag) {
699
700    if (name == nullptr || tag == nullptr) return BAD_VALUE;
701
702    size_t nameLength = strlen(name);
703
704    const SortedVector<String8> *vendorSections;
705    size_t vendorSectionCount = 0;
706
707    if (vTags != NULL) {
708        vendorSections = vTags->getAllSectionNames();
709        vendorSectionCount = vendorSections->size();
710    }
711
712    // First, find the section by the longest string match
713    const char *section = NULL;
714    size_t sectionIndex = 0;
715    size_t sectionLength = 0;
716    size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
717    for (size_t i = 0; i < totalSectionCount; ++i) {
718
719        const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
720                (*vendorSections)[i - ANDROID_SECTION_COUNT].string();
721
722        ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
723
724        if (strstr(name, str) == name) { // name begins with the section name
725            size_t strLength = strlen(str);
726
727            ALOGV("%s: Name begins with section name", __FUNCTION__);
728
729            // section name is the longest we've found so far
730            if (section == NULL || sectionLength < strLength) {
731                section = str;
732                sectionIndex = i;
733                sectionLength = strLength;
734
735                ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
736            }
737        }
738    }
739
740    // TODO: Make above get_camera_metadata_section_from_name ?
741
742    if (section == NULL) {
743        return NAME_NOT_FOUND;
744    } else {
745        ALOGV("%s: Found matched section '%s' (%zu)",
746              __FUNCTION__, section, sectionIndex);
747    }
748
749    // Get the tag name component of the name
750    const char *nameTagName = name + sectionLength + 1; // x.y.z -> z
751    if (sectionLength + 1 >= nameLength) {
752        return BAD_VALUE;
753    }
754
755    // Match rest of name against the tag names in that section only
756    uint32_t candidateTag = 0;
757    if (sectionIndex < ANDROID_SECTION_COUNT) {
758        // Match built-in tags (typically android.*)
759        uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
760        tagBegin = camera_metadata_section_bounds[sectionIndex][0];
761        tagEnd = camera_metadata_section_bounds[sectionIndex][1];
762
763        for (candidateTag = tagBegin; candidateTag < tagEnd; ++candidateTag) {
764            const char *tagName = get_camera_metadata_tag_name(candidateTag);
765
766            if (strcmp(nameTagName, tagName) == 0) {
767                ALOGV("%s: Found matched tag '%s' (%d)",
768                      __FUNCTION__, tagName, candidateTag);
769                break;
770            }
771        }
772
773        if (candidateTag == tagEnd) {
774            return NAME_NOT_FOUND;
775        }
776    } else if (vTags != NULL) {
777        // Match vendor tags (typically com.*)
778        const String8 sectionName(section);
779        const String8 tagName(nameTagName);
780
781        status_t res = OK;
782        if ((res = vTags->lookupTag(tagName, sectionName, &candidateTag)) != OK) {
783            return NAME_NOT_FOUND;
784        }
785    }
786
787    *tag = candidateTag;
788    return OK;
789}
790
791
792}; // namespace android
793