Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_tiff.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
29
30#include "nilorea/n_common.h"
31#include "nilorea/n_files.h"
32#include "nilorea/n_log.h"
33#include "nilorea/n_tiff.h"
34
35#include <math.h>
36#include <stdio.h>
37#include <string.h>
38#include <stdlib.h>
39#include <unistd.h>
40
42static int failures = 0;
43
47static void check(const char* what, int ok) {
48 if (!ok) {
49 failures++;
50 fprintf(stderr, "FAIL %s\n", what);
51 }
52}
53
58static void put16(unsigned char* p, uint16_t v, int be) {
59 p[be ? 0 : 1] = (unsigned char)(v >> 8);
60 p[be ? 1 : 0] = (unsigned char)(v & 0xff);
61}
62
67static void put32(unsigned char* p, uint32_t v, int be) {
68 int i = 0;
69
70 for (i = 0; i < 4; i++)
71 p[be ? i : 3 - i] = (unsigned char)(v >> (24 - 8 * i));
72}
73
81static void put_entry(unsigned char* e, uint16_t tag, uint16_t type, uint32_t count, uint32_t value, int be) {
82 put16(e, tag, be);
83 put16(e + 2, type, be);
84 put32(e + 4, count, be);
85 put32(e + 8, value, be);
86}
87
93static size_t build(unsigned char* buf, int be) {
94 const float floats[2] = {1.5f, -0.25f};
95 int i = 0;
96
97 memset(buf, 0, 256);
98 buf[0] = buf[1] = (unsigned char)(be ? 'M' : 'I');
99 put16(buf + 2, N_TIFF_MAGIC_DCP, be);
100 put32(buf + 4, 8, be);
101 put16(buf + 8, 5, be);
102 /* five entries of 12 bytes from 10, values from 80 */
103 put_entry(buf + 10, 50708, 2, 12, 80, be); /* ASCII, at 80 */
104 put_entry(buf + 22, 50778, 3, 1, 0, be); /* SHORT, in the entry */
105 put16(buf + 22 + 8, 21, be);
106 put_entry(buf + 34, 50721, 10, 3, 96, be); /* SRATIONAL x3, at 96 */
107 put_entry(buf + 46, 50938, 11, 2, 120, be); /* FLOAT x2, at 120 */
108 put_entry(buf + 58, 50939, 11, 64, 200, be); /* past the end */
109 memcpy(buf + 80, "Test Camera", 12);
110 put32(buf + 96, (uint32_t)8309, be);
111 put32(buf + 100, 10000, be);
112 put32(buf + 104, (uint32_t)-1786, be);
113 put32(buf + 108, 10000, be);
114 put32(buf + 112, 5, be);
115 put32(buf + 116, 0, be);
116 for (i = 0; i < 2; i++) {
117 uint32_t bits = 0;
118
119 memcpy(&bits, &floats[i], sizeof(bits));
120 put32(buf + 120 + 4 * i, bits, be);
121 }
122 return 256;
123}
124
127static void test_order(int be) {
128 unsigned char buf[256];
129 size_t len = build(buf, be);
130 N_TIFF* tiff = n_tiff_parse(buf, len);
131 double v[4] = {0, 0, 0, 0};
132 char text[64];
133
134 check("the buffer parses", tiff != NULL);
135 if (!tiff)
136 return;
137 check("the byte order is read", tiff->big_endian == be);
138 check("the magic is reported", tiff->magic == N_TIFF_MAGIC_DCP);
139 check("the entry past the end is skipped", tiff->count == 4 && !n_tiff_find(tiff, 50939));
140 check("ASCII reads", n_tiff_get_ascii(tiff, 50708, text, sizeof(text)) == 0 &&
141 strcmp(text, "Test Camera") == 0);
142 check("ASCII is cut to the room given",
143 n_tiff_get_ascii(tiff, 50708, text, 5) == 0 && strcmp(text, "Test") == 0);
144 check("a short in the entry reads", n_tiff_get_doubles(tiff, 50778, v, 4) == 1 && v[0] == 21.0);
145 check("signed rationals read", n_tiff_get_doubles(tiff, 50721, v, 4) == 3 &&
146 fabs(v[0] - 0.8309) < 1e-9 && fabs(v[1] + 0.1786) < 1e-9 &&
147 v[2] == 0.0);
148 check("floats read", n_tiff_get_doubles(tiff, 50938, v, 4) == 2 && v[0] == 1.5 && v[1] == -0.25);
149 check("a count is reported", n_tiff_count(tiff, 50721) == 3 && n_tiff_count(tiff, 1) == 0);
150 check("ASCII is not a number", n_tiff_get_doubles(tiff, 50708, v, 4) == 0);
151 check("a number is not ASCII", n_tiff_get_ascii(tiff, 50721, text, sizeof(text)) == -1 &&
152 text[0] == '\0');
153 n_tiff_free(&tiff);
154 check("free clears the pointer", tiff == NULL);
155}
156
158static void test_broken(void) {
159 unsigned char buf[256];
160 size_t len = build(buf, 0);
161
162 check("a short buffer is refused", n_tiff_parse(buf, 6) == NULL);
163 buf[0] = 'X';
164 check("a bad byte order is refused", n_tiff_parse(buf, len) == NULL);
165 build(buf, 0);
166 put32(buf + 4, 250, 0);
167 check("a directory past the end is refused", n_tiff_parse(buf, len) == NULL);
168 build(buf, 0);
169 put16(buf + 8, 60, 0);
170 check("a directory longer than the buffer is refused", n_tiff_parse(buf, len) == NULL);
171}
172
176static int list_file(const char* path) {
177 unsigned char* data = NULL;
178 size_t len = 0;
179 N_TIFF* tiff = NULL;
180 size_t i = 0;
181
182 if (n_file_read_bounded(path, 64 * 1024 * 1024, &data, &len) != TRUE || !data) {
183 fprintf(stderr, "cannot read %s\n", path);
184 return 1;
185 }
186 tiff = n_tiff_parse(data, len);
187 if (!tiff) {
188 fprintf(stderr, "%s is not TIFF structured\n", path);
189 free(data);
190 return 1;
191 }
192 printf("%s: %s endian, magic 0x%04x, %zu entries\n", path, tiff->big_endian ? "big" : "little",
193 tiff->magic, tiff->count);
194 for (i = 0; i < tiff->count; i++)
195 printf(" tag %5u type %2u count %u\n", tiff->entries[i].tag, tiff->entries[i].type,
196 tiff->entries[i].count);
197 n_tiff_free(&tiff);
198 free(data);
199 return 0;
200}
201
210int main(int argc, char** argv) {
211 int opt = 0, log_level = LOG_ERR;
212
213 while ((opt = getopt(argc, argv, "V:")) != -1) {
214 if (opt != 'V') {
215 fprintf(stderr, "Usage: %s [-V LOG_LEVEL] [file]\n", argv[0]);
216 return 2;
217 }
218 log_level = atoi(optarg);
219 }
221 if (optind < argc)
222 return list_file(argv[optind]);
223 test_order(0);
224 test_order(1);
225 test_broken();
226 printf("%s: %d failure(s)\n", failures ? "FAILED" : "ok", failures);
227 return failures ? 1 : 0;
228}
static int failures
Definition ex_atlas.c:51
int main(void)
Definition ex_atlas.c:117
static int log_level
static void type(N_GUI_CTX *gui, const char *s)
Type a whole string into whatever has focus.
static void check(const char *what, int ok)
Count and print a failed condition.
Definition ex_icc.c:46
static size_t build(unsigned char *buf, int be)
Build a DCP shaped buffer: a name, a short, three signed rationals, two floats, and one entry pointin...
Definition ex_tiff.c:93
static void put16(unsigned char *p, uint16_t v, int be)
Write a 16 bit value in a byte order.
Definition ex_tiff.c:58
static void put32(unsigned char *p, uint32_t v, int be)
Write a 32 bit value in a byte order.
Definition ex_tiff.c:67
static void test_order(int be)
Parse a built buffer and check every value.
Definition ex_tiff.c:127
static void test_broken(void)
Broken buffers are refused, never read out of bounds.
Definition ex_tiff.c:158
static int list_file(const char *path)
List the tags of a file's first directory.
Definition ex_tiff.c:176
static void put_entry(unsigned char *e, uint16_t tag, uint16_t type, uint32_t count, uint32_t value, int be)
Write one directory entry.
Definition ex_tiff.c:81
#define LOG_ERR
error conditions
Definition n_log.h:100
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
Definition n_log.c:123
int n_file_read_bounded(const char *path, size_t max_size, unsigned char **out, size_t *out_len)
read a whole file into a freshly allocated, NUL-terminated buffer, refusing a file larger than max_si...
Definition n_files.c:270
uint16_t tag
tag number
Definition n_tiff.h:68
N_TIFF_ENTRY * entries
the entries whose values lie inside the buffer, in file order
Definition n_tiff.h:88
uint16_t type
TIFF field type, 1 BYTE to 12 DOUBLE.
Definition n_tiff.h:70
uint32_t count
number of values
Definition n_tiff.h:72
int big_endian
1 for "MM" (Motorola, big endian), 0 for "II"
Definition n_tiff.h:84
size_t count
how many
Definition n_tiff.h:90
uint16_t magic
the 16 bit value after the byte order mark
Definition n_tiff.h:86
N_TIFF * n_tiff_parse(const unsigned char *data, size_t len)
Parse the first directory of a TIFF structured buffer.
Definition n_tiff.c:94
size_t n_tiff_count(const N_TIFF *tiff, uint16_t tag)
How many values a tag has.
Definition n_tiff.c:178
size_t n_tiff_get_doubles(const N_TIFF *tiff, uint16_t tag, double *out, size_t max)
Read a numeric tag as doubles.
Definition n_tiff.c:184
#define N_TIFF_MAGIC_DCP
The magic of an Adobe DCP camera profile, "RC" read little endian.
Definition n_tiff.h:63
const N_TIFF_ENTRY * n_tiff_find(const N_TIFF *tiff, uint16_t tag)
Find an entry by tag.
Definition n_tiff.c:167
int n_tiff_get_ascii(const N_TIFF *tiff, uint16_t tag, char *out, size_t out_len)
Read an ASCII tag.
Definition n_tiff.c:254
void n_tiff_free(N_TIFF **tiff)
Release a parse, and set the pointer to NULL.
Definition n_tiff.c:160
The first directory of a TIFF structured buffer.
Definition n_tiff.h:78
Common headers and low-level functions & define.
Files configuration header.
Generic log system.
Reading the tags of a TIFF structured buffer.