1/*
2 * Copyright (C) 2009 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#define LOG_TAG "MetaData"
19#include <inttypes.h>
20#include <utils/Log.h>
21
22#include <stdlib.h>
23#include <string.h>
24
25#include <media/stagefright/foundation/ADebug.h>
26#include <media/stagefright/foundation/AString.h>
27#include <media/stagefright/foundation/hexdump.h>
28#include <media/stagefright/MetaData.h>
29
30namespace android {
31
32MetaData::MetaData() {
33}
34
35MetaData::MetaData(const MetaData &from)
36    : RefBase(),
37      mItems(from.mItems) {
38}
39
40MetaData::~MetaData() {
41    clear();
42}
43
44void MetaData::clear() {
45    mItems.clear();
46}
47
48bool MetaData::remove(uint32_t key) {
49    ssize_t i = mItems.indexOfKey(key);
50
51    if (i < 0) {
52        return false;
53    }
54
55    mItems.removeItemsAt(i);
56
57    return true;
58}
59
60bool MetaData::setCString(uint32_t key, const char *value) {
61    return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
62}
63
64bool MetaData::setInt32(uint32_t key, int32_t value) {
65    return setData(key, TYPE_INT32, &value, sizeof(value));
66}
67
68bool MetaData::setInt64(uint32_t key, int64_t value) {
69    return setData(key, TYPE_INT64, &value, sizeof(value));
70}
71
72bool MetaData::setFloat(uint32_t key, float value) {
73    return setData(key, TYPE_FLOAT, &value, sizeof(value));
74}
75
76bool MetaData::setPointer(uint32_t key, void *value) {
77    return setData(key, TYPE_POINTER, &value, sizeof(value));
78}
79
80bool MetaData::setRect(
81        uint32_t key,
82        int32_t left, int32_t top,
83        int32_t right, int32_t bottom) {
84    Rect r;
85    r.mLeft = left;
86    r.mTop = top;
87    r.mRight = right;
88    r.mBottom = bottom;
89
90    return setData(key, TYPE_RECT, &r, sizeof(r));
91}
92
93/**
94 * Note that the returned pointer becomes invalid when additional metadata is set.
95 */
96bool MetaData::findCString(uint32_t key, const char **value) {
97    uint32_t type;
98    const void *data;
99    size_t size;
100    if (!findData(key, &type, &data, &size) || type != TYPE_C_STRING) {
101        return false;
102    }
103
104    *value = (const char *)data;
105
106    return true;
107}
108
109bool MetaData::findInt32(uint32_t key, int32_t *value) {
110    uint32_t type = 0;
111    const void *data;
112    size_t size;
113    if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
114        return false;
115    }
116
117    CHECK_EQ(size, sizeof(*value));
118
119    *value = *(int32_t *)data;
120
121    return true;
122}
123
124bool MetaData::findInt64(uint32_t key, int64_t *value) {
125    uint32_t type = 0;
126    const void *data;
127    size_t size;
128    if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
129        return false;
130    }
131
132    CHECK_EQ(size, sizeof(*value));
133
134    *value = *(int64_t *)data;
135
136    return true;
137}
138
139bool MetaData::findFloat(uint32_t key, float *value) {
140    uint32_t type = 0;
141    const void *data;
142    size_t size;
143    if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
144        return false;
145    }
146
147    CHECK_EQ(size, sizeof(*value));
148
149    *value = *(float *)data;
150
151    return true;
152}
153
154bool MetaData::findPointer(uint32_t key, void **value) {
155    uint32_t type = 0;
156    const void *data;
157    size_t size;
158    if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
159        return false;
160    }
161
162    CHECK_EQ(size, sizeof(*value));
163
164    *value = *(void **)data;
165
166    return true;
167}
168
169bool MetaData::findRect(
170        uint32_t key,
171        int32_t *left, int32_t *top,
172        int32_t *right, int32_t *bottom) {
173    uint32_t type = 0;
174    const void *data;
175    size_t size;
176    if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
177        return false;
178    }
179
180    CHECK_EQ(size, sizeof(Rect));
181
182    const Rect *r = (const Rect *)data;
183    *left = r->mLeft;
184    *top = r->mTop;
185    *right = r->mRight;
186    *bottom = r->mBottom;
187
188    return true;
189}
190
191bool MetaData::setData(
192        uint32_t key, uint32_t type, const void *data, size_t size) {
193    bool overwrote_existing = true;
194
195    ssize_t i = mItems.indexOfKey(key);
196    if (i < 0) {
197        typed_data item;
198        i = mItems.add(key, item);
199
200        overwrote_existing = false;
201    }
202
203    typed_data &item = mItems.editValueAt(i);
204
205    item.setData(type, data, size);
206
207    return overwrote_existing;
208}
209
210bool MetaData::findData(uint32_t key, uint32_t *type,
211                        const void **data, size_t *size) const {
212    ssize_t i = mItems.indexOfKey(key);
213
214    if (i < 0) {
215        return false;
216    }
217
218    const typed_data &item = mItems.valueAt(i);
219
220    item.getData(type, data, size);
221
222    return true;
223}
224
225bool MetaData::hasData(uint32_t key) const {
226    ssize_t i = mItems.indexOfKey(key);
227
228    if (i < 0) {
229        return false;
230    }
231
232    return true;
233}
234
235MetaData::typed_data::typed_data()
236    : mType(0),
237      mSize(0) {
238}
239
240MetaData::typed_data::~typed_data() {
241    clear();
242}
243
244MetaData::typed_data::typed_data(const typed_data &from)
245    : mType(from.mType),
246      mSize(0) {
247
248    void *dst = allocateStorage(from.mSize);
249    if (dst) {
250        memcpy(dst, from.storage(), mSize);
251    }
252}
253
254MetaData::typed_data &MetaData::typed_data::operator=(
255        const MetaData::typed_data &from) {
256    if (this != &from) {
257        clear();
258        mType = from.mType;
259        void *dst = allocateStorage(from.mSize);
260        if (dst) {
261            memcpy(dst, from.storage(), mSize);
262        }
263    }
264
265    return *this;
266}
267
268void MetaData::typed_data::clear() {
269    freeStorage();
270
271    mType = 0;
272}
273
274void MetaData::typed_data::setData(
275        uint32_t type, const void *data, size_t size) {
276    clear();
277
278    mType = type;
279
280    void *dst = allocateStorage(size);
281    if (dst) {
282        memcpy(dst, data, size);
283    }
284}
285
286void MetaData::typed_data::getData(
287        uint32_t *type, const void **data, size_t *size) const {
288    *type = mType;
289    *size = mSize;
290    *data = storage();
291}
292
293void *MetaData::typed_data::allocateStorage(size_t size) {
294    mSize = size;
295
296    if (usesReservoir()) {
297        return &u.reservoir;
298    }
299
300    u.ext_data = malloc(mSize);
301    if (u.ext_data == NULL) {
302        ALOGE("Couldn't allocate %zu bytes for item", size);
303        mSize = 0;
304    }
305    return u.ext_data;
306}
307
308void MetaData::typed_data::freeStorage() {
309    if (!usesReservoir()) {
310        if (u.ext_data) {
311            free(u.ext_data);
312            u.ext_data = NULL;
313        }
314    }
315
316    mSize = 0;
317}
318
319String8 MetaData::typed_data::asString(bool verbose) const {
320    String8 out;
321    const void *data = storage();
322    switch(mType) {
323        case TYPE_NONE:
324            out = String8::format("no type, size %zu)", mSize);
325            break;
326        case TYPE_C_STRING:
327            out = String8::format("(char*) %s", (const char *)data);
328            break;
329        case TYPE_INT32:
330            out = String8::format("(int32_t) %d", *(int32_t *)data);
331            break;
332        case TYPE_INT64:
333            out = String8::format("(int64_t) %" PRId64, *(int64_t *)data);
334            break;
335        case TYPE_FLOAT:
336            out = String8::format("(float) %f", *(float *)data);
337            break;
338        case TYPE_POINTER:
339            out = String8::format("(void*) %p", *(void **)data);
340            break;
341        case TYPE_RECT:
342        {
343            const Rect *r = (const Rect *)data;
344            out = String8::format("Rect(%d, %d, %d, %d)",
345                                  r->mLeft, r->mTop, r->mRight, r->mBottom);
346            break;
347        }
348
349        default:
350            out = String8::format("(unknown type %d, size %zu)", mType, mSize);
351            if (verbose && mSize <= 48) { // if it's less than three lines of hex data, dump it
352                AString foo;
353                hexdump(data, mSize, 0, &foo);
354                out.append("\n");
355                out.append(foo.c_str());
356            }
357            break;
358    }
359    return out;
360}
361
362static void MakeFourCCString(uint32_t x, char *s) {
363    s[0] = x >> 24;
364    s[1] = (x >> 16) & 0xff;
365    s[2] = (x >> 8) & 0xff;
366    s[3] = x & 0xff;
367    s[4] = '\0';
368}
369
370String8 MetaData::toString() const {
371    String8 s;
372    for (int i = mItems.size(); --i >= 0;) {
373        int32_t key = mItems.keyAt(i);
374        char cc[5];
375        MakeFourCCString(key, cc);
376        const typed_data &item = mItems.valueAt(i);
377        s.appendFormat("%s: %s", cc, item.asString(false).string());
378        if (i != 0) {
379            s.append(", ");
380        }
381    }
382    return s;
383}
384void MetaData::dumpToLog() const {
385    for (int i = mItems.size(); --i >= 0;) {
386        int32_t key = mItems.keyAt(i);
387        char cc[5];
388        MakeFourCCString(key, cc);
389        const typed_data &item = mItems.valueAt(i);
390        ALOGI("%s: %s", cc, item.asString(true /* verbose */).string());
391    }
392}
393
394status_t MetaData::writeToParcel(Parcel &parcel) {
395    size_t numItems = mItems.size();
396    parcel.writeUint32(uint32_t(numItems));
397    for (size_t i = 0; i < numItems; i++) {
398        int32_t key = mItems.keyAt(i);
399        const typed_data &item = mItems.valueAt(i);
400        uint32_t type;
401        const void *data;
402        size_t size;
403        item.getData(&type, &data, &size);
404        parcel.writeInt32(key);
405        parcel.writeUint32(type);
406        parcel.writeByteArray(size, (uint8_t*)data);
407    }
408    return OK;
409}
410
411status_t MetaData::updateFromParcel(const Parcel &parcel) {
412    uint32_t numItems;
413    if (parcel.readUint32(&numItems) == OK) {
414
415        for (size_t i = 0; i < numItems; i++) {
416            int32_t key;
417            uint32_t type;
418            uint32_t size;
419            status_t ret = parcel.readInt32(&key);
420            ret |= parcel.readUint32(&type);
421            ret |= parcel.readUint32(&size);
422            if (ret != OK) {
423                break;
424            }
425            // copy data directly from Parcel storage, then advance position
426            setData(key, type, parcel.readInplace(size), size);
427         }
428
429        return OK;
430    }
431    ALOGW("no metadata in parcel");
432    return UNKNOWN_ERROR;
433}
434
435
436/* static */
437sp<MetaData> MetaData::createFromParcel(const Parcel &parcel) {
438
439    sp<MetaData> meta = new MetaData();
440    meta->updateFromParcel(parcel);
441    return meta;
442}
443
444
445
446}  // namespace android
447
448