| Marco Nelissen | 3d21ae3 | 2018-02-16 08:24:08 -0800 | [diff] [blame] | 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> | 
| Marco Nelissen | 3d21ae3 | 2018-02-16 08:24:08 -0800 | [diff] [blame] | 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 |  | 
| Colin Cross | f8b5fe2 | 2021-12-15 14:59:00 -0800 | [diff] [blame] | 31 | #if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__) | 
| Dongwon Kang | 97a2155 | 2019-08-28 11:22:33 -0700 | [diff] [blame] | 32 | #include <binder/Parcel.h> | 
 | 33 | #endif | 
 | 34 |  | 
| Marco Nelissen | 3d21ae3 | 2018-02-16 08:24:08 -0800 | [diff] [blame] | 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 |  | 
 | 59 |     bool usesReservoir() const { | 
 | 60 |         return mSize <= sizeof(u.reservoir); | 
 | 61 |     } | 
 | 62 |  | 
 | 63 |     void *allocateStorage(size_t size); | 
 | 64 |     void freeStorage(); | 
 | 65 |  | 
 | 66 |     void *storage() { | 
 | 67 |         return usesReservoir() ? &u.reservoir : u.ext_data; | 
 | 68 |     } | 
 | 69 |  | 
 | 70 |     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 |  | 
 | 85 | MetaDataBase::MetaDataBase() | 
 | 86 |     : mInternalData(new MetaDataInternal()) { | 
 | 87 | } | 
 | 88 |  | 
 | 89 | MetaDataBase::MetaDataBase(const MetaDataBase &from) | 
 | 90 |     : mInternalData(new MetaDataInternal()) { | 
 | 91 |     mInternalData->mItems = from.mInternalData->mItems; | 
 | 92 | } | 
 | 93 |  | 
 | 94 | MetaDataBase& MetaDataBase::operator = (const MetaDataBase &rhs) { | 
 | 95 |     this->mInternalData->mItems = rhs.mInternalData->mItems; | 
 | 96 |     return *this; | 
 | 97 | } | 
 | 98 |  | 
 | 99 | MetaDataBase::~MetaDataBase() { | 
 | 100 |     clear(); | 
 | 101 |     delete mInternalData; | 
 | 102 | } | 
 | 103 |  | 
 | 104 | void MetaDataBase::clear() { | 
 | 105 |     mInternalData->mItems.clear(); | 
 | 106 | } | 
 | 107 |  | 
 | 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 |  | 
 | 120 | bool MetaDataBase::setCString(uint32_t key, const char *value) { | 
 | 121 |     return setData(key, TYPE_C_STRING, value, strlen(value) + 1); | 
 | 122 | } | 
 | 123 |  | 
 | 124 | bool MetaDataBase::setInt32(uint32_t key, int32_t value) { | 
 | 125 |     return setData(key, TYPE_INT32, &value, sizeof(value)); | 
 | 126 | } | 
 | 127 |  | 
 | 128 | bool MetaDataBase::setInt64(uint32_t key, int64_t value) { | 
 | 129 |     return setData(key, TYPE_INT64, &value, sizeof(value)); | 
 | 130 | } | 
 | 131 |  | 
 | 132 | bool MetaDataBase::setFloat(uint32_t key, float value) { | 
 | 133 |     return setData(key, TYPE_FLOAT, &value, sizeof(value)); | 
 | 134 | } | 
 | 135 |  | 
 | 136 | bool MetaDataBase::setPointer(uint32_t key, void *value) { | 
 | 137 |     return setData(key, TYPE_POINTER, &value, sizeof(value)); | 
 | 138 | } | 
 | 139 |  | 
 | 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 |  */ | 
 | 156 | 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 |  | 
 | 169 | 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 |  | 
 | 184 | 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 |  | 
 | 199 | 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 |  | 
 | 214 | 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 |  | 
 | 229 | 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 |  | 
 | 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 |  | 
 | 270 | 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 |  | 
 | 285 | 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 |  | 
 | 295 | MetaDataBase::typed_data::typed_data() | 
 | 296 |     : mType(0), | 
 | 297 |       mSize(0) { | 
 | 298 | } | 
 | 299 |  | 
 | 300 | MetaDataBase::typed_data::~typed_data() { | 
 | 301 |     clear(); | 
 | 302 | } | 
 | 303 |  | 
 | 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 |  | 
 | 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 |  | 
 | 328 | void MetaDataBase::typed_data::clear() { | 
 | 329 |     freeStorage(); | 
 | 330 |  | 
 | 331 |     mType = 0; | 
 | 332 | } | 
 | 333 |  | 
 | 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 |  | 
 | 346 | 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 |  | 
 | 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 |  | 
 | 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 |  | 
 | 379 | 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 |  | 
 | 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 |  | 
 | 430 | 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); | 
| Tomasz Wasilczyk | 03fc55f | 2023-08-11 17:05:05 +0000 | [diff] [blame] | 437 |         s.appendFormat("%s: %s", cc, item.asString(false).c_str()); | 
| Marco Nelissen | 3d21ae3 | 2018-02-16 08:24:08 -0800 | [diff] [blame] | 438 |         if (i != 0) { | 
 | 439 |             s.append(", "); | 
 | 440 |         } | 
 | 441 |     } | 
 | 442 |     return s; | 
 | 443 | } | 
 | 444 |  | 
 | 445 | 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); | 
