1 /* 2 * Copyright (C) 2012 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 #define _GNU_SOURCE // for fdprintf 17 #include <system/camera_metadata.h> 18 #include <cutils/log.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <errno.h> 22 23 #define OK 0 24 #define ERROR 1 25 #define NOT_FOUND -ENOENT 26 /** 27 * A single metadata entry, storing an array of values of a given type. If the 28 * array is no larger than 4 bytes in size, it is stored in the data.value[] 29 * array; otherwise, it can found in the parent's data array at index 30 * data.offset. 31 */ 32 typedef struct camera_metadata_buffer_entry { 33 uint32_t tag; 34 size_t count; 35 union { 36 size_t offset; 37 uint8_t value[4]; 38 } data; 39 uint8_t type; 40 uint8_t reserved[3]; 41 } __attribute__((packed)) camera_metadata_buffer_entry_t; 42 43 /** 44 * A packet of metadata. This is a list of entries, each of which may point to 45 * its values stored at an offset in data. 46 * 47 * It is assumed by the utility functions that the memory layout of the packet 48 * is as follows: 49 * 50 * |-----------------------------------------------| 51 * | camera_metadata_t | 52 * | | 53 * |-----------------------------------------------| 54 * | reserved for future expansion | 55 * |-----------------------------------------------| 56 * | camera_metadata_buffer_entry_t #0 | 57 * |-----------------------------------------------| 58 * | .... | 59 * |-----------------------------------------------| 60 * | camera_metadata_buffer_entry_t #entry_count-1 | 61 * |-----------------------------------------------| 62 * | free space for | 63 * | (entry_capacity-entry_count) entries | 64 * |-----------------------------------------------| 65 * | start of camera_metadata.data | 66 * | | 67 * |-----------------------------------------------| 68 * | free space for | 69 * | (data_capacity-data_count) bytes | 70 * |-----------------------------------------------| 71 * 72 * With the total length of the whole packet being camera_metadata.size bytes. 73 * 74 * In short, the entries and data are contiguous in memory after the metadata 75 * header. 76 */ 77 struct camera_metadata { 78 size_t size; 79 uint32_t version; 80 uint32_t flags; 81 size_t entry_count; 82 size_t entry_capacity; 83 camera_metadata_buffer_entry_t *entries; 84 size_t data_count; 85 size_t data_capacity; 86 uint8_t *data; 87 void *user; // User set pointer, not copied with buffer 88 uint8_t reserved[0]; 89 }; 90 91 /** Versioning information */ 92 #define CURRENT_METADATA_VERSION 1 93 94 /** Flag definitions */ 95 #define FLAG_SORTED 0x00000001 96 97 /** Tag information */ 98 99 typedef struct tag_info { 100 const char *tag_name; 101 uint8_t tag_type; 102 } tag_info_t; 103 104 #include "camera_metadata_tag_info.c" 105 106 const size_t camera_metadata_type_size[NUM_TYPES] = { 107 [TYPE_BYTE] = sizeof(uint8_t), 108 [TYPE_INT32] = sizeof(int32_t), 109 [TYPE_FLOAT] = sizeof(float), 110 [TYPE_INT64] = sizeof(int64_t), 111 [TYPE_DOUBLE] = sizeof(double), 112 [TYPE_RATIONAL] = sizeof(camera_metadata_rational_t) 113 }; 114 115 const char *camera_metadata_type_names[NUM_TYPES] = { 116 [TYPE_BYTE] = "byte", 117 [TYPE_INT32] = "int32", 118 [TYPE_FLOAT] = "float", 119 [TYPE_INT64] = "int64", 120 [TYPE_DOUBLE] = "double", 121 [TYPE_RATIONAL] = "rational" 122 }; 123 124 camera_metadata_t *allocate_camera_metadata(size_t entry_capacity, 125 size_t data_capacity) { 126 if (entry_capacity == 0) return NULL; 127 128 size_t memory_needed = calculate_camera_metadata_size(entry_capacity, 129 data_capacity); 130 void *buffer = malloc(memory_needed); 131 return place_camera_metadata(buffer, memory_needed, 132 entry_capacity, 133 data_capacity); 134 } 135 136 camera_metadata_t *place_camera_metadata(void *dst, 137 size_t dst_size, 138 size_t entry_capacity, 139 size_t data_capacity) { 140 if (dst == NULL) return NULL; 141 if (entry_capacity == 0) return NULL; 142 143 size_t memory_needed = calculate_camera_metadata_size(entry_capacity, 144 data_capacity); 145 if (memory_needed > dst_size) return NULL; 146 147 camera_metadata_t *metadata = (camera_metadata_t*)dst; 148 metadata->version = CURRENT_METADATA_VERSION; 149 metadata->flags = 0; 150 metadata->entry_count = 0; 151 metadata->entry_capacity = entry_capacity; 152 metadata->entries = (camera_metadata_buffer_entry_t*)(metadata + 1); 153 metadata->data_count = 0; 154 metadata->data_capacity = data_capacity; 155 metadata->size = memory_needed; 156 if (metadata->data_capacity != 0) { 157 metadata->data = 158 (uint8_t*)(metadata->entries + metadata->entry_capacity); 159 } else { 160 metadata->data = NULL; 161 } 162 metadata->user = NULL; 163 164 return metadata; 165 } 166 void free_camera_metadata(camera_metadata_t *metadata) { 167 free(metadata); 168 } 169 170 size_t calculate_camera_metadata_size(size_t entry_count, 171 size_t data_count) { 172 size_t memory_needed = sizeof(camera_metadata_t); 173 memory_needed += sizeof(camera_metadata_buffer_entry_t[entry_count]); 174 memory_needed += sizeof(uint8_t[data_count]); 175 return memory_needed; 176 } 177 178 size_t get_camera_metadata_size(const camera_metadata_t *metadata) { 179 if (metadata == NULL) return ERROR; 180 181 return metadata->size; 182 } 183 184 size_t get_camera_metadata_compact_size(const camera_metadata_t *metadata) { 185 if (metadata == NULL) return ERROR; 186 187 ptrdiff_t reserved_size = metadata->size - 188 calculate_camera_metadata_size(metadata->entry_capacity, 189 metadata->data_capacity); 190 191 return calculate_camera_metadata_size(metadata->entry_count, 192 metadata->data_count) + reserved_size; 193 } 194 195 size_t get_camera_metadata_entry_count(const camera_metadata_t *metadata) { 196 return metadata->entry_count; 197 } 198 199 size_t get_camera_metadata_entry_capacity(const camera_metadata_t *metadata) { 200 return metadata->entry_capacity; 201 } 202 203 size_t get_camera_metadata_data_count(const camera_metadata_t *metadata) { 204 return metadata->data_count; 205 } 206 207 size_t get_camera_metadata_data_capacity(const camera_metadata_t *metadata) { 208 return metadata->data_capacity; 209 } 210 211 camera_metadata_t* copy_camera_metadata(void *dst, size_t dst_size, 212 const camera_metadata_t *src) { 213 size_t memory_needed = get_camera_metadata_compact_size(src); 214 215 if (dst == NULL) return NULL; 216 if (dst_size < memory_needed) return NULL; 217 218 // If copying a newer version of the structure, there may be additional 219 // header fields we don't know about but need to copy 220 ptrdiff_t reserved_size = src->size - 221 calculate_camera_metadata_size(src->entry_capacity, 222 src->data_capacity); 223 224 camera_metadata_t *metadata = (camera_metadata_t*)dst; 225 metadata->version = CURRENT_METADATA_VERSION; 226 metadata->flags = src->flags; 227 metadata->entry_count = src->entry_count; 228 metadata->entry_capacity = src->entry_count; 229 metadata->entries = (camera_metadata_buffer_entry_t*) 230 ((uint8_t *)(metadata + 1) + reserved_size); 231 metadata->data_count = src->data_count; 232 metadata->data_capacity = src->data_count; 233 metadata->data = (uint8_t *)(metadata->entries + metadata->entry_capacity); 234 metadata->size = memory_needed; 235 236 if (reserved_size > 0) { 237 memcpy(metadata->reserved, src->reserved, reserved_size); 238 } 239 memcpy(metadata->entries, src->entries, 240 sizeof(camera_metadata_buffer_entry_t[metadata->entry_count])); 241 memcpy(metadata->data, src->data, 242 sizeof(uint8_t[metadata->data_count])); 243 metadata->user = NULL; 244 245 return metadata; 246 } 247 248 int append_camera_metadata(camera_metadata_t *dst, 249 const camera_metadata_t *src) { 250 if (dst == NULL || src == NULL ) return ERROR; 251 252 if (dst->entry_capacity < src->entry_count + dst->entry_count) return ERROR; 253 if (dst->data_capacity < src->data_count + dst->data_count) return ERROR; 254 255 memcpy(dst->entries + dst->entry_count, src->entries, 256 sizeof(camera_metadata_buffer_entry_t[src->entry_count])); 257 memcpy(dst->data + dst->data_count, src->data, 258 sizeof(uint8_t[src->data_count])); 259 if (dst->data_count != 0) { 260 unsigned int i; 261 for (i = dst->entry_count; 262 i < dst->entry_count + src->entry_count; 263 i++) { 264 camera_metadata_buffer_entry_t *entry = dst->entries + i; 265 if ( camera_metadata_type_size[entry->type] * entry->count > 4 ) { 266 entry->data.offset += dst->data_count; 267 } 268 } 269 } 270 if (dst->entry_count == 0) { 271 // Appending onto empty buffer, keep sorted state 272 dst->flags |= src->flags & FLAG_SORTED; 273 } else if (src->entry_count != 0) { 274 // Both src, dst are nonempty, cannot assume sort remains 275 dst->flags &= ~FLAG_SORTED; 276 } else { 277 // Src is empty, keep dst sorted state 278 } 279 dst->entry_count += src->entry_count; 280 dst->data_count += src->data_count; 281 282 return OK; 283 } 284 285 camera_metadata_t *clone_camera_metadata(const camera_metadata_t *src) { 286 int res; 287 if (src == NULL) return NULL; 288 camera_metadata_t *clone = allocate_camera_metadata( 289 get_camera_metadata_entry_count(src), 290 get_camera_metadata_data_count(src)); 291 if (clone != NULL) { 292 res = append_camera_metadata(clone, src); 293 if (res != OK) { 294 free_camera_metadata(clone); 295 clone = NULL; 296 } 297 } 298 return clone; 299 } 300 301 size_t calculate_camera_metadata_entry_data_size(uint8_t type, 302 size_t data_count) { 303 if (type >= NUM_TYPES) return 0; 304 size_t data_bytes = data_count * 305 camera_metadata_type_size[type]; 306 return data_bytes <= 4 ? 0 : data_bytes; 307 } 308 309 static int add_camera_metadata_entry_raw(camera_metadata_t *dst, 310 uint32_t tag, 311 uint8_t type, 312 const void *data, 313 size_t data_count) { 314 315 if (dst == NULL) return ERROR; 316 if (dst->entry_count == dst->entry_capacity) return ERROR; 317 if (data == NULL) return ERROR; 318 319 size_t data_bytes = 320 calculate_camera_metadata_entry_data_size(type, data_count); 321 322 camera_metadata_buffer_entry_t *entry = dst->entries + dst->entry_count; 323 entry->tag = tag; 324 entry->type = type; 325 entry->count = data_count; 326 327 if (data_bytes == 0) { 328 memcpy(entry->data.value, data, 329 data_count * camera_metadata_type_size[type] ); 330 } else { 331 entry->data.offset = dst->data_count; 332 memcpy(dst->data + entry->data.offset, data, data_bytes); 333 dst->data_count += data_bytes; 334 } 335 dst->entry_count++; 336 dst->flags &= ~FLAG_SORTED; 337 return OK; 338 } 339 340 int add_camera_metadata_entry(camera_metadata_t *dst, 341 uint32_t tag, 342 const void *data, 343 size_t data_count) { 344 345 int type = get_camera_metadata_tag_type(tag); 346 if (type == -1) { 347 ALOGE("%s: Unknown tag %04x.", __FUNCTION__, tag); 348 return ERROR; 349 } 350 351 return add_camera_metadata_entry_raw(dst, 352 tag, 353 type, 354 data, 355 data_count); 356 } 357 358 static int compare_entry_tags(const void *p1, const void *p2) { 359 uint32_t tag1 = ((camera_metadata_buffer_entry_t*)p1)->tag; 360 uint32_t tag2 = ((camera_metadata_buffer_entry_t*)p2)->tag; 361 return tag1 < tag2 ? -1 : 362 tag1 == tag2 ? 0 : 363 1; 364 } 365 366 int sort_camera_metadata(camera_metadata_t *dst) { 367 if (dst == NULL) return ERROR; 368 if (dst->flags & FLAG_SORTED) return OK; 369 370 qsort(dst->entries, dst->entry_count, 371 sizeof(camera_metadata_buffer_entry_t), 372 compare_entry_tags); 373 dst->flags |= FLAG_SORTED; 374 375 return OK; 376 } 377 378 int get_camera_metadata_entry(camera_metadata_t *src, 379 size_t index, 380 camera_metadata_entry_t *entry) { 381 if (src == NULL || entry == NULL) return ERROR; 382 if (index >= src->entry_count) return ERROR; 383 384 camera_metadata_buffer_entry_t *buffer_entry = src->entries + index; 385 386 entry->index = index; 387 entry->tag = buffer_entry->tag; 388 entry->type = buffer_entry->type; 389 entry->count = buffer_entry->count; 390 if (buffer_entry->count * 391 camera_metadata_type_size[buffer_entry->type] > 4) { 392 entry->data.u8 = src->data + buffer_entry->data.offset; 393 } else { 394 entry->data.u8 = buffer_entry->data.value; 395 } 396 return OK; 397 } 398 399 int find_camera_metadata_entry(camera_metadata_t *src, 400 uint32_t tag, 401 camera_metadata_entry_t *entry) { 402 if (src == NULL) return ERROR; 403 404 uint32_t index; 405 if (src->flags & FLAG_SORTED) { 406 // Sorted entries, do a binary search 407 camera_metadata_buffer_entry_t *search_entry = NULL; 408 camera_metadata_buffer_entry_t key; 409 key.tag = tag; 410 search_entry = bsearch(&key, 411 src->entries, 412 src->entry_count, 413 sizeof(camera_metadata_buffer_entry_t), 414 compare_entry_tags); 415 if (search_entry == NULL) return NOT_FOUND; 416 index = search_entry - src->entries; 417 } else { 418 // Not sorted, linear search 419 for (index = 0; index < src->entry_count; index++) { 420 if (src->entries[index].tag == tag) { 421 break; 422 } 423 } 424 if (index == src->entry_count) return NOT_FOUND; 425 } 426 427 return get_camera_metadata_entry(src, index, 428 entry); 429 } 430 431 int find_camera_metadata_ro_entry(const camera_metadata_t *src, 432 uint32_t tag, 433 camera_metadata_ro_entry_t *entry) { 434 return find_camera_metadata_entry((camera_metadata_t*)src, tag, 435 (camera_metadata_entry_t*)entry); 436 } 437 438 439 int delete_camera_metadata_entry(camera_metadata_t *dst, 440 size_t index) { 441 if (dst == NULL) return ERROR; 442 if (index >= dst->entry_count) return ERROR; 443 444 camera_metadata_buffer_entry_t *entry = dst->entries + index; 445 size_t data_bytes = calculate_camera_metadata_entry_data_size(entry->type, 446 entry->count); 447 448 if (data_bytes > 0) { 449 // Shift data buffer to overwrite deleted data 450 uint8_t *start = dst->data + entry->data.offset; 451 uint8_t *end = start + data_bytes; 452 size_t length = dst->data_count - entry->data.offset - data_bytes; 453 memmove(start, end, length); 454 455 // Update all entry indices to account for shift 456 camera_metadata_buffer_entry_t *e = dst->entries; 457 size_t i; 458 for (i = 0; i < dst->entry_count; i++) { 459 if (calculate_camera_metadata_entry_data_size( 460 e->type, e->count) > 0 && 461 e->data.offset > entry->data.offset) { 462 e->data.offset -= data_bytes; 463 } 464 ++e; 465 } 466 dst->data_count -= data_bytes; 467 } 468 // Shift entry array 469 memmove(entry, entry + 1, 470 sizeof(camera_metadata_buffer_entry_t) * 471 (dst->entry_count - index - 1) ); 472 dst->entry_count -= 1; 473 474 return OK; 475 } 476 477 int update_camera_metadata_entry(camera_metadata_t *dst, 478 size_t index, 479 const void *data, 480 size_t data_count, 481 camera_metadata_entry_t *updated_entry) { 482 if (dst == NULL) return ERROR; 483 if (index >= dst->entry_count) return ERROR; 484 485 camera_metadata_buffer_entry_t *entry = dst->entries + index; 486 487 size_t data_bytes = 488 calculate_camera_metadata_entry_data_size(entry->type, 489 data_count); 490 size_t entry_bytes = 491 calculate_camera_metadata_entry_data_size(entry->type, 492 entry->count); 493 if (data_bytes != entry_bytes) { 494 // May need to shift/add to data array 495 if (dst->data_capacity < dst->data_count + data_bytes - entry_bytes) { 496 // No room 497 return ERROR; 498 } 499 if (entry_bytes != 0) { 500 // Remove old data 501 uint8_t *start = dst->data + entry->data.offset; 502 uint8_t *end = start + entry_bytes; 503 size_t length = dst->data_count - entry->data.offset - entry_bytes; 504 memmove(start, end, length); 505 dst->data_count -= entry_bytes; 506 507 // Update all entry indices to account for shift 508 camera_metadata_buffer_entry_t *e = dst->entries; 509 size_t i; 510 for (i = 0; i < dst->entry_count; i++) { 511 if (calculate_camera_metadata_entry_data_size( 512 e->type, e->count) > 0 && 513 e->data.offset > entry->data.offset) { 514 e->data.offset -= entry_bytes; 515 } 516 ++e; 517 } 518 } 519 520 if (data_bytes != 0) { 521 // Append new data 522 entry->data.offset = dst->data_count; 523 524 memcpy(dst->data + entry->data.offset, data, data_bytes); 525 dst->data_count += data_bytes; 526 } 527 } else if (data_bytes != 0) { 528 // data size unchanged, reuse same data location 529 memcpy(dst->data + entry->data.offset, data, data_bytes); 530 } 531 532 if (data_bytes == 0) { 533 // Data fits into entry 534 memcpy(entry->data.value, data, 535 data_count * camera_metadata_type_size[entry->type]); 536 } 537 538 entry->count = data_count; 539 540 if (updated_entry != NULL) { 541 get_camera_metadata_entry(dst, 542 index, 543 updated_entry); 544 } 545 546 return OK; 547 } 548 549 int set_camera_metadata_user_pointer(camera_metadata_t *dst, void* user) { 550 if (dst == NULL) return ERROR; 551 dst->user = user; 552 return OK; 553 } 554 555 int get_camera_metadata_user_pointer(camera_metadata_t *dst, void** user) { 556 if (dst == NULL) return ERROR; 557 *user = dst->user; 558 return OK; 559 } 560 561 static const vendor_tag_query_ops_t *vendor_tag_ops = NULL; 562 563 const char *get_camera_metadata_section_name(uint32_t tag) { 564 uint32_t tag_section = tag >> 16; 565 if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) { 566 return vendor_tag_ops->get_camera_vendor_section_name( 567 vendor_tag_ops, 568 tag); 569 } 570 if (tag_section >= ANDROID_SECTION_COUNT) { 571 return NULL; 572 } 573 return camera_metadata_section_names[tag_section]; 574 } 575 576 const char *get_camera_metadata_tag_name(uint32_t tag) { 577 uint32_t tag_section = tag >> 16; 578 if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) { 579 return vendor_tag_ops->get_camera_vendor_tag_name( 580 vendor_tag_ops, 581 tag); 582 } 583 if (tag_section >= ANDROID_SECTION_COUNT || 584 tag >= camera_metadata_section_bounds[tag_section][1] ) { 585 return NULL; 586 } 587 uint32_t tag_index = tag & 0xFFFF; 588 return tag_info[tag_section][tag_index].tag_name; 589 } 590 591 int get_camera_metadata_tag_type(uint32_t tag) { 592 uint32_t tag_section = tag >> 16; 593 if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) { 594 return vendor_tag_ops->get_camera_vendor_tag_type( 595 vendor_tag_ops, 596 tag); 597 } 598 if (tag_section >= ANDROID_SECTION_COUNT || 599 tag >= camera_metadata_section_bounds[tag_section][1] ) { 600 return -1; 601 } 602 uint32_t tag_index = tag & 0xFFFF; 603 return tag_info[tag_section][tag_index].tag_type; 604 } 605 606 int set_camera_metadata_vendor_tag_ops(const vendor_tag_query_ops_t *query_ops) { 607 vendor_tag_ops = query_ops; 608 return OK; 609 } 610 611 static void print_data(int fd, const uint8_t *data_ptr, int type, int count, 612 int indentation); 613 614 void dump_camera_metadata(const camera_metadata_t *metadata, 615 int fd, 616 int verbosity) { 617 dump_indented_camera_metadata(metadata, fd, verbosity, 0); 618 } 619 620 void dump_indented_camera_metadata(const camera_metadata_t *metadata, 621 int fd, 622 int verbosity, 623 int indentation) { 624 if (metadata == NULL) { 625 fdprintf(fd, "%*sDumping camera metadata array: Not allocated\n", 626 indentation, ""); 627 return; 628 } 629 unsigned int i; 630 fdprintf(fd, 631 "%*sDumping camera metadata array: %d / %d entries, " 632 "%d / %d bytes of extra data.\n", indentation, "", 633 metadata->entry_count, metadata->entry_capacity, 634 metadata->data_count, metadata->data_capacity); 635 fdprintf(fd, "%*sVersion: %d, Flags: %08x\n", 636 indentation + 2, "", 637 metadata->version, metadata->flags); 638 for (i=0; i < metadata->entry_count; i++) { 639 camera_metadata_buffer_entry_t *entry = metadata->entries + i; 640 641 const char *tag_name, *tag_section; 642 tag_section = get_camera_metadata_section_name(entry->tag); 643 if (tag_section == NULL) { 644 tag_section = "unknownSection"; 645 } 646 tag_name = get_camera_metadata_tag_name(entry->tag); 647 if (tag_name == NULL) { 648 tag_name = "unknownTag"; 649 } 650 const char *type_name; 651 if (entry->type >= NUM_TYPES) { 652 type_name = "unknown"; 653 } else { 654 type_name = camera_metadata_type_names[entry->type]; 655 } 656 fdprintf(fd, "%*s%s.%s (%05x): %s[%d]\n", 657 indentation + 2, "", 658 tag_section, 659 tag_name, 660 entry->tag, 661 type_name, 662 entry->count); 663 664 if (verbosity < 1) continue; 665 666 if (entry->type >= NUM_TYPES) continue; 667 668 size_t type_size = camera_metadata_type_size[entry->type]; 669 uint8_t *data_ptr; 670 if ( type_size * entry->count > 4 ) { 671 if (entry->data.offset >= metadata->data_count) { 672 ALOGE("%s: Malformed entry data offset: %d (max %d)", 673 __FUNCTION__, 674 entry->data.offset, 675 metadata->data_count); 676 continue; 677 } 678 data_ptr = metadata->data + entry->data.offset; 679 } else { 680 data_ptr = entry->data.value; 681 } 682 int count = entry->count; 683 if (verbosity < 2 && count > 16) count = 16; 684 685 print_data(fd, data_ptr, entry->type, count, indentation); 686 } 687 } 688 689 static void print_data(int fd, const uint8_t *data_ptr, 690 int type, int count, int indentation) { 691 static int values_per_line[NUM_TYPES] = { 692 [TYPE_BYTE] = 16, 693 [TYPE_INT32] = 4, 694 [TYPE_FLOAT] = 8, 695 [TYPE_INT64] = 2, 696 [TYPE_DOUBLE] = 4, 697 [TYPE_RATIONAL] = 2, 698 }; 699 size_t type_size = camera_metadata_type_size[type]; 700 701 int lines = count / values_per_line[type]; 702 if (count % values_per_line[type] != 0) lines++; 703 704 int index = 0; 705 int j, k; 706 for (j = 0; j < lines; j++) { 707 fdprintf(fd, "%*s[", indentation + 4, ""); 708 for (k = 0; 709 k < values_per_line[type] && count > 0; 710 k++, count--, index += type_size) { 711 712 switch (type) { 713 case TYPE_BYTE: 714 fdprintf(fd, "%hhu ", 715 *(data_ptr + index)); 716 break; 717 case TYPE_INT32: 718 fdprintf(fd, "%d ", 719 *(int32_t*)(data_ptr + index)); 720 break; 721 case TYPE_FLOAT: 722 fdprintf(fd, "%0.2f ", 723 *(float*)(data_ptr + index)); 724 break; 725 case TYPE_INT64: 726 fdprintf(fd, "%lld ", 727 *(int64_t*)(data_ptr + index)); 728 break; 729 case TYPE_DOUBLE: 730 fdprintf(fd, "%0.2f ", 731 *(float*)(data_ptr + index)); 732 break; 733 case TYPE_RATIONAL: { 734 int32_t numerator = *(int32_t*)(data_ptr + index); 735 int32_t denominator = *(int32_t*)(data_ptr + index + 4); 736 fdprintf(fd, "(%d / %d) ", 737 numerator, denominator); 738 break; 739 } 740 default: 741 fdprintf(fd, "??? "); 742 } 743 } 744 fdprintf(fd, "]\n"); 745 } 746 } 747