1 /*
2  * ipdb.h
3  *  Image Viewer PDB file functions.
4  *
5  * Copyright (C) 1997 Eric A. Howe
6  *
7  * This library is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Library General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  *   Authors: Eric A. Howe (mu@trends.net)
22  *            Bryan Henderson 2010
23  */
24 #ifndef IPDB_H_INCLUDED
25 #define IPDB_H_INCLUDED
26 
27 #include <stdio.h>
28 #include <errno.h>
29 
30 /*
31  * Extra error numbers, feed these (or errno values) to ipdb_err()
32  * to get strings.
33  */
34 #define E_BADCOLORS -1
35 #define E_NOTIMAGE  -2
36 #define E_IMAGETHERE    -3
37 #define E_IMAGENOTTHERE -4
38 #define E_TEXTTHERE -5
39 #define E_NOTRECHDR -6
40 #define E_UNKNOWNRECHDR -7
41 #define E_TOOBIGG   -8
42 #define E_TOOBIGM   -9
43 #define E_LAST      -9
44 
45 /*
46  * The standard pdb header.
47  */
48 typedef struct {
49     char      name[32];       /* nul terminated   */
50     uint16_t  flags;          /* 0            */
51     uint16_t  version;        /* 0            */
52     uint32_t  ctime;          /* mac time     */
53     uint32_t  mtime;          /* mac time     */
54     uint32_t  btime;          /* mac time     */
55     uint32_t  mod_num;        /* 0            */
56     uint32_t  app_info;       /* 0            */
57     uint32_t  sort_info;      /* 0            */
58     uint8_t   type[4];        /* vIMG         */
59     uint8_t   id[4];          /* View         */
60     uint32_t  uniq_seed;      /* 0            */
61     uint32_t  next_rec;       /* 0            */
62     uint16_t  num_recs;       /* 1            */
63 } PDBHEAD;
64 #define PDBHEAD_SIZE    (32 + 2*2 + 6*4 + 4 + 4 + 2*4 + 2)
65 
66 /*
67  * Between the pdb header and the image header we find some "mystery" bytes,
68  * these are supposed to be eight byte record headers but sometimes there
69  * are ten bytes.  Version zero files use eight bytes, version 1 files appear
70  * to use ten bytes, files with attached notes (version 2?) use two sets of
71  * eight bytes.  Note that this version isn't the same as the `version' field
72  * in IMAGE, that version only indicates if the file is compressed or not.
73  *
74  * The first four bytes of each piece are a four byte offset to the start
75  * of the corresponding image header or text record; the next three bytes
76  * (40 6f 80) are some kind of magic (they are always the same); the next
77  * byte is zero for image records and 1 for text records; any remaining
78  * mystery bytes (zero or two) are always zero.
79  */
80 typedef struct {
81     uint32_t offset;     /* offset, from zero, to the image  */
82     uint8_t  unknown[3]; /* 40 6f 80             */
83     uint8_t  rec_type;   /* byte seven, TEXT_REC || IMG_REC  */
84     size_t   n_extra;    /* bytes in extra           */
85     uint8_t  *extra;     /* extra unknown end bytes      */
86 } RECHDR;
87 #define IMG_REC     (uint8_t)(0x00)
88 #define TEXT_REC    (uint8_t)(0x01)
89 
90 /*
91  * The image headers.
92  */
93 typedef struct {
94     RECHDR  * r;
95 
96     /*
97      * Whether the image was originally compressed.  Since compressed
98      * data can cross row boundaries we have to uncompress the whole
99      * thing during reads so `data' is always in the uncompressed
100      * (but packed) format.  I think we can just use the `version'
101      * field for this but a little extra paranoia is worth a couple
102      * of bytes. This is also set after a write to indicate if
103      * compression was used.
104      */
105     int       compressed;
106 
107     /*
108      * The actual image header, this starts at `m->offset'.
109      */
110     char      name[32];   /* nul terminated           */
111     uint8_t   version;    /* 0 => uncompressed, 1 => compressed   */
112     uint8_t   type;       /* GRAYSCALE || MONOCHROME      */
113     uint8_t   reserved1[4];   /* zero                 */
114     uint8_t   note[4];    /* zero                 */
115     uint16_t  x_last;     /* zero                 */
116     uint16_t  y_last;     /* zero                 */
117     uint8_t   reserved2[4];   /* zero                 */
118     uint16_t  x_anchor;   /* 0xffff               */
119     uint16_t  y_anchor;   /* 0xffff               */
120     uint16_t  width;      /* pixels (must be 0 mod 16)        */
121     uint16_t  height;     /* pixels               */
122 
123     /*
124      * And finally, the actual image data.  We always store the
125      * image data as 4 pixels per byte uncompressed.  Any compression
126      * or decompression is done at I/O time.
127      */
128     uint8_t  * data;
129 } IMAGE;
130 
131 #define IMAGESIZE   (32 + 1 + 1 + 4 + 4 + 2*2 + 4 + 2*2 + 2*2)
132 
133 /*
134  * Image types for IMAGE.type.
135  */
136 #define IMG_GRAY16  ((uint8_t)2)
137 #define IMG_GRAY    ((uint8_t)0)
138 #define IMG_MONO    ((uint8_t)0xff)
139 
140 const char *
141 ipdb_typeName(uint8_t const type);
142 
143 
144 /*
145  * Compression constants for IMAGE.version.
146  */
147 #define IMG_COMPRESSED      ((uint8_t)0x01)
148 #define IMG_UNCOMPRESSED    ((uint8_t)0x00)
149 
150 /*
151  * The notes record.  If this exists, it will follow the image record.
152  */
153 typedef struct {
154     RECHDR  *r;
155     char    *data;      /* the actual text as a normal string   */
156 } TEXT;
157 
158 /*
159  * One PDB file.  The `t' field will be NULL if there is no note.
160  */
161 typedef struct {
162     PDBHEAD * p;
163     IMAGE   * i;
164     TEXT    * t;
165 } IPDB;
166 
167 /*
168  * Only use four bytes of these.
169  */
170 #define IPDB_vIMG   "vIMG"
171 #define IPDB_View   "View"
172 /*
173  * Only use three bytes of this.
174  */
175 #define IPDB_MYST   "\x40\x6f\x80"
176 
177 /*
178  * Flags for ipdb_write().
179  */
180 #define IPDB_COMPMAYBE  0       /* compress if it does any good */
181 #define IPDB_NOCOMPRESS (1 << 1)    /* don't compress       */
182 #define IPDB_COMPRESS   (1 << 2)    /* compress         */
183 
184 #define ipdb_width(pdb)     ((pdb)->i->width)
185 #define ipdb_height(pdb)    ((pdb)->i->height)
186 #define ipdb_text(pdb)      ((pdb)->t == NULL ? NULL : (pdb)->t->data)
187 #define ipdb_compressed(pdb)    ((pdb)->i->compressed)
188 #define ipdb_ctime(pdb)     ((time_t)((pdb)->p->ctime - UNIXEPOCH))
189 #define ipdb_mtime(pdb)     ((time_t)((pdb)->p->mtime - UNIXEPOCH))
190 #define ipdb_btime(pdb)     ((time_t)((pdb)->p->btime - UNIXEPOCH))
191 #define ipdb_iname(pdb)     ((pdb)->i->name)
192 #define ipdb_pname(pdb)     ((pdb)->p->name)
193 #define ipdb_version(pdb)   ((pdb)->i->version)
194 #define ipdb_type(pdb)      ((pdb)->i->type)
195 #define ipdb_xlast(pdb)     ((pdb)->i->x_last)
196 #define ipdb_ylast(pdb)     ((pdb)->i->y_last)
197 #define ipdb_xanchor(pdb)   ((pdb)->i->x_anchor)
198 #define ipdb_yanchor(pdb)   ((pdb)->i->y_anchor)
199 
200 const char *
201 ipdb_err(int error);
202 
203 size_t
204 ipdb_img_size(IMAGE * const imgP);
205 
206 unsigned int
207 ipdb_img_ppb(IMAGE * const imgP);
208 
209 uint8_t *
210 ipdb_img_row(IMAGE *      const imgP,
211              unsigned int const row);
212 
213 void
214 ipdb_free(IPDB *);
215 
216 IPDB *
217 ipdb_alloc(const char *);
218 
219 void
220 ipdb_clear(IPDB * const pdbP);
221 
222 PDBHEAD *
223 ipdb_pdbhead_alloc(const char * const name);
224 
225 void
226 ipdb_pdbhead_free(PDBHEAD * const headP);
227 
228 IMAGE *
229 ipdb_image_alloc(const char * const name,
230                  int          const type,
231                  int          const w,
232                  int          const h);
233 
234 void
235 ipdb_image_free(IMAGE * const imgP);
236 
237 void
238 ipdb_text_free(TEXT * const textP);
239 
240 TEXT *
241 ipdb_text_alloc(const char * const content);
242 
243 #endif
244