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