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 "MetaDataBase"
19 #include <inttypes.h>
20 #include <utils/KeyedVector.h>
21 #include <utils/Log.h>
22 
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include <media/stagefright/foundation/ADebug.h>
27 #include <media/stagefright/foundation/AString.h>
28 #include <media/stagefright/foundation/hexdump.h>
29 #include <media/stagefright/MetaDataBase.h>
30 
31 #ifndef __ANDROID_VNDK__
32 #include <binder/Parcel.h>
33 #endif
34 
35 namespace android {
36 
37 struct MetaDataBase::typed_data {
38     typed_data();
39     ~typed_data();
40 
41     typed_data(const MetaDataBase::typed_data &);
42     typed_data &operator=(const MetaDataBase::typed_data &);
43 
44     void clear();
45     void setData(uint32_t type, const void *data, size_t size);
46     void getData(uint32_t *type, const void **data, size_t *size) const;
47     // may include hexdump of binary data if verbose=true
48     String8 asString(bool verbose) const;
49 
50 private:
51     uint32_t mType;
52     size_t mSize;
53 
54     union {
55         void *ext_data;
56         float reservoir;
57     } u;
58 
usesReservoirandroid::MetaDataBase::typed_data59     bool usesReservoir() const {
60         return mSize <= sizeof(u.reservoir);
61     }
62 
63     void *allocateStorage(size_t size);
64     void freeStorage();
65 
storageandroid::MetaDataBase::typed_data66     void *storage() {
67         return usesReservoir() ? &u.reservoir : u.ext_data;
68     }
69 
storageandroid::MetaDataBase::typed_data70     const void *storage() const {
71         return usesReservoir() ? &u.reservoir : u.ext_data;
72     }
73 };
74 
75 struct MetaDataBase::Rect {
76     int32_t mLeft, mTop, mRight, mBottom;
77 };
78 
79 
80 struct MetaDataBase::MetaDataInternal {
81     KeyedVector<uint32_t, MetaDataBase::typed_data> mItems;
82 };
83 
84 
MetaDataBase()85 MetaDataBase::MetaDataBase()
86     : mInternalData(new MetaDataInternal()) {
87 }
88 
MetaDataBase(const MetaDataBase & from)89 MetaDataBase::MetaDataBase(const MetaDataBase &from)
90     : mInternalData(new MetaDataInternal()) {
91     mInternalData->mItems = from.mInternalData->mItems;
92 }
93 
operator =(const MetaDataBase & rhs)94 MetaDataBase& MetaDataBase::operator = (const MetaDataBase &rhs) {
95     this->mInternalData->mItems = rhs.mInternalData->mItems;
96     return *this;
97 }
98 
~MetaDataBase()99 MetaDataBase::~MetaDataBase() {
100     clear();
101     delete mInternalData;
102 }
103 
clear()104 void MetaDataBase::clear() {
105     mInternalData->mItems.clear();
106 }
107 
remove(uint32_t key)108 bool MetaDataBase::remove(uint32_t key) {
109     ssize_t i = mInternalData->mItems.indexOfKey(key);
110 
111     if (i < 0) {
112         return false;
113     }
114 
115     mInternalData->mItems.removeItemsAt(i);
116 
117     return true;
118 }
119 
setCString(uint32_t key,const char * value)120 bool MetaDataBase::setCString(uint32_t key, const char *value) {
121     return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
122 }
123 
setInt32(uint32_t key,int32_t value)124 bool MetaDataBase::setInt32(uint32_t key, int32_t value) {
125     return setData(key, TYPE_INT32, &value, sizeof(value));
126 }
127 
setInt64(uint32_t key,int64_t value)128 bool MetaDataBase::setInt64(uint32_t key, int64_t value) {
129     return setData(key, TYPE_INT64, &value, sizeof(value));
130 }
131 
setFloat(uint32_t key,float value)132 bool MetaDataBase::setFloat(uint32_t key, float value) {
133     return setData(key, TYPE_FLOAT, &value, sizeof(value));
134 }
135 
setPointer(uint32_t key,void * value)136 bool MetaDataBase::setPointer(uint32_t key, void *value) {
137     return setData(key, TYPE_POINTER, &value, sizeof(value));
138 }
139 
setRect(uint32_t key,int32_t left,int32_t top,int32_t right,int32_t bottom)140 bool MetaDataBase::setRect(
141         uint32_t key,
142         int32_t left, int32_t top,
143         int32_t right, int32_t bottom) {
144     Rect r;
145     r.mLeft = left;
146     r.mTop = top;
147     r.mRight = right;
148     r.mBottom = bottom;
149 
150     return setData(key, TYPE_RECT, &r, sizeof(r));
151 }
152 
153 /**
154  * Note that the returned pointer becomes invalid when additional metadata is set.
155  */
findCString(uint32_t key,const char ** value) const156 bool MetaDataBase::findCString(uint32_t key, const char **value) const {
157     uint32_t type;
158     const void *data;
159     size_t size;
160     if (!findData(key, &type, &data, &size) || type != TYPE_C_STRING) {
161         return false;
162     }
163 
164     *value = (const char *)data;
165 
166     return true;
167 }
168 
findInt32(uint32_t key,int32_t * value) const169 bool MetaDataBase::findInt32(uint32_t key, int32_t *value) const {
170     uint32_t type = 0;
171     const void *data;
172     size_t size;
173     if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
174         return false;
175     }
176 
177     CHECK_EQ(size, sizeof(*value));
178 
179     *value = *(int32_t *)data;
180 
181     return true;
182 }
183 
findInt64(uint32_t key,int64_t * value) const184 bool MetaDataBase::findInt64(uint32_t key, int64_t *value) const {
185     uint32_t type = 0;
186     const void *data;
187     size_t size;
188     if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
189         return false;
190     }
191 
192     CHECK_EQ(size, sizeof(*value));
193 
194     *value = *(int64_t *)data;
195 
196     return true;
197 }
198 
findFloat(uint32_t key,float * value) const199 bool MetaDataBase::findFloat(uint32_t key, float *value) const {
200     uint32_t type = 0;
201     const void *data;
202     size_t size;
203     if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
204         return false;
205     }
206 
207     CHECK_EQ(size, sizeof(*value));
208 
209     *value = *(float *)data;
210 
211     return true;
212 }
213 
findPointer(uint32_t key,void ** value) const214 bool MetaDataBase::findPointer(uint32_t key, void **value) const {
215     uint32_t type = 0;
216     const void *data;
217     size_t size;
218     if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
219         return false;
220     }
221 
222     CHECK_EQ(size, sizeof(*value));
223 
224     *value = *(void **)data;
225 
226     return true;
227 }
228 
findRect(uint32_t key,int32_t * left,int32_t * top,int32_t * right,int32_t * bottom) const229 bool MetaDataBase::findRect(
230         uint32_t key,
231         int32_t *left, int32_t *top,
232         int32_t *right, int32_t *bottom) const {
233     uint32_t type = 0;
234     const void *data;
235     size_t size;
236     if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
237         return false;
238     }
239 
240     CHECK_EQ(size, sizeof(Rect));
241 
242     const Rect *r = (const Rect *)data;
243     *left = r->mLeft;
244     *top = r->mTop;
245     *right = r->mRight;
246     *bottom = r->mBottom;
247 
248     return true;
249 }
250 
setData(uint32_t key,uint32_t type,const void * data,size_t size)251 bool MetaDataBase::setData(
252         uint32_t key, uint32_t type, const void *data, size_t size) {
253     bool overwrote_existing = true;
254 
255     ssize_t i = mInternalData->mItems.indexOfKey(key);
256     if (i < 0) {
257         typed_data item;
258         i = mInternalData->mItems.add(key, item);
259 
260         overwrote_existing = false;
261     }
262 
263     typed_data &item = mInternalData->mItems.editValueAt(i);
264 
265     item.setData(type, data, size);
266 
267     return overwrote_existing;
268 }
269 
findData(uint32_t key,uint32_t * type,const void ** data,size_t * size) const270 bool MetaDataBase::findData(uint32_t key, uint32_t *type,
271                         const void **data, size_t *size) const {
272     ssize_t i = mInternalData->mItems.indexOfKey(key);
273 
274     if (i < 0) {
275         return false;
276     }
277 
278     const typed_data &item = mInternalData->mItems.valueAt(i);
279 
280     item.getData(type, data, size);
281 
282     return true;
283 }
284 
hasData(uint32_t key) const285 bool MetaDataBase::hasData(uint32_t key) const {
286     ssize_t i = mInternalData->mItems.indexOfKey(key);
287 
288     if (i < 0) {
289         return false;
290     }
291 
292     return true;
293 }
294 
typed_data()295 MetaDataBase::typed_data::typed_data()
296     : mType(0),
297       mSize(0) {
298 }
299 
~typed_data()300 MetaDataBase::typed_data::~typed_data() {
301     clear();
302 }
303 
typed_data(const typed_data & from)304 MetaDataBase::typed_data::typed_data(const typed_data &from)
305     : mType(from.mType),
306       mSize(0) {
307 
308     void *dst = allocateStorage(from.mSize);
309     if (dst) {
310         memcpy(dst, from.storage(), mSize);
311     }
312 }
313 
operator =(const MetaDataBase::typed_data & from)314 MetaDataBase::typed_data &MetaDataBase::typed_data::operator=(
315         const MetaDataBase::typed_data &from) {
316     if (this != &from) {
317         clear();
318         mType = from.mType;
319         void *dst = allocateStorage(from.mSize);
320         if (dst) {
321             memcpy(dst, from.storage(), mSize);
322         }
323     }
324 
325     return *this;
326 }
327 
clear()328 void MetaDataBase::typed_data::clear() {
329     freeStorage();
330 
331     mType = 0;
332 }
333 
setData(uint32_t type,const void * data,size_t size)334 void MetaDataBase::typed_data::setData(
335         uint32_t type, const void *data, size_t size) {
336     clear();
337 
338     mType = type;
339 
340     void *dst = allocateStorage(size);
341     if (dst) {
342         memcpy(dst, data, size);
343     }
344 }
345 
getData(uint32_t * type,const void ** data,size_t * size) const346 void MetaDataBase::typed_data::getData(
347         uint32_t *type, const void **data, size_t *size) const {
348     *type = mType;
349     *size = mSize;
350     *data = storage();
351 }
352 
allocateStorage(size_t size)353 void *MetaDataBase::typed_data::allocateStorage(size_t size) {
354     mSize = size;
355 
356     if (usesReservoir()) {
357         return &u.reservoir;
358     }
359 
360     u.ext_data = malloc(mSize);
361     if (u.ext_data == NULL) {
362         ALOGE("Couldn't allocate %zu bytes for item", size);
363         mSize = 0;
364     }
365     return u.ext_data;
366 }
367 
freeStorage()368 void MetaDataBase::typed_data::freeStorage() {
369     if (!usesReservoir()) {
370         if (u.ext_data) {
371             free(u.ext_data);
372             u.ext_data = NULL;
373         }
374     }
375 
376     mSize = 0;
377 }
378 
asString(bool verbose) const379 String8 MetaDataBase::typed_data::asString(bool verbose) const {
380     String8 out;
381     const void *data = storage();
382     switch(mType) {
383         case TYPE_NONE:
384             out = String8::format("no type, size %zu)", mSize);
385             break;
386         case TYPE_C_STRING:
387             out = String8::format("(char*) %s", (const char *)data);
388             break;
389         case TYPE_INT32:
390             out = String8::format("(int32_t) %d", *(int32_t *)data);
391             break;
392         case TYPE_INT64:
393             out = String8::format("(int64_t) %" PRId64, *(int64_t *)data);
394             break;
395         case TYPE_FLOAT:
396             out = String8::format("(float) %f", *(float *)data);
397             break;
398         case TYPE_POINTER:
399             out = String8::format("(void*) %p", *(void **)data);
400             break;
401         case TYPE_RECT:
402         {
403             const Rect *r = (const Rect *)data;
404             out = String8::format("Rect(%d, %d, %d, %d)",
405                                   r->mLeft, r->mTop, r->mRight, r->mBottom);
406             break;
407         }
408 
409         default:
410             out = String8::format("(unknown type %d, size %zu)", mType, mSize);
411             if (verbose && mSize <= 48) { // if it's less than three lines of hex data, dump it
412                 AString foo;
413                 hexdump(data, mSize, 0, &foo);
414                 out.append("\n");
415                 out.append(foo.c_str());
416             }
417             break;
418     }
419     return out;
420 }
421 
MakeFourCCString(uint32_t x,char * s)422 static void MakeFourCCString(uint32_t x, char *s) {
423     s[0] = x >> 24;
424     s[1] = (x >> 16) & 0xff;
425     s[2] = (x >> 8) & 0xff;
426     s[3] = x & 0xff;
427     s[4] = '\0';
428 }
429 
toString() const430 String8 MetaDataBase::toString() const {
431     String8 s;
432     for (int i = mInternalData->mItems.size(); --i >= 0;) {
433         int32_t key = mInternalData->mItems.keyAt(i);
434         char cc[5];
435         MakeFourCCString(key, cc);
436         const typed_data &item = mInternalData->mItems.valueAt(i);
437         s.appendFormat("%s: %s", cc, item.asString(false).string());
438         if (i != 0) {
439             s.append(", ");
440         }
441     }
442     return s;
443 }
444 
dumpToLog() const445 void MetaDataBase::dumpToLog() const {
446     for (int i = mInternalData->mItems.size(); --i >= 0;) {
447         int32_t key = mInternalData->mItems.keyAt(i);
448         char cc[5];
449         MakeFourCCString(key, cc);
450         const typed_data &item = mInternalData->mItems.valueAt(i);
451         ALOGI("%s: %s", cc, item.asString(true /* verbose */).string());
452     }
453 }
454 
455 #ifndef __ANDROID_VNDK__
writeToParcel(Parcel & parcel)456 status_t MetaDataBase::writeToParcel(Parcel &parcel) {
457     status_t ret;
458     size_t numItems = mInternalData->mItems.size();
459     ret = parcel.writeUint32(uint32_t(numItems));
460     if (ret) {
461         return ret;
462     }
463     for (size_t i = 0; i < numItems; i++) {
464         int32_t key = mInternalData->mItems.keyAt(i);
465         const typed_data &item = mInternalData->mItems.valueAt(i);
466         uint32_t type;
467         const void *data;
468         size_t size;
469         item.getData(&type, &data, &size);
470         ret = parcel.writeInt32(key);
471         if (ret) {
472             return ret;
473         }
474         ret = parcel.writeUint32(type);
475         if (ret) {
476             return ret;
477         }
478         if (type == TYPE_NONE) {
479             android::Parcel::WritableBlob blob;
480             ret = parcel.writeUint32(static_cast<uint32_t>(size));
481             if (ret) {
482                 return ret;
483             }
484             ret = parcel.writeBlob(size, false, &blob);
485             if (ret) {
486                 return ret;
487             }
488             memcpy(blob.data(), data, size);
489             blob.release();
490         } else {
491             ret = parcel.writeByteArray(size, (uint8_t*)data);
492             if (ret) {
493                 return ret;
494             }
495         }
496     }
497     return OK;
498 }
499 
updateFromParcel(const Parcel & parcel)500 status_t MetaDataBase::updateFromParcel(const Parcel &parcel) {
501     uint32_t numItems;
502     if (parcel.readUint32(&numItems) == OK) {
503 
504         for (size_t i = 0; i < numItems; i++) {
505             int32_t key;
506             uint32_t type;
507             uint32_t size;
508             status_t ret = parcel.readInt32(&key);
509             ret |= parcel.readUint32(&type);
510             ret |= parcel.readUint32(&size);
511             if (ret != OK) {
512                 break;
513             }
514             // copy data from Blob, which may be inline in Parcel storage,
515             // then advance position
516             if (type == TYPE_NONE) {
517                 android::Parcel::ReadableBlob blob;
518                 ret = parcel.readBlob(size, &blob);
519                 if (ret != OK) {
520                     break;
521                 }
522                 setData(key, type, blob.data(), size);
523                 blob.release();
524             } else {
525                 // copy data directly from Parcel storage, then advance position
526                 setData(key, type, parcel.readInplace(size), size);
527             }
528          }
529 
530         return OK;
531     }
532     ALOGW("no metadata in parcel");
533     return UNKNOWN_ERROR;
534 }
535 #endif
536 
537 }  // namespace android
538 
539