Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_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
27
28#include "nilorea/n_tiff.h"
29#include "nilorea/n_common.h"
30#include "nilorea/n_log.h"
31
32#include <string.h>
33
36#define N_TIFF_MAX_ENTRIES 4096
37
41static size_t _n_tiff_type_size(uint16_t type) {
42 switch (type) {
43 case 1: /* BYTE */
44 case 2: /* ASCII */
45 case 6: /* SBYTE */
46 case 7: /* UNDEFINED */
47 return 1;
48 case 3: /* SHORT */
49 case 8: /* SSHORT */
50 return 2;
51 case 4: /* LONG */
52 case 9: /* SLONG */
53 case 11: /* FLOAT */
54 return 4;
55 case 5: /* RATIONAL */
56 case 10: /* SRATIONAL */
57 case 12: /* DOUBLE */
58 return 8;
59 default:
60 return 0;
61 }
62}
63
68static uint16_t _n_tiff_u16(const N_TIFF* tiff, const unsigned char* p) {
69 if (tiff->big_endian)
70 return (uint16_t)((p[0] << 8) | p[1]);
71 return (uint16_t)((p[1] << 8) | p[0]);
72}
73
78static uint32_t _n_tiff_u32(const N_TIFF* tiff, const unsigned char* p) {
79 if (tiff->big_endian)
80 return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
81 return ((uint32_t)p[3] << 24) | ((uint32_t)p[2] << 16) | ((uint32_t)p[1] << 8) | (uint32_t)p[0];
82}
83
88static uint64_t _n_tiff_u64(const N_TIFF* tiff, const unsigned char* p) {
89 uint64_t hi = _n_tiff_u32(tiff, tiff->big_endian ? p : p + 4);
90 uint64_t lo = _n_tiff_u32(tiff, tiff->big_endian ? p + 4 : p);
91 return (hi << 32) | lo;
92}
93
94N_TIFF* n_tiff_parse(const unsigned char* data, size_t len) {
95 N_TIFF* tiff = NULL;
96 size_t ifd = 0;
97 size_t count = 0;
98 size_t i = 0;
99
100 __n_assert(data, return NULL);
101 if (len < 8)
102 return NULL;
103 Malloc(tiff, N_TIFF, 1);
104 __n_assert(tiff, return NULL);
105 tiff->data = data;
106 tiff->len = len;
107 if (data[0] == 'I' && data[1] == 'I')
108 tiff->big_endian = 0;
109 else if (data[0] == 'M' && data[1] == 'M')
110 tiff->big_endian = 1;
111 else {
112 Free(tiff);
113 return NULL;
114 }
115 tiff->magic = _n_tiff_u16(tiff, data + 2);
116 ifd = _n_tiff_u32(tiff, data + 4);
117 if (ifd < 8 || ifd > len - 2) {
118 Free(tiff);
119 return NULL;
120 }
121 count = _n_tiff_u16(tiff, data + ifd);
122 if (count == 0 || count > N_TIFF_MAX_ENTRIES || ifd + 2 + count * 12 > len) {
123 Free(tiff);
124 return NULL;
125 }
126 Malloc(tiff->entries, N_TIFF_ENTRY, count);
127 if (!tiff->entries) {
128 Free(tiff);
129 return NULL;
130 }
131 for (i = 0; i < count; i++) {
132 const unsigned char* e = data + ifd + 2 + i * 12;
133 N_TIFF_ENTRY entry;
134 size_t size = 0;
135 size_t bytes = 0;
136
137 entry.tag = _n_tiff_u16(tiff, e);
138 entry.type = _n_tiff_u16(tiff, e + 2);
139 entry.count = _n_tiff_u32(tiff, e + 4);
140 size = _n_tiff_type_size(entry.type);
141 if (size == 0 || entry.count == 0)
142 continue;
143 /* A count so large that its size overflows cannot fit either. */
144 if ((size_t)entry.count > len / size)
145 continue;
146 bytes = size * entry.count;
147 /* Four bytes or less sit in the entry itself; more are at an offset. */
148 if (bytes <= 4)
149 entry.offset = (size_t)(e + 8 - data);
150 else {
151 entry.offset = _n_tiff_u32(tiff, e + 8);
152 if (entry.offset > len || bytes > len - entry.offset)
153 continue;
154 }
155 tiff->entries[tiff->count++] = entry;
156 }
157 return tiff;
158}
159
160void n_tiff_free(N_TIFF** tiff) {
161 if (!tiff || !*tiff)
162 return;
163 FreeNoLog((*tiff)->entries);
164 Free((*tiff));
165}
166
167const N_TIFF_ENTRY* n_tiff_find(const N_TIFF* tiff, uint16_t tag) {
168 size_t i = 0;
169
170 __n_assert(tiff, return NULL);
171 for (i = 0; i < tiff->count; i++) {
172 if (tiff->entries[i].tag == tag)
173 return &tiff->entries[i];
174 }
175 return NULL;
176}
177
178size_t n_tiff_count(const N_TIFF* tiff, uint16_t tag) {
179 const N_TIFF_ENTRY* entry = n_tiff_find(tiff, tag);
180
181 return entry ? entry->count : 0;
182}
183
184size_t n_tiff_get_doubles(const N_TIFF* tiff, uint16_t tag, double* out, size_t max) {
185 const N_TIFF_ENTRY* entry = NULL;
186 size_t i = 0;
187 size_t n = 0;
188
189 __n_assert(tiff, return 0);
190 __n_assert(out, return 0);
191 entry = n_tiff_find(tiff, tag);
192 if (!entry || entry->type == 2 || entry->type == 7)
193 return 0;
194 n = entry->count < max ? entry->count : max;
195 for (i = 0; i < n; i++) {
196 const unsigned char* p = tiff->data + entry->offset + i * _n_tiff_type_size(entry->type);
197
198 switch (entry->type) {
199 case 1:
200 out[i] = (double)p[0];
201 break;
202 case 6:
203 out[i] = (double)(int8_t)p[0];
204 break;
205 case 3:
206 out[i] = (double)_n_tiff_u16(tiff, p);
207 break;
208 case 8:
209 out[i] = (double)(int16_t)_n_tiff_u16(tiff, p);
210 break;
211 case 4:
212 out[i] = (double)_n_tiff_u32(tiff, p);
213 break;
214 case 9:
215 out[i] = (double)(int32_t)_n_tiff_u32(tiff, p);
216 break;
217 case 5: {
218 uint32_t num = _n_tiff_u32(tiff, p);
219 uint32_t den = _n_tiff_u32(tiff, p + 4);
220
221 out[i] = den ? (double)num / (double)den : 0.0;
222 break;
223 }
224 case 10: {
225 int32_t num = (int32_t)_n_tiff_u32(tiff, p);
226 int32_t den = (int32_t)_n_tiff_u32(tiff, p + 4);
227
228 out[i] = den ? (double)num / (double)den : 0.0;
229 break;
230 }
231 case 11: {
232 uint32_t bits = _n_tiff_u32(tiff, p);
233 float value = 0.0f;
234
235 memcpy(&value, &bits, sizeof(value));
236 out[i] = (double)value;
237 break;
238 }
239 case 12: {
240 uint64_t bits = _n_tiff_u64(tiff, p);
241 double value = 0.0;
242
243 memcpy(&value, &bits, sizeof(value));
244 out[i] = value;
245 break;
246 }
247 default:
248 return i;
249 }
250 }
251 return n;
252}
253
254int n_tiff_get_ascii(const N_TIFF* tiff, uint16_t tag, char* out, size_t out_len) {
255 const N_TIFF_ENTRY* entry = NULL;
256 size_t n = 0;
257 size_t i = 0;
258
259 __n_assert(out, return -1);
260 if (out_len == 0)
261 return -1;
262 out[0] = '\0';
263 __n_assert(tiff, return -1);
264 entry = n_tiff_find(tiff, tag);
265 if (!entry || entry->type != 2)
266 return -1;
267 n = entry->count < out_len - 1 ? entry->count : out_len - 1;
268 for (i = 0; i < n && tiff->data[entry->offset + i] != '\0'; i++)
269 out[i] = (char)tiff->data[entry->offset + i];
270 out[i] = '\0';
271 return 0;
272}
static void type(N_GUI_CTX *gui, const char *s)
Type a whole string into whatever has focus.
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:272
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:204
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:279
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:263
size_t offset
where the values start in the buffer, already checked to hold them
Definition n_tiff.h:74
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
const unsigned char * data
the buffer, borrowed
Definition n_tiff.h:80
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 len
its length
Definition n_tiff.h:82
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
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
One directory entry.
Definition n_tiff.h:66
Common headers and low-level functions & define.
Generic log system.
static size_t _n_tiff_type_size(uint16_t type)
Bytes one value of a field type takes.
Definition n_tiff.c:41
static uint64_t _n_tiff_u64(const N_TIFF *tiff, const unsigned char *p)
Read a 64 bit value in the buffer's byte order.
Definition n_tiff.c:88
#define N_TIFF_MAX_ENTRIES
Most entries a directory is read for: a real TIFF directory holds tens, a DCP a few dozen; a count pa...
Definition n_tiff.c:36
static uint16_t _n_tiff_u16(const N_TIFF *tiff, const unsigned char *p)
Read a 16 bit value in the buffer's byte order.
Definition n_tiff.c:68
static uint32_t _n_tiff_u32(const N_TIFF *tiff, const unsigned char *p)
Read a 32 bit value in the buffer's byte order.
Definition n_tiff.c:78
Reading the tags of a TIFF structured buffer.