camera_metadata.c revision 2cae02cd02ea0b5d04268621616d386c9d5261c6
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