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;
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;
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;
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;
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;
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    allocateStorage(from.mSize);
248    memcpy(storage(), from.storage(), mSize);
249}
250
251MetaData::typed_data &MetaData::typed_data::operator=(
252        const MetaData::typed_data &from) {
253    if (this != &from) {
254        clear();
255        mType = from.mType;
256        allocateStorage(from.mSize);
257        memcpy(storage(), from.storage(), mSize);
258    }
259
260    return *this;
261}
262
263void MetaData::typed_data::clear() {
264    freeStorage();
265
266    mType = 0;
267}
268
269void MetaData::typed_data::setData(
270        uint32_t type, const void *data, size_t size) {
271    clear();
272
273    mType = type;
274    allocateStorage(size);
275    memcpy(storage(), data, size);
276}
277
278void MetaData::typed_data::getData(
279        uint32_t *type, const void **data, size_t *size) const {
280    *type = mType;
281    *size = mSize;
282    *data = storage();
283}
284
285void MetaData::typed_data::allocateStorage(size_t size) {
286    mSize = size;
287
288    if (usesReservoir()) {
289        return;
290    }
291
292    u.ext_data = malloc(mSize);
293}
294
295void MetaData::typed_data::freeStorage() {
296    if (!usesReservoir()) {
297        if (u.ext_data) {
298            free(u.ext_data);
299            u.ext_data = NULL;
300        }
301    }
302
303    mSize = 0;
304}
305
306String8 MetaData::typed_data::asString() const {
307    String8 out;
308    const void *data = storage();
309    switch(mType) {
310        case TYPE_NONE:
311            out = String8::format("no type, size %zu)", mSize);
312            break;
313        case TYPE_C_STRING:
314            out = String8::format("(char*) %s", (const char *)data);
315            break;
316        case TYPE_INT32:
317            out = String8::format("(int32_t) %d", *(int32_t *)data);
318            break;
319        case TYPE_INT64:
320            out = String8::format("(int64_t) %" PRId64, *(int64_t *)data);
321            break;
322        case TYPE_FLOAT:
323            out = String8::format("(float) %f", *(float *)data);
324            break;
325        case TYPE_POINTER:
326            out = String8::format("(void*) %p", *(void **)data);
327            break;
328        case TYPE_RECT:
329        {
330            const Rect *r = (const Rect *)data;
331            out = String8::format("Rect(%d, %d, %d, %d)",
332                                  r->mLeft, r->mTop, r->mRight, r->mBottom);
333            break;
334        }
335
336        default:
337            out = String8::format("(unknown type %d, size %zu)", mType, mSize);
338            if (mSize <= 48) { // if it's less than three lines of hex data, dump it
339                AString foo;
340                hexdump(data, mSize, 0, &foo);
341                out.append("\n");
342                out.append(foo.c_str());
343            }
344            break;
345    }
346    return out;
347}
348
349static void MakeFourCCString(uint32_t x, char *s) {
350    s[0] = x >> 24;
351    s[1] = (x >> 16) & 0xff;
352    s[2] = (x >> 8) & 0xff;
353    s[3] = x & 0xff;
354    s[4] = '\0';
355}
356
357void MetaData::dumpToLog() const {
358    for (int i = mItems.size(); --i >= 0;) {
359        int32_t key = mItems.keyAt(i);
360        char cc[5];
361        MakeFourCCString(key, cc);
362        const typed_data &item = mItems.valueAt(i);
363        ALOGI("%s: %s", cc, item.asString().string());
364    }
365}
366
367}  // namespace android
368
369