comparison pack.c @ 103:7fefa3a34461

pack.c now directly write to the file
author David Demelier <markand@malikania.fr>
date Tue, 17 Jan 2012 13:38:54 +0100
parents b1a084c030c8
children c66fb578a7c4
comparison
equal deleted inserted replaced
102:735d6c774f7a 103:7fefa3a34461
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 17 */
18 18
19 #include <sys/queue.h>
20 #include <stdio.h> 19 #include <stdio.h>
21 #include <stdlib.h> 20 #include <stdlib.h>
22 #include <stdint.h> 21 #include <stdint.h>
23 #include <stdarg.h> 22 #include <stdarg.h>
24 #include <string.h> 23 #include <string.h>
28 27
29 /* -------------------------------------------------------- 28 /* --------------------------------------------------------
30 * structure definitions 29 * structure definitions
31 * -------------------------------------------------------- */ 30 * -------------------------------------------------------- */
32 31
33 /* 32 typedef void (*ConvertFn)(void *);
34 * Conversion function pointer.
35 */
36 typedef void (*convert_fn)(void *);
37
38 /*
39 * Item structure store the integer into the largest data type
40 * uint64_t.
41 */
42
43 struct item {
44 size_t size; /* 8, 16, 32 or 64 bits? */
45 uint64_t i; /* the data */
46 convert_fn conv; /* conversion function */
47 STAILQ_ENTRY(item) next;
48 };
49
50 /*
51 * List of item structure.
52 */
53
54 STAILQ_HEAD(item_list, item);
55 33
56 /* -------------------------------------------------------- 34 /* --------------------------------------------------------
57 * prototypes 35 * prototypes
58 * -------------------------------------------------------- */ 36 * -------------------------------------------------------- */
59 37
60 static int pack_item_add(struct item_list *, const struct item *);
61 static int pack_parse(struct item_list *, const char *, va_list);
62 static size_t pack_getsize(char); 38 static size_t pack_getsize(char);
63 static convert_fn pack_getconvert(char); 39 static ConvertFn pack_getconvert_by_tok(char);
40 static ConvertFn pack_getconvert_by_size(size_t);
64 static void pack_convert16(void *); 41 static void pack_convert16(void *);
65 static void pack_convert32(void *); 42 static void pack_convert32(void *);
66 static void pack_convert64(void *); 43 static void pack_convert64(void *);
67 static int pack_fatal(struct item_list *); 44 static void pack_write_one(int, FILE *, uint64_t, size_t);
45 static void pack_write_multiple(int, FILE *, uint8_t *, int, size_t);
68 46
69 /* -------------------------------------------------------- 47 /* --------------------------------------------------------
70 * private functions 48 * private functions
71 * -------------------------------------------------------- */ 49 * -------------------------------------------------------- */
72 50
79 */ 57 */
80 58
81 static struct integer { 59 static struct integer {
82 char tok; /* format char */ 60 char tok; /* format char */
83 size_t tocopy; /* size */ 61 size_t tocopy; /* size */
84 convert_fn convert; /* conversion function */ 62 ConvertFn convert; /* conversion function */
85 } sizes[] = { 63 } sizes[] = {
86 { 'c', sizeof (uint8_t), NULL }, 64 { 'c', sizeof (uint8_t), NULL },
87 { 's', sizeof (uint16_t), &pack_convert16 }, 65 { 's', sizeof (uint16_t), &pack_convert16 },
88 { 'i', sizeof (uint32_t), &pack_convert32 }, 66 { 'i', sizeof (uint32_t), &pack_convert32 },
89 { 'l', sizeof (uint64_t), &pack_convert64 } 67 { 'l', sizeof (uint64_t), &pack_convert64 }
90 }; 68 };
91
92 /*
93 * Try to append a new item to the list. The function create a new item
94 * object since the pack_parse() use a stack'ed item and not an
95 * allocated object. Returns 0 or -1 on failure.
96 */
97
98 static int
99 pack_item_add(struct item_list *list, const struct item *item)
100 {
101 struct item *res;
102
103 if ((res = malloc(sizeof (struct item))) == NULL)
104 return -1;
105
106 res->size = item->size;
107 res->i = item->i;
108 res->conv = item->conv;
109
110 STAILQ_INSERT_TAIL(list, res, next);
111
112 return 0;
113 }
114 69
115 /* 70 /*
116 * Parse the format, return 0 on success or -1 on failure. 71 * Parse the format, return 0 on success or -1 on failure.
117 */ 72 */
118 73
149 ++p; \ 104 ++p; \
150 } else \ 105 } else \
151 nelem = 1; \ 106 nelem = 1; \
152 } while (/* CONSTCOND */ 0) 107 } while (/* CONSTCOND */ 0)
153 108
154 static int 109 /*
155 pack_parse(struct item_list *list, const char *fmt, va_list ap) 110 * Get the appropriate size associated with the `tok' character. If
156 { 111 * the token is not found the result is 0.
112 */
113
114 static size_t
115 pack_getsize(char tok)
116 {
117 struct integer *s;
118 unsigned int i;
119
120 for (s = sizes, i = 0; i < LENGTH(sizes); ++s, ++i)
121 if (s->tok == tok)
122 return s->tocopy;
123
124 return 0;
125 }
126
127 /*
128 * Return the conversion function.
129 */
130
131 static ConvertFn
132 pack_getconvert_by_tok(char tok)
133 {
134 struct integer *s;
135 unsigned int i;
136
137 for (s = sizes, i = 0; i < LENGTH(sizes); ++s, ++i)
138 if (s->tok == tok)
139 return s->convert;
140
141 return NULL;
142 }
143
144 /*
145 * Same but by size.
146 */
147
148 static ConvertFn
149 pack_getconvert_by_size(size_t size)
150 {
151 struct integer *s;
152 unsigned int i;
153
154 for (s = sizes, i = 0; i < LENGTH(sizes); ++s, ++i)
155 if (s->tocopy == size)
156 return s->convert;
157
158 return NULL;
159 }
160
161 /*
162 * Conversion functions. They reverse the bytes without any
163 * check.
164 */
165
166 static void
167 pack_convert16(void *obj)
168 {
169 uint16_t *x = obj;
170
171 *x = pack_swap16(*x);
172 }
173
174 static void
175 pack_convert32(void *obj)
176 {
177 uint32_t *x = obj;
178
179 *x = pack_swap32(*x);
180 }
181
182 static void
183 pack_convert64(void *obj)
184 {
185 uint64_t *x = obj;
186
187 *x = pack_swap64(*x);
188 }
189
190 static void
191 pack_write_one(int ptype, FILE *fp, uint64_t it, size_t size)
192 {
193 uint64_t cv = it;
194
195 if (ptype != PACK_HOST_BYTEORDER) {
196 ConvertFn conv = pack_getconvert_by_size(size);
197
198 if (conv != NULL)
199 conv(&cv);
200 }
201
202 fwrite(&cv, size, 1, fp);
203 }
204
205 static void
206 pack_write_multiple(int ptype, FILE *fp, uint8_t *arr, int length, size_t size)
207 {
208 uint64_t cv;
209 int i;
210 ConvertFn conv = NULL;
211
212 if (ptype != PACK_HOST_BYTEORDER)
213 conv = pack_getconvert_by_size(size);
214
215 for (i = 0; i < length; ++i) {
216 cv = arr[i * size];
217 if (conv != NULL)
218 conv(&cv);
219
220 fwrite(&cv, size, 1, fp);
221 }
222 }
223
224
225 /* --------------------------------------------------------
226 * public functions
227 * -------------------------------------------------------- */
228
229 /*
230 * Function that writes everything to the file `path'. These functions
231 * does not append to the file, so if you want successive call to append
232 * variables use fpack instead.
233 * Returns 0 on success or -1 on failure.
234 */
235
236 int
237 pack_write(int ptype, const char *path, const char *fmt, ...)
238 {
239 va_list ap;
240 int status;
241
242 va_start(ap, fmt);
243 status = pack_vwrite(ptype, path, fmt, ap);
244 va_end(ap);
245
246 return status;
247 }
248
249 int
250 pack_vwrite(int ptype, const char *path, const char *fmt, va_list ap)
251 {
252 FILE *fp;
253 int status;
254
255 if ((fp = fopen(path, "w+b")) == NULL)
256 return -1;
257
258 status = pack_vfwrite(ptype, fp, fmt, ap);
259 fclose(fp);
260
261 return status;
262 }
263
264 /*
265 * Write to a file that is already open. The function does not call
266 * fclose() so you need to do it yourself later.
267 */
268
269 int
270 pack_fwrite(int ptype, FILE *fp, const char *fmt, ...)
271 {
272 va_list ap;
273 int status;
274
275 va_start(ap, fmt);
276 status = pack_vfwrite(ptype, fp, fmt, ap);
277 va_end(ap);
278
279 return status;
280 }
281
282 int
283 pack_vfwrite(int ptype, FILE *fp, const char *fmt, va_list ap)
284 {
285 int nelem;
286 size_t size;
287 char tok;
157 const char *p; 288 const char *p;
158 char tok;
159 struct item item;
160 int nelem;
161
162 STAILQ_INIT(list);
163 289
164 for (p = fmt; *p != '\0'; ++p) { 290 for (p = fmt; *p != '\0'; ++p) {
165 if (isspace(*p)) 291 if (isspace(*p))
166 continue; 292 continue;
167 293
168 tok = *p; 294 tok = *p;
169 item.size = pack_getsize(tok); 295 size = pack_getsize(tok);
170 296
171 /* Bad character */ 297 /* Bad character */
172 if (item.size == 0) 298 if (size == 0)
173 continue; 299 continue;
174 300
175 PACK_GETNELEM(nelem, p); 301 PACK_GETNELEM(nelem, p);
176 if (nelem == 0) 302 if (nelem == 0)
177 continue; 303 continue;
179 /* 305 /*
180 * If i is 1, then we only have one integer, if it's more 306 * If i is 1, then we only have one integer, if it's more
181 * than one, user may have given an array of something else. 307 * than one, user may have given an array of something else.
182 */ 308 */
183 if (nelem == 1) { 309 if (nelem == 1) {
184 PACK_GETARG(item.i, ap, tok); 310 uint64_t item;
185 item.conv = pack_getconvert(tok); 311
186 312 PACK_GETARG(item, ap, tok);
187 if (pack_item_add(list, &item) < 0) 313 pack_write_one(ptype, fp, item, size);
188 return pack_fatal(list);
189 } else { 314 } else {
190 uint8_t *arr = va_arg(ap, void *); 315 uint8_t *arr;
191 int i; 316
192 317 arr = va_arg(ap, uint8_t *);
193 for (i = 0; i < nelem; ++i) { 318 pack_write_multiple(ptype, fp, arr, nelem, size);
194 memcpy(&item.i, &arr[i * item.size], item.size);
195 if (pack_item_add(list, &item) < 0)
196 return pack_fatal(list);
197 }
198 } 319 }
199 } 320 }
200 321
201 return 0; 322 return 0;
202 }
203
204 /*
205 * Get the appropriate size associated with the `tok' character. If
206 * the token is not found the result is 0.
207 */
208
209 static size_t
210 pack_getsize(char tok)
211 {
212 struct integer *s;
213 unsigned int i;
214
215 for (s = sizes, i = 0; i < LENGTH(sizes); ++s, ++i)
216 if (s->tok == tok)
217 return s->tocopy;
218
219 return 0;
220 }
221
222 /*
223 * Return the conversion function.
224 */
225
226 static convert_fn
227 pack_getconvert(char tok)
228 {
229 struct integer *s;
230 unsigned int i;
231
232 for (s = sizes, i = 0; i < LENGTH(sizes); ++s, ++i)
233 if (s->tok == tok)
234 return s->convert;
235
236 return NULL;
237 }
238
239 /*
240 * Conversion functions. They reverse the bytes without any
241 * check.
242 */
243
244 static void
245 pack_convert16(void *obj)
246 {
247 uint16_t *x = obj;
248
249 *x = pack_swap16(*x);
250 }
251
252 static void
253 pack_convert32(void *obj)
254 {
255 uint32_t *x = obj;
256
257 *x = pack_swap32(*x);
258 }
259
260 static void
261 pack_convert64(void *obj)
262 {
263 uint64_t *x = obj;
264
265 *x = pack_swap64(*x);
266 }
267
268 static int
269 pack_fatal(struct item_list *list)
270 {
271 struct item *item, *tmp;
272
273 STAILQ_FOREACH_SAFE(item, list, next, tmp)
274 free(item);
275
276 return -1;
277 }
278
279 /* --------------------------------------------------------
280 * public functions
281 * -------------------------------------------------------- */
282
283 /*
284 * Function that writes everything to the file `path'. These functions
285 * does not append to the file, so if you want successive call to append
286 * variables use fpack instead.
287 * Returns 0 on success or -1 on failure.
288 */
289
290 int
291 pack_write(int ptype, const char *path, const char *fmt, ...)
292 {
293 va_list ap;
294 int status;
295
296 va_start(ap, fmt);
297 status = pack_vwrite(ptype, path, fmt, ap);
298 va_end(ap);
299
300 return status;
301 }
302
303 int
304 pack_vwrite(int ptype, const char *path, const char *fmt, va_list ap)
305 {
306 FILE *fp;
307 int status;
308
309 if ((fp = fopen(path, "w+b")) == NULL)
310 return -1;
311
312 status = pack_vfwrite(ptype, fp, fmt, ap);
313 fclose(fp);
314
315 return status;
316 }
317
318 /*
319 * Write to a file that is already open. The function does not call
320 * fclose() so you need to do it yourself later.
321 */
322
323 int
324 pack_fwrite(int ptype, FILE *fp, const char *fmt, ...)
325 {
326 va_list ap;
327 int status;
328
329 va_start(ap, fmt);
330 status = pack_vfwrite(ptype, fp, fmt, ap);
331 va_end(ap);
332
333 return status;
334 }
335
336 int
337 pack_vfwrite(int ptype, FILE *fp, const char *fmt, va_list ap)
338 {
339 struct item_list list;
340 int status;
341
342 if ((status = pack_parse(&list, fmt, ap)) == 0) {
343 struct item *item, *tmp;
344
345 STAILQ_FOREACH_SAFE(item, &list, next, tmp) {
346 /* 8 bits does not need to be converted */
347 if (ptype != PACK_HOST_BYTEORDER && item->conv != NULL)
348 item->conv(&item->i);
349
350 fwrite(&item->i, item->size, 1, fp);
351
352 free(item);
353 }
354 }
355
356 return status;
357 } 323 }
358 324
359 /* 325 /*
360 * Function that read the binary file and restore values to the same format 326 * Function that read the binary file and restore values to the same format
361 * as pack functions. Arguments must be pointer of enough space to store 327 * as pack functions. Arguments must be pointer of enough space to store
408 pack_vfread(int ptype, FILE *fp, const char *fmt, va_list ap) 374 pack_vfread(int ptype, FILE *fp, const char *fmt, va_list ap)
409 { 375 {
410 const char *p; 376 const char *p;
411 void *ptr; 377 void *ptr;
412 size_t tocopy; 378 size_t tocopy;
413 convert_fn convert; 379 ConvertFn convert;
414 380
415 for (p = fmt; *p != '\0'; ++p) { 381 for (p = fmt; *p != '\0'; ++p) {
416 char tok; 382 char tok;
417 int nelem, i; 383 int nelem, i;
418 384
436 402
437 for (i = 0; i < nelem; ++i) { 403 for (i = 0; i < nelem; ++i) {
438 fread((char *) ptr + (tocopy * i), tocopy, 1, fp); 404 fread((char *) ptr + (tocopy * i), tocopy, 1, fp);
439 405
440 /* Convert if needed */ 406 /* Convert if needed */
441 convert = pack_getconvert(tok); 407 convert = pack_getconvert_by_tok(tok);
442 if (ptype != PACK_HOST_BYTEORDER && convert != NULL) 408 if (ptype != PACK_HOST_BYTEORDER && convert != NULL)
443 convert((char *) ptr + (tocopy * i)); 409 convert((char *) ptr + (tocopy * i));
444 } 410 }
445 } 411 }
446 412