1 /*
2 *
3 * Copyright (C) 1997 Eric A. Howe
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 * Authors: Eric A. Howe (mu@trends.net)
20 * Bryan Henderson, 2010
21 */
22 #define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
23 #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */
24 #define _BSD_SOURCE /* Ensure strdup() is in <string.h> */
25 #include <assert.h>
26 #include <time.h>
27 #include <string.h>
28
29 #include "mallocvar.h"
30 #include "nstring.h"
31 #include "ipdb.h"
32
33 typedef uint32_t pilot_time_t;
34
35
36
37
38 static unsigned int
imgPpb(IMAGE * const imgP)39 imgPpb(IMAGE * const imgP) {
40 /*----------------------------------------------------------------------------
41 Pixels per byte
42 -----------------------------------------------------------------------------*/
43 return
44 imgP->type == IMG_GRAY ? 4 :
45 imgP->type == IMG_GRAY16 ? 2 :
46 8;
47 }
48
49
50
51 unsigned int
ipdb_img_ppb(IMAGE * const imgP)52 ipdb_img_ppb(IMAGE * const imgP) {
53 /*----------------------------------------------------------------------------
54 Pixels per byte
55 -----------------------------------------------------------------------------*/
56 return imgPpb(imgP);
57 }
58
59
60
61 size_t
ipdb_img_size(IMAGE * const imgP)62 ipdb_img_size(IMAGE * const imgP) {
63 /*----------------------------------------------------------------------------
64 Size (in bytes) of an image's data.
65 -----------------------------------------------------------------------------*/
66 return (size_t)(imgP->width / imgPpb(imgP) * imgP->height);
67 }
68
69
70
71 /*
72 * Return the start of row `r'.
73 */
74 uint8_t *
ipdb_img_row(IMAGE * const imgP,unsigned int const row)75 ipdb_img_row(IMAGE * const imgP,
76 unsigned int const row) {
77
78 return &imgP->data[(row) * imgP->width / imgPpb(imgP)];
79 }
80
81
82
83 #define img_row(i, r)
84
85 static pilot_time_t const unixepoch = (66*365+17)*24*3600;
86 /* The unix epoch in Mac time (the Mac epoch is 00:00 UTC 1904.01.01).
87 The 17 is the number of leap years.
88 */
89
90 static const char * const errorDesc[] = {
91 /* E_BADCOLORS */
92 "Invalid palette, only {0x00, 0x55, 0xAA, 0xFF} allowed.",
93
94 /* E_NOTIMAGE */
95 "Not an image file.",
96
97 /* E_IMAGETHERE */
98 "Image record already present, logic error.",
99
100 /* E_IMAGENOTTHERE */
101 "Image record required before text record, logic error.",
102
103 /* E_TEXTTHERE */
104 "Text record already present, logic error.",
105
106 /* E_NOTRECHDR */
107 "Invalid record header encountered.",
108
109 /* E_UNKNOWNRECHDR */
110 "Unknown record header.",
111
112 /* E_TOOBIGG */
113 "Image too big, maximum size approx. 640*400 gray pixels.",
114
115 /* E_TOOBIGM */
116 "Image too big, maximum size approx. 640*800 monochrome pixels.",
117 };
118
119
120
121 const char *
ipdb_err(int const e)122 ipdb_err(int const e) {
123
124 if (e < 0)
125 return e >= E_LAST ? errorDesc[-e - 1] : "unknown error";
126 else
127 return strerror(e);
128 }
129
130
131
132 static void
rechdr_free(RECHDR * const recP)133 rechdr_free(RECHDR * const recP) {
134
135 if (recP) {
136 free(recP->extra);
137 free(recP);
138 }
139 }
140
141
142
143 void
ipdb_image_free(IMAGE * const imgP)144 ipdb_image_free(IMAGE * const imgP) {
145
146 if (imgP) {
147 rechdr_free(imgP->r);
148 free(imgP->data);
149 free(imgP);
150 }
151 }
152
153
154
155 void
ipdb_text_free(TEXT * const textP)156 ipdb_text_free(TEXT * const textP) {
157
158 if (textP) {
159 rechdr_free(textP->r);
160 free(textP->data);
161 free(textP);
162 }
163 }
164
165
166
167 void
ipdb_pdbhead_free(PDBHEAD * const headP)168 ipdb_pdbhead_free(PDBHEAD * const headP) {
169
170 free(headP);
171 }
172
173
174
175 void
ipdb_clear(IPDB * const pdbP)176 ipdb_clear(IPDB * const pdbP) {
177
178 if (pdbP) {
179 ipdb_image_free(pdbP->i);
180 ipdb_text_free(pdbP->t);
181 ipdb_pdbhead_free(pdbP->p);
182 }
183 }
184
185
186
187 void
ipdb_free(IPDB * const pdbP)188 ipdb_free(IPDB * const pdbP) {
189
190 ipdb_clear(pdbP);
191 free(pdbP);
192 }
193
194
195
196 PDBHEAD *
ipdb_pdbhead_alloc(const char * const name)197 ipdb_pdbhead_alloc(const char * const name) {
198
199 PDBHEAD * pdbHeadP;
200
201 MALLOCVAR(pdbHeadP);
202
203 if (pdbHeadP) {
204 MEMSZERO(pdbHeadP);
205
206 STRSCPY(pdbHeadP->name, name == NULL ? "unnamed" : name);
207
208 /*
209 * All of the Image Viewer pdb files that I've come across have
210 * 3510939142U (1997.08.16 14:38:22 UTC) here. I don't know where
211 * this bizarre date comes from but the real date works fine so
212 * I'm using it.
213 */
214 pdbHeadP->ctime =
215 pdbHeadP->mtime = (pilot_time_t)time(NULL) + unixepoch;
216
217 MEMSCPY(&pdbHeadP->type, IPDB_vIMG);
218 MEMSCPY(&pdbHeadP->id, IPDB_View);
219 }
220 return pdbHeadP;
221 }
222
223
224
225 static RECHDR *
rechdr_alloc(int const type,uint32_t const offset)226 rechdr_alloc(int const type,
227 uint32_t const offset) {
228
229 /*
230 * We never produce the `extra' bytes (we only read them from a file)
231 * so there is no point allocating them here.
232 */
233
234 RECHDR * recHdrP;
235
236 MALLOCVAR(recHdrP);
237
238 if (recHdrP) {
239 MEMSSET(recHdrP, 0);
240
241 recHdrP->offset = offset;
242 recHdrP->rec_type = (uint8_t)(0xff & type);
243 MEMSCPY(&recHdrP->unknown, IPDB_MYST);
244 }
245 return recHdrP;
246 }
247
248
249
250 /*
251 * The offset will be patched up as needed elsewhere.
252 */
253 #define IMGOFFSET (PDBHEAD_SIZE + 8)
254
255
256
257 IMAGE *
ipdb_image_alloc(const char * const name,int const type,int const w,int const h)258 ipdb_image_alloc(const char * const name,
259 int const type,
260 int const w,
261 int const h) {
262
263 bool failed;
264 IMAGE * imgP;
265
266 failed = false;
267
268 MALLOCVAR(imgP);
269
270 if (imgP) {
271 MEMSZERO(imgP);
272
273 STRSCPY(imgP->name, name == NULL ? "unnamed" : name);
274 imgP->type = type;
275 imgP->x_anchor = 0xffff;
276 imgP->y_anchor = 0xffff;
277 imgP->width = w;
278 imgP->height = h;
279
280 imgP->r = rechdr_alloc(IMG_REC, IMGOFFSET);
281
282 if (imgP->r) {
283 if (w != 0 && h != 0) {
284 MALLOCARRAY(imgP->data, w * h);
285
286 if (imgP->data != NULL) {
287 memset(imgP->data, 0, sizeof(*(imgP->data)) * w * h);
288 } else
289 failed = true;
290 }
291 if (failed)
292 rechdr_free(imgP->r);
293 } else
294 failed = true;
295
296 if (failed)
297 ipdb_image_free(imgP);
298 } else
299 failed = true;
300
301 return failed ? NULL : imgP;
302 }
303
304
305
306 TEXT *
ipdb_text_alloc(const char * const content)307 ipdb_text_alloc(const char * const content) {
308
309 TEXT * textP;
310 bool failed;
311
312 failed = false;
313 /*
314 * The offset will be patched up later on when we know what it
315 * should be.
316 */
317
318 MALLOCVAR(textP);
319
320 if (textP) {
321 MEMSZERO(textP);
322
323 textP->r = rechdr_alloc(TEXT_REC, 0);
324
325 if (textP->r) {
326 if (content) {
327 textP->data = strdup(content);
328
329 if (!textP->data)
330 failed = true;
331 }
332 if (failed)
333 rechdr_free(textP->r);
334 } else
335 failed = true;
336
337 if (failed)
338 ipdb_text_free(textP);
339 } else
340 failed = true;
341
342 return failed ? NULL : textP;
343 }
344
345
346
347 IPDB *
ipdb_alloc(const char * const name)348 ipdb_alloc(const char * const name) {
349
350 IPDB * pdbP;
351 bool failed;
352
353 failed = false;
354
355 MALLOCVAR(pdbP);
356
357 if (pdbP) {
358 MEMSZERO(pdbP);
359
360 if (name) {
361 pdbP->p = ipdb_pdbhead_alloc(name);
362
363 if (!pdbP->p)
364 failed = true;
365 }
366 if (failed)
367 ipdb_free(pdbP);
368 } else
369 failed = true;
370
371 return failed ? NULL : pdbP;
372 }
373
374
375
376 const char *
ipdb_typeName(uint8_t const type)377 ipdb_typeName(uint8_t const type) {
378
379 switch (type) {
380 case IMG_GRAY16: return "16 Bit Grayscale"; break;
381 case IMG_GRAY: return "Grayscale"; break;
382 case IMG_MONO: return "Monochrome"; break;
383 default: return "???";
384 }
385 }
386