Mercurial > code
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 |