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 <utils/Log.h>
20
21#include <stdlib.h>
22#include <string.h>
23
24#include <media/stagefright/foundation/ADebug.h>
25#include <media/stagefright/foundation/AString.h>
26#include <media/stagefright/foundation/hexdump.h>
27#include <media/stagefright/MetaData.h>
28
29namespace android {
30
31MetaData::MetaData() {
32}
33
34MetaData::MetaData(const MetaData &from)
35    : RefBase(),
36      mItems(from.mItems) {
37}
38
39MetaData::~MetaData() {
40    clear();
41}
42
43void MetaData::clear() {
44    mItems.clear();
45}
46
47bool MetaData::remove(uint32_t key) {
48    ssize_t i = mItems.indexOfKey(key);
49
50    if (i < 0) {
51        return false;
52    }
53
54    mItems.removeItemsAt(i);
55
56    return true;
57}
58
59bool MetaData::setCString(uint32_t key, const char *value) {
60    return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
61}
62
63bool MetaData::setInt32(uint32_t key, int32_t value) {
64    return setData(key, TYPE_INT32, &value, sizeof(value));
65}
66
67bool MetaData::setInt64(uint32_t key, int64_t value) {
68    return setData(key, TYPE_INT64, &value, sizeof(value));
69}
70
71bool MetaData::setFloat(uint32_t key, float value) {
72    return setData(key, TYPE_FLOAT, &value, sizeof(value));
73}
74
75bool MetaData::setPointer(uint32_t key, void *value) {
76    return setData(key, TYPE_POINTER, &value, sizeof(value));
77}
78
79bool MetaData::setRect(
80        uint32_t key,
81        int32_t left, int32_t top,
82        int32_t right, int32_t bottom) {
83    Rect r;
84    r.mLeft = left;
85    r.mTop = top;
86    r.mRight = right;
87    r.mBottom = bottom;
88
89    return setData(key, TYPE_RECT, &r, sizeof(r));
90}
91
92bool MetaData::findCString(uint32_t key, const char **value) {
93    uint32_t type;
94    const void *data;
95    size_t size;
96    if (!findData(key, &type, &data, &size) || type != TYPE_C_STRING) {
97        return false;
98    }
99
100    *value = (const char *)data;
101
102    return true;
103}
104
105bool MetaData::findInt32(uint32_t key, int32_t *value) {
106    uint32_t type;
107    const void *data;
108    size_t size;
109    if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
110        return false;
111    }
112
113    CHECK_EQ(size, sizeof(*value));
114
115    *value = *(int32_t *)data;
116
117    return true;
118}
119
120bool MetaData::findInt64(uint32_t key, int64_t *value) {
121    uint32_t type;
122    const void *data;
123    size_t size;
124    if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
125        return false;
126    }
127
128    CHECK_EQ(size, sizeof(*value));
129
130    *value = *(int64_t *)data;
131
132    return true;
133}
134
135bool MetaData::findFloat(uint32_t key, float *value) {
136    uint32_t type;
137    const void *data;
138    size_t size;
139    if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
140        return false;
141    }
142
143    CHECK_EQ(size, sizeof(*value));
144
145    *value = *(float *)data;
146
147    return true;
148}
149
150bool MetaData::findPointer(uint32_t key, void **value) {
151    uint32_t type;
152    const void *data;
153    size_t size;
154    if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
155        return false;
156    }
157
158    CHECK_EQ(size, sizeof(*value));
159
160    *value = *(void **)data;
161
162    return true;
163}
164
165bool MetaData::findRect(
166        uint32_t key,
167        int32_t *left, int32_t *top,
168        int32_t *right, int32_t *bottom) {
169    uint32_t type;
170    const void *data;
171    size_t size;
172    if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
173        return false;
174    }
175
176    CHECK_EQ(size, sizeof(Rect));
177
178    const Rect *r = (const Rect *)data;
179    *left = r->mLeft;
180    *top = r->mTop;
181    *right = r->mRight;
182    *bottom = r->mBottom;
183
184    return true;
185}
186
187bool MetaData::setData(
188        uint32_t key, uint32_t type, const void *data, size_t size) {
189    bool overwrote_existing = true;
190
191    ssize_t i = mItems.indexOfKey(key);
192    if (i < 0) {
193        typed_data item;
194        i = mItems.add(key, item);
195
196        overwrote_existing = false;
197    }
198
199    typed_data &item = mItems.editValueAt(i);
200
201    item.setData(type, data, size);
202
203    return overwrote_existing;
204}
205
206bool MetaData::findData(uint32_t key, uint32_t *type,
207                        const void **data, size_t *size) const {
208    ssize_t i = mItems.indexOfKey(key);
209
210    if (i < 0) {
211        return false;
212    }
213
214    const typed_data &item = mItems.valueAt(i);
215
216    item.getData(type, data, size);
217
218    return true;
219}
220
221MetaData::typed_data::typed_data()
222    : mType(0),
223      mSize(0) {
224}
225
226MetaData::typed_data::~typed_data() {
227    clear();
228}
229
230MetaData::typed_data::typed_data(const typed_data &from)
231    : mType(from.mType),
232      mSize(0) {
233    allocateStorage(from.mSize);
234    memcpy(storage(), from.storage(), mSize);
235}
236
237MetaData::typed_data &MetaData::typed_data::operator=(
238        const MetaData::typed_data &from) {
239    if (this != &from) {
240        clear();
241        mType = from.mType;
242        allocateStorage(from.mSize);
243        memcpy(storage(), from.storage(), mSize);
244    }
245
246    return *this;
247}
248
249void MetaData::typed_data::clear() {
250    freeStorage();
251
252    mType = 0;
253}
254
255void MetaData::typed_data::setData(
256        uint32_t type, const void *data, size_t size) {
257    clear();
258
259    mType = type;
260    allocateStorage(size);
261    memcpy(storage(), data, size);
262}
263
264void MetaData::typed_data::getData(
265        uint32_t *type, const void **data, size_t *size) const {
266    *type = mType;
267    *size = mSize;
268    *data = storage();
269}
270
271void MetaData::typed_data::allocateStorage(size_t size) {
272    mSize = size;
273
274    if (usesReservoir()) {
275        return;
276    }
277
278    u.ext_data = malloc(mSize);
279}
280
281void MetaData::typed_data::freeStorage() {
282    if (!usesReservoir()) {
283        if (u.ext_data) {
284            free(u.ext_data);
285        }
286    }
287
288    mSize = 0;
289}
290
291String8 MetaData::typed_data::asString() const {
292    String8 out;
293    const void *data = storage();
294    switch(mType) {
295        case TYPE_NONE:
296            out = String8::format("no type, size %d)", mSize);
297            break;
298        case TYPE_C_STRING:
299            out = String8::format("(char*) %s", (const char *)data);
300            break;
301        case TYPE_INT32:
302            out = String8::format("(int32_t) %d", *(int32_t *)data);
303            break;
304        case TYPE_INT64:
305            out = String8::format("(int64_t) %lld", *(int64_t *)data);
306            break;
307        case TYPE_FLOAT:
308            out = String8::format("(float) %f", *(float *)data);
309            break;
310        case TYPE_POINTER:
311            out = String8::format("(void*) %p", *(void **)data);
312            break;
313        case TYPE_RECT:
314        {
315            const Rect *r = (const Rect *)data;
316            out = String8::format("Rect(%d, %d, %d, %d)",
317                                  r->mLeft, r->mTop, r->mRight, r->mBottom);
318            break;
319        }
320
321        default:
322            out = String8::format("(unknown type %d, size %d)", mType, mSize);
323            if (mSize <= 48) { // if it's less than three lines of hex data, dump it
324                AString foo;
325                hexdump(data, mSize, 0, &foo);
326                out.append("\n");
327                out.append(foo.c_str());
328            }
329            break;
330    }
331    return out;
332}
333
334static void MakeFourCCString(uint32_t x, char *s) {
335    s[0] = x >> 24;
336    s[1] = (x >> 16) & 0xff;
337    s[2] = (x >> 8) & 0xff;
338    s[3] = x & 0xff;
339    s[4] = '\0';
340}
341
342void MetaData::dumpToLog() const {
343    for (int i = mItems.size(); --i >= 0;) {
344        int32_t key = mItems.keyAt(i);
345        char cc[5];
346        MakeFourCCString(key, cc);
347        const typed_data &item = mItems.valueAt(i);
348        ALOGI("%s: %s", cc, item.asString().string());
349    }
350}
351
352}  // namespace android
353
354