Mercurial > code
view pack.c @ 175:73d8f140bc86
Add some getters
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 12 Sep 2013 13:36:12 +0200 |
parents | 1167cd06b475 |
children |
line wrap: on
line source
/* * pack.c -- endian dependant binary file reader * * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include "pack.h" /* Compilation tunables */ #if !defined(PACK_CHKSIZE) # define PACK_CHKSIZE (256) /* default chunk size */ #endif /* Type */ enum pack_type { TYPE_FP, TYPE_FIXEDBUF, TYPE_AUTOBUF }; struct pack_sc { enum pack_type type; /* which kind of work */ short endian; /* endian */ /* if TYPE_FP */ FILE * fp; /* file to write */ /* else */ char * buf; /* bytes converted */ size_t size; /* current length */ size_t allocated; /* allocated size */ /* for reading */ unsigned int position; /* position where to read */ }; struct pack_value { /* for writing */ int nelem; /* number of element */ int size; /* size of elements */ uint64_t value; /* direct value */ char * array; /* array of values */ /* for reading */ char * dst; /* destination */ }; #define SC_SET(s, tp, ed, f, b, al) do { \ memset((s), 0, sizeof (struct pack_sc)); \ (s)->type = tp; \ (s)->endian = ed; \ (s)->fp = f; \ (s)->buf = b; \ (s)->allocated = al; \ } while (/* CONSTCOND */ 0) #define TOKNARG(tok, nelem) do { \ if (p[1] == '[') { \ char *end; \ \ /* Can statically write the number, or pass it */ \ if (p[2] != ']') { \ nelem = (int)strtol(&p[2], &end, 10); \ p = end; \ } else { \ nelem = va_arg(ap, int); \ while (!isspace(*p) && *p != ']' && *p != '\0') \ ++p; \ } \ } else \ nelem = 1; \ } while (/* CONSTCOND */ 0) #define TOKSIZE(tok, size) do { \ switch (tok) { \ case 'c': \ size = sizeof (uint8_t); \ break; \ case 's': \ size = sizeof (uint16_t); \ break; \ case 'i': \ size = sizeof (uint32_t); \ break; \ case 'l': \ size = sizeof (uint64_t); \ break; \ default: \ size = 0; \ break; \ } \ } while (/* CONSTCOND */ 0) #define TOKGETARG(serv, tok, val, ap) do { \ if ((val)->nelem == 1 && serv == writeto) { \ uint64_t item; \ switch (tok) { \ case 'c': case 's': case 'i': \ item = va_arg(ap, int); \ break; \ case 'l': \ item = va_arg(ap, uint64_t); \ break; \ default: \ item = 0; \ break; \ } \ \ memset(&(val)->value, 0, sizeof (uint64_t)); \ memcpy(&(val)->value, &item, (val)->size); \ (val)->array = (char *)&(val)->value; \ } else { /* read is always a pointer */ \ (val)->array = va_arg(ap, void *); \ (val)->dst = (val)->array; \ } \ } while (/* CONSTCOND */ 0) #define GETCONV(ed, size, conv) do { \ if (ed != PACK_HOST_BYTEORDER) { \ switch ((size)) { \ case (sizeof (uint16_t)): \ conv = conv16; break; \ case (sizeof (uint32_t)): \ conv = conv32; break; \ case (sizeof (uint64_t)): \ conv = conv64; break; \ default: \ conv = NULL; \ } \ } else \ conv = NULL; \ } while (/* CONSTCOND */ 0) static void conv16(void *item) { *(uint16_t *)item = pack_swap16(*(uint16_t *)item); } static void conv32(void *item) { *(uint32_t *)item = pack_swap32(*(uint32_t *)item); } static void conv64(void *item) { *(uint64_t *)item = pack_swap64(*(uint64_t *)item); } /* * Function that write content into the buffer or file depending * on the calling function. Returns the number of bytes written * or -1 on failure. */ static long writeto(struct pack_sc *sc, struct pack_value *val) { void (*conv)(void *); int i; uint64_t item; long nbytes = 0; /* Get converter */ GETCONV(sc->endian, val->size, conv); for (i = 0; i < val->nelem; ++i) { item = 0; memcpy(&item, &val->array[i * val->size], val->size); if (conv != NULL) conv(&item); switch (sc->type) { case TYPE_FP: fwrite(&item, val->size, 1, sc->fp); break; case TYPE_AUTOBUF: if (sc->size + val->size >= sc->allocated) { sc->allocated += PACK_CHKSIZE; sc->buf = realloc(sc->buf, sc->allocated); if (sc->buf == NULL) return -1; } /* FALLTHROUGH */ case TYPE_FIXEDBUF: if (sc->size + val->size <= sc->allocated) { memcpy(&sc->buf[sc->size], &item, val->size); sc->size += val->size; } else continue; default: break; } nbytes += val->size; } return nbytes; } /* * Function that read the file or buffer and fill array. */ static long readfrom(struct pack_sc *sc, struct pack_value *val) { void (*conv)(void *); int i, oktoread; uint64_t item; long nbytes = 0; /* Get converter */ GETCONV(sc->endian, val->size, conv); for (i = 0; i < val->nelem; ++i) { item = oktoread = 0; switch (sc->type) { case TYPE_FP: fread(&item, val->size, 1, sc->fp); oktoread = 1; break; case TYPE_FIXEDBUF: if (sc->position + val->size <= sc->allocated) { memcpy(&item, &sc->buf[sc->position], val->size); sc->position += val->size; oktoread = 1; } break; default: break; } if (conv != NULL) conv(&item); if (oktoread) { memcpy(&val->dst[i * val->size], &item, val->size); nbytes += val->size; } } return nbytes; } /* * Function that analyses the format, write or read the values depending * on the calling functions. */ static long packit(struct pack_sc *sc, long (*func)(struct pack_sc *, struct pack_value *), const char *fmt, va_list ap) { struct pack_value val; const char *p; int tok; long nbytes = 0, rv; for (p = fmt; *p != '\0'; ++p) { tok = *p; if (isspace(*p)) continue; TOKNARG(tok, val.nelem); TOKSIZE(tok, val.size); if (val.size == 0 || val.nelem == 0) continue; TOKGETARG(func, tok, &val, ap); if ((rv = func(sc, &val)) == -1) return -1; nbytes += rv; } return nbytes; } long pack_write(short ed, const char *path, const char *fmt, ...) { va_list ap; long rv; va_start(ap, fmt); rv = pack_vwrite(ed, path, fmt, ap); va_end(ap); return rv; } long pack_vwrite(short ed, const char *path, const char *fmt, va_list ap) { FILE *fp; long rv; if ((fp = fopen(path, "wb")) == NULL) return -1; rv = pack_vfwrite(ed, fp, fmt, ap); fclose(fp); return rv; } long pack_fwrite(short ed, FILE *fp, const char *fmt, ...) { va_list ap; long rv; va_start(ap, fmt); rv = pack_vfwrite(ed, fp, fmt, ap); va_end(ap); return rv; } long pack_vfwrite(short ed, FILE *fp, const char *fmt, va_list ap) { struct pack_sc sc; SC_SET(&sc, TYPE_FP, ed, fp, NULL, 0); return packit(&sc, writeto, fmt, ap); } long pack_swrite(short ed, char *buf, size_t max, const char *fmt, ...) { va_list ap; long rv; va_start(ap, fmt); rv = pack_vswrite(ed, buf, max, fmt, ap); va_end(ap); return rv; } long pack_vswrite(short ed, char *buf, size_t max, const char *fmt, va_list ap) { struct pack_sc sc; SC_SET(&sc, TYPE_FIXEDBUF, ed, NULL, buf, max); return packit(&sc, writeto, fmt, ap); } long pack_aswrite(short ed, char **bufp, const char *fmt, ...) { va_list ap; long rv; va_start(ap, fmt); rv = pack_vaswrite(ed, bufp, fmt, ap); va_end(ap); return rv; } long pack_vaswrite(short ed, char **bufp, const char *fmt, va_list ap) { struct pack_sc sc; int rv; SC_SET(&sc, TYPE_AUTOBUF, ed, NULL, NULL, PACK_CHKSIZE); if ((sc.buf = malloc(PACK_CHKSIZE)) == NULL) return -1; rv = packit(&sc, writeto, fmt, ap); *bufp = sc.buf; return rv; } long pack_read(short ed, const char *path, const char *fmt, ...) { va_list ap; long rv; va_start(ap, fmt); rv = pack_vread(ed, path, fmt, ap); va_end(ap); return rv; } long pack_vread(short ed, const char *path, const char *fmt, va_list ap) { FILE *fp; long rv; if ((fp = fopen(path, "rb")) == NULL) return -1; rv = pack_vfread(ed, fp, fmt, ap); fclose(fp); return rv; } long pack_fread(short ed, FILE *fp, const char *fmt, ...) { va_list ap; long rv; va_start(ap, fmt); rv = pack_vfread(ed, fp, fmt, ap); va_end(ap); return rv; } long pack_vfread(short ed, FILE *fp, const char *fmt, va_list ap) { struct pack_sc sc; SC_SET(&sc, TYPE_FP, ed, fp, NULL, 0); return packit(&sc, readfrom, fmt, ap); } long pack_sread(short ed, const char *buf, size_t max, const char *fmt, ...) { va_list ap; long rv; va_start(ap, fmt); rv = pack_vsread(ed, buf, max, fmt, ap); va_end(ap); return rv; } long pack_vsread(short ed, const char *buf, size_t max, const char *fmt, va_list ap) { struct pack_sc sc; SC_SET(&sc, TYPE_FIXEDBUF, ed, NULL, (char *)buf, max); return packit(&sc, readfrom, fmt, ap); }