| Tomasz Wasilczyk | 03fc55f | 2023-08-11 17:05:05 +0000 | [diff] [blame] | 451 |         ALOGI("%s: %s", cc, item.asString(true /* verbose */).c_str()); | 
| Marco Nelissen | 3d21ae3 | 2018-02-16 08:24:08 -0800 | [diff] [blame] | 452 |     } | 
 | 453 | } | 
 | 454 |  | 
| Colin Cross | f8b5fe2 | 2021-12-15 14:59:00 -0800 | [diff] [blame] | 455 | #if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__) | 
| Marco Nelissen | 3d21ae3 | 2018-02-16 08:24:08 -0800 | [diff] [blame] | 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 |  | 
 | 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(); | 
| Ray Essick | 9aeb7a8 | 2022-04-28 14:58:43 -0700 | [diff] [blame] | 524 |             } else if (type == TYPE_C_STRING) { | 
 | 525 |                 // copy data directly from Parcel storage, then advance position | 
 | 526 |                 // NB: readInplace() bumps position, it is NOT idempotent. | 
 | 527 |                 const void *src = parcel.readInplace(size); | 
 | 528 |                 char *str = (char *) src; | 
 | 529 |                 if (src == nullptr || size == 0 || str[size-1] != '\0') { | 
 | 530 |                     char ccKey[5]; | 
 | 531 |                     MakeFourCCString(key, ccKey); | 
 | 532 |                     if (src == nullptr) { | 
 | 533 |                         ALOGW("ignoring key '%s' string with no data (expected %d)", ccKey, size); | 
 | 534 |                     } else { | 
 | 535 |                         ALOGW("ignoring key '%s': unterminated string of %d bytes", ccKey, size); | 
 | 536 |                     } | 
 | 537 |                 } else { | 
 | 538 |                     setData(key, type, src, size); | 
 | 539 |                 } | 
| Marco Nelissen | 3d21ae3 | 2018-02-16 08:24:08 -0800 | [diff] [blame] | 540 |             } else { | 
 | 541 |                 // copy data directly from Parcel storage, then advance position | 
| Ray Essick | 9aeb7a8 | 2022-04-28 14:58:43 -0700 | [diff] [blame] | 542 |                 // verify that the received size is enough | 
 | 543 |                 uint32_t needed = 0; | 
 | 544 |                 switch (type) { | 
 | 545 |                     case TYPE_INT32: | 
 | 546 |                         needed = sizeof(int32_t); | 
 | 547 |                         break; | 
 | 548 |                     case TYPE_INT64: | 
 | 549 |                         needed = sizeof(int64_t); | 
 | 550 |                         break; | 
 | 551 |                     case TYPE_FLOAT: | 
 | 552 |                         needed = sizeof(float); | 
 | 553 |                         break; | 
 | 554 |                     case TYPE_POINTER: | 
 | 555 |                         // NB: this rejects passing between 32-bit and 64-bit space. | 
 | 556 |                         needed = sizeof(void*); | 
 | 557 |                         break; | 
 | 558 |                     case TYPE_RECT: | 
 | 559 |                         needed = sizeof(Rect); | 
 | 560 |                         break; | 
 | 561 |                     default: | 
 | 562 |                         // non-standard entities can be any size >= 0 | 
 | 563 |                         needed = 0; | 
 | 564 |                         break; | 
 | 565 |                 } | 
 | 566 |                 const void *src = parcel.readInplace(size); | 
 | 567 |                 if (src == nullptr || (needed != 0 && size != needed)) { | 
 | 568 |                     char ccKey[5]; | 
 | 569 |                     MakeFourCCString(key, ccKey); | 
 | 570 |                     char ccType[5]; | 
 | 571 |                     MakeFourCCString(type, ccType); | 
 | 572 |                     if (src == nullptr) { | 
 | 573 |                         ALOGW("ignoring key '%s' type '%s' missing data (expected %d)", | 
 | 574 |                               ccKey, ccType, size); | 
 | 575 |                     } else { | 
 | 576 |                         ALOGW("ignoring key '%s': type '%s' bytes: expected %d != %d received", | 
 | 577 |                                ccKey, ccType, needed, size); | 
 | 578 |                     } | 
 | 579 |                 } else { | 
 | 580 |                     setData(key, type, src, size); | 
 | 581 |                 } | 
| Marco Nelissen | 3d21ae3 | 2018-02-16 08:24:08 -0800 | [diff] [blame] | 582 |             } | 
 | 583 |          } | 
 | 584 |  | 
 | 585 |         return OK; | 
 | 586 |     } | 
 | 587 |     ALOGW("no metadata in parcel"); | 
 | 588 |     return UNKNOWN_ERROR; | 
 | 589 | } | 
| Colin Cross | f8b5fe2 | 2021-12-15 14:59:00 -0800 | [diff] [blame] | 590 | #endif // defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__) | 
| Marco Nelissen | 3d21ae3 | 2018-02-16 08:24:08 -0800 | [diff] [blame] | 591 |  | 
 | 592 | }  // namespace android | 
 | 593 |  |