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    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
136camera_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}
166void free_camera_metadata(camera_metadata_t *metadata) {
167    free(metadata);
168}
169
170size_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
178size_t get_camera_metadata_size(const camera_metadata_t *metadata) {
179    if (metadata == NULL) return ERROR;
180
181    return metadata->size;
182}
183
184size_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
195size_t get_camera_metadata_entry_count(const camera_metadata_t *metadata) {
196    return metadata->entry_count;
197}
198
199size_t get_camera_metadata_entry_capacity(const camera_metadata_t *metadata) {
200    return metadata->entry_capacity;
201}
202
203size_t get_camera_metadata_data_count(const camera_metadata_t *metadata) {
204    return metadata->data_count;
205}
206
207size_t get_camera_metadata_data_capacity(const camera_metadata_t *metadata) {
208    return metadata->data_capacity;
209}
210
211camera_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
248int 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
285camera_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
301size_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
309static 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
340int 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
358static 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
366int 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
378int 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
399int 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
431int 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
439int 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
477int 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
549int 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
555int 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
561static const vendor_tag_query_ops_t *vendor_tag_ops = NULL;
562
563const 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
576const 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
591int 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
606int 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
611static void print_data(int fd, const uint8_t *data_ptr, int type, int count,
612        int indentation);
613
614void 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
620void 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
689static 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