blob: a413f66c87238f76e310723193672f0f5b5734bf [file] [log] [blame]
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -08001/*
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 */
Eino-Ville Talvala623ff652012-04-11 16:15:50 -070016#define _GNU_SOURCE // for fdprintf
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -080017#include <system/camera_metadata.h>
Igor Murashkind1cecc12013-04-30 17:21:54 -070018
19#define LOG_TAG "camera_metadata"
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -080020#include <cutils/log.h>
Eino-Ville Talvala94c19012012-04-04 15:30:06 -070021#include <stdio.h>
22#include <stdlib.h>
23#include <errno.h>
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -080024
Eino-Ville Talvala94c19012012-04-04 15:30:06 -070025#define OK 0
26#define ERROR 1
27#define NOT_FOUND -ENOENT
Eino-Ville Talvala31540362012-11-07 16:36:50 -080028
29#define _Alignas(T) \
30 ({struct _AlignasStruct { char c; T field; }; \
31 offsetof(struct _AlignasStruct, field); })
32
33// Align entry buffers as the compiler would
34#define ENTRY_ALIGNMENT _Alignas(camera_metadata_buffer_entry_t)
35// Align data buffer to largest supported data type
Igor Murashkin555aac82012-11-15 10:54:57 -080036#define DATA_ALIGNMENT _Alignas(camera_metadata_data_t)
Eino-Ville Talvala31540362012-11-07 16:36:50 -080037
38#define ALIGN_TO(val, alignment) \
Igor Murashkind1cecc12013-04-30 17:21:54 -070039 (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1))
40
41typedef size_t uptrdiff_t;
Eino-Ville Talvala31540362012-11-07 16:36:50 -080042
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -080043/**
44 * A single metadata entry, storing an array of values of a given type. If the
45 * array is no larger than 4 bytes in size, it is stored in the data.value[]
46 * array; otherwise, it can found in the parent's data array at index
47 * data.offset.
48 */
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -070049typedef struct camera_metadata_buffer_entry {
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -080050 uint32_t tag;
51 size_t count;
52 union {
53 size_t offset;
54 uint8_t value[4];
55 } data;
56 uint8_t type;
57 uint8_t reserved[3];
Eino-Ville Talvala31540362012-11-07 16:36:50 -080058} camera_metadata_buffer_entry_t;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -080059
60/**
61 * A packet of metadata. This is a list of entries, each of which may point to
62 * its values stored at an offset in data.
63 *
64 * It is assumed by the utility functions that the memory layout of the packet
65 * is as follows:
66 *
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -070067 * |-----------------------------------------------|
68 * | camera_metadata_t |
69 * | |
70 * |-----------------------------------------------|
71 * | reserved for future expansion |
72 * |-----------------------------------------------|
73 * | camera_metadata_buffer_entry_t #0 |
74 * |-----------------------------------------------|
75 * | .... |
76 * |-----------------------------------------------|
77 * | camera_metadata_buffer_entry_t #entry_count-1 |
78 * |-----------------------------------------------|
79 * | free space for |
80 * | (entry_capacity-entry_count) entries |
81 * |-----------------------------------------------|
82 * | start of camera_metadata.data |
83 * | |
84 * |-----------------------------------------------|
85 * | free space for |
86 * | (data_capacity-data_count) bytes |
87 * |-----------------------------------------------|
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -080088 *
89 * With the total length of the whole packet being camera_metadata.size bytes.
90 *
91 * In short, the entries and data are contiguous in memory after the metadata
92 * header.
93 */
94struct camera_metadata {
95 size_t size;
Eino-Ville Talvala94c19012012-04-04 15:30:06 -070096 uint32_t version;
97 uint32_t flags;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -080098 size_t entry_count;
99 size_t entry_capacity;
Igor Murashkind1cecc12013-04-30 17:21:54 -0700100 uptrdiff_t entries_start; // Offset from camera_metadata
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800101 size_t data_count;
102 size_t data_capacity;
Igor Murashkind1cecc12013-04-30 17:21:54 -0700103 uptrdiff_t data_start; // Offset from camera_metadata
Eino-Ville Talvala98d02fd2012-05-21 14:46:49 -0700104 void *user; // User set pointer, not copied with buffer
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800105 uint8_t reserved[0];
106};
107
Igor Murashkin555aac82012-11-15 10:54:57 -0800108/**
109 * A datum of metadata. This corresponds to camera_metadata_entry_t::data
110 * with the difference that each element is not a pointer. We need to have a
111 * non-pointer type description in order to figure out the largest alignment
112 * requirement for data (DATA_ALIGNMENT).
113 */
114typedef union camera_metadata_data {
115 uint8_t u8;
116 int32_t i32;
117 float f;
118 int64_t i64;
119 double d;
120 camera_metadata_rational_t r;
121} camera_metadata_data_t;
122
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700123/** Versioning information */
124#define CURRENT_METADATA_VERSION 1
125
126/** Flag definitions */
127#define FLAG_SORTED 0x00000001
128
129/** Tag information */
130
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800131typedef struct tag_info {
132 const char *tag_name;
133 uint8_t tag_type;
134} tag_info_t;
135
136#include "camera_metadata_tag_info.c"
137
Eino-Ville Talvalafd258822012-06-06 17:22:42 -0700138const size_t camera_metadata_type_size[NUM_TYPES] = {
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800139 [TYPE_BYTE] = sizeof(uint8_t),
140 [TYPE_INT32] = sizeof(int32_t),
141 [TYPE_FLOAT] = sizeof(float),
142 [TYPE_INT64] = sizeof(int64_t),
143 [TYPE_DOUBLE] = sizeof(double),
144 [TYPE_RATIONAL] = sizeof(camera_metadata_rational_t)
145};
146
Eino-Ville Talvalafd258822012-06-06 17:22:42 -0700147const char *camera_metadata_type_names[NUM_TYPES] = {
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800148 [TYPE_BYTE] = "byte",
149 [TYPE_INT32] = "int32",
150 [TYPE_FLOAT] = "float",
151 [TYPE_INT64] = "int64",
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700152 [TYPE_DOUBLE] = "double",
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800153 [TYPE_RATIONAL] = "rational"
154};
155
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800156static camera_metadata_buffer_entry_t *get_entries(
157 const camera_metadata_t *metadata) {
158 return (camera_metadata_buffer_entry_t*)
159 ((uint8_t*)metadata + metadata->entries_start);
160}
161
162static uint8_t *get_data(const camera_metadata_t *metadata) {
163 return (uint8_t*)metadata + metadata->data_start;
164}
165
Igor Murashkind1cecc12013-04-30 17:21:54 -0700166camera_metadata_t *allocate_copy_camera_metadata_checked(
167 const camera_metadata_t *src,
168 size_t src_size) {
169
170 if (src == NULL) {
171 return NULL;
172 }
173
174 void *buffer = malloc(src_size);
175 memcpy(buffer, src, src_size);
176
177 camera_metadata_t *metadata = (camera_metadata_t*) buffer;
178 if (validate_camera_metadata_structure(metadata, &src_size) != OK) {
179 free(buffer);
180 return NULL;
181 }
182
183 return metadata;
184}
185
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800186camera_metadata_t *allocate_camera_metadata(size_t entry_capacity,
187 size_t data_capacity) {
Eino-Ville Talvala2f4aca62012-08-24 11:42:06 -0700188 if (entry_capacity == 0) return NULL;
189
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800190 size_t memory_needed = calculate_camera_metadata_size(entry_capacity,
191 data_capacity);
192 void *buffer = malloc(memory_needed);
193 return place_camera_metadata(buffer, memory_needed,
194 entry_capacity,
195 data_capacity);
196}
197
198camera_metadata_t *place_camera_metadata(void *dst,
199 size_t dst_size,
200 size_t entry_capacity,
201 size_t data_capacity) {
202 if (dst == NULL) return NULL;
203 if (entry_capacity == 0) return NULL;
204
205 size_t memory_needed = calculate_camera_metadata_size(entry_capacity,
206 data_capacity);
207 if (memory_needed > dst_size) return NULL;
208
209 camera_metadata_t *metadata = (camera_metadata_t*)dst;
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700210 metadata->version = CURRENT_METADATA_VERSION;
211 metadata->flags = 0;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800212 metadata->entry_count = 0;
213 metadata->entry_capacity = entry_capacity;
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800214 metadata->entries_start =
215 ALIGN_TO(sizeof(camera_metadata_t), ENTRY_ALIGNMENT);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800216 metadata->data_count = 0;
217 metadata->data_capacity = data_capacity;
218 metadata->size = memory_needed;
Igor Murashkind1cecc12013-04-30 17:21:54 -0700219 size_t data_unaligned = (uint8_t*)(get_entries(metadata) +
220 metadata->entry_capacity) - (uint8_t*)metadata;
221 metadata->data_start = ALIGN_TO(data_unaligned, DATA_ALIGNMENT);
Eino-Ville Talvala98d02fd2012-05-21 14:46:49 -0700222 metadata->user = NULL;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800223
224 return metadata;
225}
226void free_camera_metadata(camera_metadata_t *metadata) {
227 free(metadata);
228}
229
230size_t calculate_camera_metadata_size(size_t entry_count,
231 size_t data_count) {
232 size_t memory_needed = sizeof(camera_metadata_t);
Eino-Ville Talvala31540362012-11-07 16:36:50 -0800233 // Start entry list at aligned boundary
234 memory_needed = ALIGN_TO(memory_needed, ENTRY_ALIGNMENT);
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700235 memory_needed += sizeof(camera_metadata_buffer_entry_t[entry_count]);
Eino-Ville Talvala31540362012-11-07 16:36:50 -0800236 // Start buffer list at aligned boundary
237 memory_needed = ALIGN_TO(memory_needed, DATA_ALIGNMENT);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800238 memory_needed += sizeof(uint8_t[data_count]);
239 return memory_needed;
240}
241
242size_t get_camera_metadata_size(const camera_metadata_t *metadata) {
243 if (metadata == NULL) return ERROR;
244
245 return metadata->size;
246}
247
248size_t get_camera_metadata_compact_size(const camera_metadata_t *metadata) {
249 if (metadata == NULL) return ERROR;
250
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800251 return calculate_camera_metadata_size(metadata->entry_count,
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800252 metadata->data_count);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800253}
254
255size_t get_camera_metadata_entry_count(const camera_metadata_t *metadata) {
256 return metadata->entry_count;
257}
258
259size_t get_camera_metadata_entry_capacity(const camera_metadata_t *metadata) {
260 return metadata->entry_capacity;
261}
262
263size_t get_camera_metadata_data_count(const camera_metadata_t *metadata) {
264 return metadata->data_count;
265}
266
267size_t get_camera_metadata_data_capacity(const camera_metadata_t *metadata) {
268 return metadata->data_capacity;
269}
270
271camera_metadata_t* copy_camera_metadata(void *dst, size_t dst_size,
272 const camera_metadata_t *src) {
273 size_t memory_needed = get_camera_metadata_compact_size(src);
274
275 if (dst == NULL) return NULL;
276 if (dst_size < memory_needed) return NULL;
277
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800278 camera_metadata_t *metadata =
279 place_camera_metadata(dst, dst_size, src->entry_count, src->data_count);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800280
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700281 metadata->flags = src->flags;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800282 metadata->entry_count = src->entry_count;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800283 metadata->data_count = src->data_count;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800284
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800285 memcpy(get_entries(metadata), get_entries(src),
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700286 sizeof(camera_metadata_buffer_entry_t[metadata->entry_count]));
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800287 memcpy(get_data(metadata), get_data(src),
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800288 sizeof(uint8_t[metadata->data_count]));
Eino-Ville Talvala98d02fd2012-05-21 14:46:49 -0700289 metadata->user = NULL;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800290
291 return metadata;
292}
293
Igor Murashkind1cecc12013-04-30 17:21:54 -0700294int validate_camera_metadata_structure(const camera_metadata_t *metadata,
295 const size_t *expected_size) {
296
297 if (metadata == NULL) {
298 return ERROR;
299 }
300
301 // Check that the metadata pointer is well-aligned first.
302 {
303 struct {
304 const char *name;
305 size_t alignment;
306 } alignments[] = {
307 {
308 .name = "camera_metadata",
309 .alignment = _Alignas(struct camera_metadata)
310 },
311 {
312 .name = "camera_metadata_buffer_entry",
313 .alignment = _Alignas(struct camera_metadata_buffer_entry)
314 },
315 {
316 .name = "camera_metadata_data",
317 .alignment = _Alignas(union camera_metadata_data)
318 },
319 };
320
321 for (size_t i = 0; i < sizeof(alignments)/sizeof(alignments[0]); ++i) {
322 uintptr_t aligned_ptr = ALIGN_TO(metadata, alignments[i].alignment);
323
324 if ((uintptr_t)metadata != aligned_ptr) {
325 ALOGE("%s: Metadata pointer is not aligned (actual %p, "
326 "expected %p) to type %s",
327 __FUNCTION__, metadata,
328 (void*)aligned_ptr, alignments[i].name);
329 return ERROR;
330 }
331 }
332 }
333
334 /**
335 * Check that the metadata contents are correct
336 */
337
338 if (expected_size != NULL && metadata->size > *expected_size) {
339 ALOGE("%s: Metadata size (%u) should be <= expected size (%u)",
340 __FUNCTION__, metadata->size, *expected_size);
341 return ERROR;
342 }
343
344 if (metadata->entry_count > metadata->entry_capacity) {
345 ALOGE("%s: Entry count (%u) should be <= entry capacity (%u)",
346 __FUNCTION__, metadata->entry_count, metadata->entry_capacity);
347 return ERROR;
348 }
349
350 uptrdiff_t entries_end = metadata->entries_start + metadata->entry_capacity;
351 if (entries_end < metadata->entries_start || // overflow check
352 entries_end > metadata->data_start) {
353
354 ALOGE("%s: Entry start + capacity (%u) should be <= data start (%u)",
355 __FUNCTION__,
356 (metadata->entries_start + metadata->entry_capacity),
357 metadata->data_start);
358 return ERROR;
359 }
360
361 uptrdiff_t data_end = metadata->data_start + metadata->data_capacity;
362 if (data_end < metadata->data_start || // overflow check
363 data_end > metadata->size) {
364
365 ALOGE("%s: Data start + capacity (%u) should be <= total size (%u)",
366 __FUNCTION__,
367 (metadata->data_start + metadata->data_capacity),
368 metadata->size);
369 return ERROR;
370 }
371
372 // Validate each entry
373 size_t entry_count = metadata->entry_count;
374 camera_metadata_buffer_entry_t *entries = get_entries(metadata);
375
376 for (size_t i = 0; i < entry_count; ++i) {
377
378 if ((uintptr_t)&entries[i] != ALIGN_TO(&entries[i], ENTRY_ALIGNMENT)) {
379 ALOGE("%s: Entry index %u had bad alignment (address %p),"
380 " expected alignment %d",
381 __FUNCTION__, i, &entries[i], ENTRY_ALIGNMENT);
382 return ERROR;
383 }
384
385 camera_metadata_buffer_entry_t entry = entries[i];
386
387 if (entry.type >= NUM_TYPES) {
388 ALOGE("%s: Entry index %u had a bad type %d",
389 __FUNCTION__, i, entry.type);
390 return ERROR;
391 }
392
393 // TODO: fix vendor_tag_ops across processes so we don't need to special
394 // case vendor-specific tags
395 uint32_t tag_section = entry.tag >> 16;
396 int tag_type = get_camera_metadata_tag_type(entry.tag);
397 if (tag_type != (int)entry.type && tag_section < VENDOR_SECTION) {
398 ALOGE("%s: Entry index %u had tag type %d, but the type was %d",
399 __FUNCTION__, i, tag_type, entry.type);
400 return ERROR;
401 }
402
403 size_t data_size =
404 calculate_camera_metadata_entry_data_size(entry.type,
405 entry.count);
406
407 if (data_size != 0) {
408 camera_metadata_data_t *data =
409 (camera_metadata_data_t*) (get_data(metadata) +
410 entry.data.offset);
411
412 if ((uintptr_t)data != ALIGN_TO(data, DATA_ALIGNMENT)) {
413 ALOGE("%s: Entry index %u had bad data alignment (address %p),"
414 " expected align %d, (tag name %s, data size %u)",
415 __FUNCTION__, i, data, DATA_ALIGNMENT,
416 get_camera_metadata_tag_name(entry.tag) ?: "unknown",
417 data_size);
418 return ERROR;
419 }
420
421 size_t data_entry_end = entry.data.offset + data_size;
422 if (data_entry_end < entry.data.offset || // overflow check
423 data_entry_end > metadata->data_capacity) {
424
425 ALOGE("%s: Entry index %u data ends (%u) beyond the capacity "
426 "%u", __FUNCTION__, i, data_entry_end,
427 metadata->data_capacity);
428 return ERROR;
429 }
430
431 } else if (entry.count == 0) {
432 if (entry.data.offset != 0) {
433 ALOGE("%s: Entry index %u had 0 items, but offset was non-0 "
Zhijun He3064d312013-07-15 13:55:11 -0700434 "(%u), tag name: %s", __FUNCTION__, i, entry.data.offset,
435 get_camera_metadata_tag_name(entry.tag) ?: "unknown");
Igor Murashkind1cecc12013-04-30 17:21:54 -0700436 return ERROR;
437 }
438 } // else data stored inline, so we look at value which can be anything.
439 }
440
441 return OK;
442}
443
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800444int append_camera_metadata(camera_metadata_t *dst,
445 const camera_metadata_t *src) {
446 if (dst == NULL || src == NULL ) return ERROR;
447
448 if (dst->entry_capacity < src->entry_count + dst->entry_count) return ERROR;
449 if (dst->data_capacity < src->data_count + dst->data_count) return ERROR;
450
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800451 memcpy(get_entries(dst) + dst->entry_count, get_entries(src),
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700452 sizeof(camera_metadata_buffer_entry_t[src->entry_count]));
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800453 memcpy(get_data(dst) + dst->data_count, get_data(src),
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800454 sizeof(uint8_t[src->data_count]));
455 if (dst->data_count != 0) {
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800456 camera_metadata_buffer_entry_t *entry = get_entries(dst) + dst->entry_count;
457 for (size_t i = 0; i < src->entry_count; i++, entry++) {
458 if ( calculate_camera_metadata_entry_data_size(entry->type,
459 entry->count) > 0 ) {
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800460 entry->data.offset += dst->data_count;
461 }
462 }
463 }
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700464 if (dst->entry_count == 0) {
465 // Appending onto empty buffer, keep sorted state
466 dst->flags |= src->flags & FLAG_SORTED;
467 } else if (src->entry_count != 0) {
468 // Both src, dst are nonempty, cannot assume sort remains
469 dst->flags &= ~FLAG_SORTED;
470 } else {
471 // Src is empty, keep dst sorted state
472 }
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800473 dst->entry_count += src->entry_count;
474 dst->data_count += src->data_count;
475
476 return OK;
477}
478
Eino-Ville Talvala2f4aca62012-08-24 11:42:06 -0700479camera_metadata_t *clone_camera_metadata(const camera_metadata_t *src) {
Eino-Ville Talvalafd258822012-06-06 17:22:42 -0700480 int res;
Eino-Ville Talvala2f4aca62012-08-24 11:42:06 -0700481 if (src == NULL) return NULL;
Eino-Ville Talvalafd258822012-06-06 17:22:42 -0700482 camera_metadata_t *clone = allocate_camera_metadata(
483 get_camera_metadata_entry_count(src),
484 get_camera_metadata_data_count(src));
485 if (clone != NULL) {
486 res = append_camera_metadata(clone, src);
487 if (res != OK) {
488 free_camera_metadata(clone);
489 clone = NULL;
490 }
491 }
492 return clone;
493}
494
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800495size_t calculate_camera_metadata_entry_data_size(uint8_t type,
496 size_t data_count) {
497 if (type >= NUM_TYPES) return 0;
498 size_t data_bytes = data_count *
499 camera_metadata_type_size[type];
Eino-Ville Talvala31540362012-11-07 16:36:50 -0800500 return data_bytes <= 4 ? 0 : ALIGN_TO(data_bytes, DATA_ALIGNMENT);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800501}
502
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700503static int add_camera_metadata_entry_raw(camera_metadata_t *dst,
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800504 uint32_t tag,
505 uint8_t type,
506 const void *data,
507 size_t data_count) {
508
509 if (dst == NULL) return ERROR;
510 if (dst->entry_count == dst->entry_capacity) return ERROR;
511 if (data == NULL) return ERROR;
512
513 size_t data_bytes =
514 calculate_camera_metadata_entry_data_size(type, data_count);
Eino-Ville Talvala31540362012-11-07 16:36:50 -0800515 if (data_bytes + dst->data_count > dst->data_capacity) return ERROR;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800516
Eino-Ville Talvala31540362012-11-07 16:36:50 -0800517 size_t data_payload_bytes =
518 data_count * camera_metadata_type_size[type];
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800519 camera_metadata_buffer_entry_t *entry = get_entries(dst) + dst->entry_count;
Zhijun He3064d312013-07-15 13:55:11 -0700520 memset(entry, 0, sizeof(camera_metadata_buffer_entry_t));
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800521 entry->tag = tag;
522 entry->type = type;
523 entry->count = data_count;
524
525 if (data_bytes == 0) {
526 memcpy(entry->data.value, data,
Eino-Ville Talvala31540362012-11-07 16:36:50 -0800527 data_payload_bytes);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800528 } else {
529 entry->data.offset = dst->data_count;
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800530 memcpy(get_data(dst) + entry->data.offset, data,
Eino-Ville Talvala31540362012-11-07 16:36:50 -0800531 data_payload_bytes);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800532 dst->data_count += data_bytes;
533 }
534 dst->entry_count++;
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700535 dst->flags &= ~FLAG_SORTED;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800536 return OK;
537}
538
539int add_camera_metadata_entry(camera_metadata_t *dst,
540 uint32_t tag,
541 const void *data,
542 size_t data_count) {
543
544 int type = get_camera_metadata_tag_type(tag);
545 if (type == -1) {
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700546 ALOGE("%s: Unknown tag %04x.", __FUNCTION__, tag);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800547 return ERROR;
548 }
549
550 return add_camera_metadata_entry_raw(dst,
551 tag,
552 type,
553 data,
554 data_count);
555}
556
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700557static int compare_entry_tags(const void *p1, const void *p2) {
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700558 uint32_t tag1 = ((camera_metadata_buffer_entry_t*)p1)->tag;
559 uint32_t tag2 = ((camera_metadata_buffer_entry_t*)p2)->tag;
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700560 return tag1 < tag2 ? -1 :
561 tag1 == tag2 ? 0 :
562 1;
563}
564
565int sort_camera_metadata(camera_metadata_t *dst) {
566 if (dst == NULL) return ERROR;
567 if (dst->flags & FLAG_SORTED) return OK;
568
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800569 qsort(get_entries(dst), dst->entry_count,
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700570 sizeof(camera_metadata_buffer_entry_t),
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700571 compare_entry_tags);
572 dst->flags |= FLAG_SORTED;
573
574 return OK;
575}
576
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800577int get_camera_metadata_entry(camera_metadata_t *src,
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700578 size_t index,
579 camera_metadata_entry_t *entry) {
580 if (src == NULL || entry == NULL) return ERROR;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800581 if (index >= src->entry_count) return ERROR;
582
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800583 camera_metadata_buffer_entry_t *buffer_entry = get_entries(src) + index;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800584
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700585 entry->index = index;
586 entry->tag = buffer_entry->tag;
587 entry->type = buffer_entry->type;
588 entry->count = buffer_entry->count;
589 if (buffer_entry->count *
590 camera_metadata_type_size[buffer_entry->type] > 4) {
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800591 entry->data.u8 = get_data(src) + buffer_entry->data.offset;
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700592 } else {
593 entry->data.u8 = buffer_entry->data.value;
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700594 }
595 return OK;
596}
597
598int find_camera_metadata_entry(camera_metadata_t *src,
599 uint32_t tag,
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700600 camera_metadata_entry_t *entry) {
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700601 if (src == NULL) return ERROR;
602
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700603 uint32_t index;
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700604 if (src->flags & FLAG_SORTED) {
605 // Sorted entries, do a binary search
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700606 camera_metadata_buffer_entry_t *search_entry = NULL;
607 camera_metadata_buffer_entry_t key;
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700608 key.tag = tag;
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700609 search_entry = bsearch(&key,
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800610 get_entries(src),
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700611 src->entry_count,
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700612 sizeof(camera_metadata_buffer_entry_t),
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700613 compare_entry_tags);
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700614 if (search_entry == NULL) return NOT_FOUND;
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800615 index = search_entry - get_entries(src);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800616 } else {
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700617 // Not sorted, linear search
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800618 camera_metadata_buffer_entry_t *search_entry = get_entries(src);
619 for (index = 0; index < src->entry_count; index++, search_entry++) {
620 if (search_entry->tag == tag) {
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700621 break;
622 }
623 }
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700624 if (index == src->entry_count) return NOT_FOUND;
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700625 }
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700626
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700627 return get_camera_metadata_entry(src, index,
628 entry);
629}
630
Eino-Ville Talvala2f4aca62012-08-24 11:42:06 -0700631int find_camera_metadata_ro_entry(const camera_metadata_t *src,
632 uint32_t tag,
633 camera_metadata_ro_entry_t *entry) {
634 return find_camera_metadata_entry((camera_metadata_t*)src, tag,
635 (camera_metadata_entry_t*)entry);
636}
637
638
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700639int delete_camera_metadata_entry(camera_metadata_t *dst,
640 size_t index) {
641 if (dst == NULL) return ERROR;
642 if (index >= dst->entry_count) return ERROR;
643
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800644 camera_metadata_buffer_entry_t *entry = get_entries(dst) + index;
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700645 size_t data_bytes = calculate_camera_metadata_entry_data_size(entry->type,
646 entry->count);
647
648 if (data_bytes > 0) {
649 // Shift data buffer to overwrite deleted data
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800650 uint8_t *start = get_data(dst) + entry->data.offset;
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700651 uint8_t *end = start + data_bytes;
652 size_t length = dst->data_count - entry->data.offset - data_bytes;
653 memmove(start, end, length);
654
655 // Update all entry indices to account for shift
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800656 camera_metadata_buffer_entry_t *e = get_entries(dst);
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700657 size_t i;
658 for (i = 0; i < dst->entry_count; i++) {
659 if (calculate_camera_metadata_entry_data_size(
660 e->type, e->count) > 0 &&
661 e->data.offset > entry->data.offset) {
662 e->data.offset -= data_bytes;
663 }
664 ++e;
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700665 }
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700666 dst->data_count -= data_bytes;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800667 }
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700668 // Shift entry array
669 memmove(entry, entry + 1,
670 sizeof(camera_metadata_buffer_entry_t) *
671 (dst->entry_count - index - 1) );
672 dst->entry_count -= 1;
673
674 return OK;
675}
676
677int update_camera_metadata_entry(camera_metadata_t *dst,
678 size_t index,
679 const void *data,
680 size_t data_count,
681 camera_metadata_entry_t *updated_entry) {
682 if (dst == NULL) return ERROR;
683 if (index >= dst->entry_count) return ERROR;
684
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800685 camera_metadata_buffer_entry_t *entry = get_entries(dst) + index;
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700686
687 size_t data_bytes =
688 calculate_camera_metadata_entry_data_size(entry->type,
689 data_count);
Eino-Ville Talvala31540362012-11-07 16:36:50 -0800690 size_t data_payload_bytes =
691 data_count * camera_metadata_type_size[entry->type];
692
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700693 size_t entry_bytes =
694 calculate_camera_metadata_entry_data_size(entry->type,
695 entry->count);
696 if (data_bytes != entry_bytes) {
697 // May need to shift/add to data array
698 if (dst->data_capacity < dst->data_count + data_bytes - entry_bytes) {
699 // No room
700 return ERROR;
701 }
702 if (entry_bytes != 0) {
703 // Remove old data
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800704 uint8_t *start = get_data(dst) + entry->data.offset;
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700705 uint8_t *end = start + entry_bytes;
706 size_t length = dst->data_count - entry->data.offset - entry_bytes;
707 memmove(start, end, length);
708 dst->data_count -= entry_bytes;
709
710 // Update all entry indices to account for shift
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800711 camera_metadata_buffer_entry_t *e = get_entries(dst);
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700712 size_t i;
713 for (i = 0; i < dst->entry_count; i++) {
714 if (calculate_camera_metadata_entry_data_size(
715 e->type, e->count) > 0 &&
716 e->data.offset > entry->data.offset) {
717 e->data.offset -= entry_bytes;
718 }
719 ++e;
720 }
721 }
722
723 if (data_bytes != 0) {
724 // Append new data
725 entry->data.offset = dst->data_count;
726
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800727 memcpy(get_data(dst) + entry->data.offset, data, data_payload_bytes);
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700728 dst->data_count += data_bytes;
729 }
730 } else if (data_bytes != 0) {
731 // data size unchanged, reuse same data location
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800732 memcpy(get_data(dst) + entry->data.offset, data, data_payload_bytes);
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700733 }
734
735 if (data_bytes == 0) {
736 // Data fits into entry
737 memcpy(entry->data.value, data,
Eino-Ville Talvala31540362012-11-07 16:36:50 -0800738 data_payload_bytes);
Eino-Ville Talvalaf5fb8a52012-05-10 14:22:28 -0700739 }
740
741 entry->count = data_count;
742
743 if (updated_entry != NULL) {
744 get_camera_metadata_entry(dst,
745 index,
746 updated_entry);
747 }
748
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800749 return OK;
750}
751
Eino-Ville Talvala98d02fd2012-05-21 14:46:49 -0700752int set_camera_metadata_user_pointer(camera_metadata_t *dst, void* user) {
753 if (dst == NULL) return ERROR;
754 dst->user = user;
755 return OK;
756}
757
758int get_camera_metadata_user_pointer(camera_metadata_t *dst, void** user) {
759 if (dst == NULL) return ERROR;
760 *user = dst->user;
761 return OK;
762}
763
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800764static const vendor_tag_query_ops_t *vendor_tag_ops = NULL;
765
766const char *get_camera_metadata_section_name(uint32_t tag) {
767 uint32_t tag_section = tag >> 16;
768 if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700769 return vendor_tag_ops->get_camera_vendor_section_name(
770 vendor_tag_ops,
771 tag);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800772 }
773 if (tag_section >= ANDROID_SECTION_COUNT) {
774 return NULL;
775 }
776 return camera_metadata_section_names[tag_section];
777}
778
779const char *get_camera_metadata_tag_name(uint32_t tag) {
780 uint32_t tag_section = tag >> 16;
781 if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700782 return vendor_tag_ops->get_camera_vendor_tag_name(
783 vendor_tag_ops,
784 tag);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800785 }
786 if (tag_section >= ANDROID_SECTION_COUNT ||
787 tag >= camera_metadata_section_bounds[tag_section][1] ) {
788 return NULL;
789 }
790 uint32_t tag_index = tag & 0xFFFF;
791 return tag_info[tag_section][tag_index].tag_name;
792}
793
794int get_camera_metadata_tag_type(uint32_t tag) {
795 uint32_t tag_section = tag >> 16;
796 if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700797 return vendor_tag_ops->get_camera_vendor_tag_type(
798 vendor_tag_ops,
799 tag);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800800 }
801 if (tag_section >= ANDROID_SECTION_COUNT ||
802 tag >= camera_metadata_section_bounds[tag_section][1] ) {
803 return -1;
804 }
805 uint32_t tag_index = tag & 0xFFFF;
806 return tag_info[tag_section][tag_index].tag_type;
807}
808
809int set_camera_metadata_vendor_tag_ops(const vendor_tag_query_ops_t *query_ops) {
810 vendor_tag_ops = query_ops;
811 return OK;
812}
813
Igor Murashkin375cfd32012-12-03 13:55:33 -0800814static void print_data(int fd, const uint8_t *data_ptr, uint32_t tag, int type,
815 int count,
Eino-Ville Talvala1d27e5b2012-07-30 10:46:22 -0700816 int indentation);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800817
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700818void dump_camera_metadata(const camera_metadata_t *metadata,
819 int fd,
820 int verbosity) {
Eino-Ville Talvala1d27e5b2012-07-30 10:46:22 -0700821 dump_indented_camera_metadata(metadata, fd, verbosity, 0);
822}
823
824void dump_indented_camera_metadata(const camera_metadata_t *metadata,
825 int fd,
826 int verbosity,
827 int indentation) {
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800828 if (metadata == NULL) {
Eino-Ville Talvala94879bd2012-10-01 16:33:03 -0700829 fdprintf(fd, "%*sDumping camera metadata array: Not allocated\n",
Eino-Ville Talvala2f4aca62012-08-24 11:42:06 -0700830 indentation, "");
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800831 return;
832 }
833 unsigned int i;
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700834 fdprintf(fd,
Eino-Ville Talvala2f4aca62012-08-24 11:42:06 -0700835 "%*sDumping camera metadata array: %d / %d entries, "
Eino-Ville Talvala1d27e5b2012-07-30 10:46:22 -0700836 "%d / %d bytes of extra data.\n", indentation, "",
837 metadata->entry_count, metadata->entry_capacity,
838 metadata->data_count, metadata->data_capacity);
839 fdprintf(fd, "%*sVersion: %d, Flags: %08x\n",
840 indentation + 2, "",
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700841 metadata->version, metadata->flags);
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800842 camera_metadata_buffer_entry_t *entry = get_entries(metadata);
843 for (i=0; i < metadata->entry_count; i++, entry++) {
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800844
845 const char *tag_name, *tag_section;
846 tag_section = get_camera_metadata_section_name(entry->tag);
847 if (tag_section == NULL) {
848 tag_section = "unknownSection";
849 }
850 tag_name = get_camera_metadata_tag_name(entry->tag);
851 if (tag_name == NULL) {
852 tag_name = "unknownTag";
853 }
854 const char *type_name;
855 if (entry->type >= NUM_TYPES) {
856 type_name = "unknown";
857 } else {
858 type_name = camera_metadata_type_names[entry->type];
859 }
Eino-Ville Talvala1d27e5b2012-07-30 10:46:22 -0700860 fdprintf(fd, "%*s%s.%s (%05x): %s[%d]\n",
861 indentation + 2, "",
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800862 tag_section,
863 tag_name,
864 entry->tag,
865 type_name,
866 entry->count);
867
868 if (verbosity < 1) continue;
869
870 if (entry->type >= NUM_TYPES) continue;
871
872 size_t type_size = camera_metadata_type_size[entry->type];
873 uint8_t *data_ptr;
874 if ( type_size * entry->count > 4 ) {
875 if (entry->data.offset >= metadata->data_count) {
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700876 ALOGE("%s: Malformed entry data offset: %d (max %d)",
877 __FUNCTION__,
878 entry->data.offset,
879 metadata->data_count);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800880 continue;
881 }
Eino-Ville Talvalab10d56a2012-11-13 11:45:12 -0800882 data_ptr = get_data(metadata) + entry->data.offset;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800883 } else {
884 data_ptr = entry->data.value;
885 }
886 int count = entry->count;
887 if (verbosity < 2 && count > 16) count = 16;
888
Igor Murashkin375cfd32012-12-03 13:55:33 -0800889 print_data(fd, data_ptr, entry->tag, entry->type, count, indentation);
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800890 }
891}
892
Igor Murashkin375cfd32012-12-03 13:55:33 -0800893static void print_data(int fd, const uint8_t *data_ptr, uint32_t tag,
Eino-Ville Talvala1d27e5b2012-07-30 10:46:22 -0700894 int type, int count, int indentation) {
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800895 static int values_per_line[NUM_TYPES] = {
896 [TYPE_BYTE] = 16,
897 [TYPE_INT32] = 4,
898 [TYPE_FLOAT] = 8,
899 [TYPE_INT64] = 2,
900 [TYPE_DOUBLE] = 4,
901 [TYPE_RATIONAL] = 2,
902 };
903 size_t type_size = camera_metadata_type_size[type];
Igor Murashkin375cfd32012-12-03 13:55:33 -0800904 char value_string_tmp[CAMERA_METADATA_ENUM_STRING_MAX_SIZE];
905 uint32_t value;
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800906
907 int lines = count / values_per_line[type];
908 if (count % values_per_line[type] != 0) lines++;
909
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800910 int index = 0;
911 int j, k;
912 for (j = 0; j < lines; j++) {
Eino-Ville Talvala1d27e5b2012-07-30 10:46:22 -0700913 fdprintf(fd, "%*s[", indentation + 4, "");
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800914 for (k = 0;
915 k < values_per_line[type] && count > 0;
916 k++, count--, index += type_size) {
917
918 switch (type) {
919 case TYPE_BYTE:
Igor Murashkin375cfd32012-12-03 13:55:33 -0800920 value = *(data_ptr + index);
921 if (camera_metadata_enum_snprint(tag,
922 value,
923 value_string_tmp,
924 sizeof(value_string_tmp))
925 == OK) {
926 fdprintf(fd, "%s ", value_string_tmp);
927 } else {
928 fdprintf(fd, "%hhu ",
929 *(data_ptr + index));
930 }
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800931 break;
932 case TYPE_INT32:
Igor Murashkin375cfd32012-12-03 13:55:33 -0800933 value =
934 *(int32_t*)(data_ptr + index);
935 if (camera_metadata_enum_snprint(tag,
936 value,
937 value_string_tmp,
938 sizeof(value_string_tmp))
939 == OK) {
940 fdprintf(fd, "%s ", value_string_tmp);
941 } else {
942 fdprintf(fd, "%d ",
943 *(int32_t*)(data_ptr + index));
944 }
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800945 break;
946 case TYPE_FLOAT:
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700947 fdprintf(fd, "%0.2f ",
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800948 *(float*)(data_ptr + index));
949 break;
950 case TYPE_INT64:
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700951 fdprintf(fd, "%lld ",
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800952 *(int64_t*)(data_ptr + index));
953 break;
954 case TYPE_DOUBLE:
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700955 fdprintf(fd, "%0.2f ",
Eino-Ville Talvala31540362012-11-07 16:36:50 -0800956 *(double*)(data_ptr + index));
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800957 break;
958 case TYPE_RATIONAL: {
959 int32_t numerator = *(int32_t*)(data_ptr + index);
960 int32_t denominator = *(int32_t*)(data_ptr + index + 4);
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700961 fdprintf(fd, "(%d / %d) ",
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800962 numerator, denominator);
963 break;
964 }
965 default:
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700966 fdprintf(fd, "??? ");
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800967 }
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800968 }
Eino-Ville Talvala94c19012012-04-04 15:30:06 -0700969 fdprintf(fd, "]\n");
Eino-Ville Talvalad8afb4d2012-02-10 14:27:08 -0800970 }
971}