#include "Eet.h" #define _GNU_SOURCE /* need this for fmemopen & open_memstream */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * rotuines for doing data -> struct and struct -> data conversion * * types: * * basic types: * a sequence of... * * char * short * int * long long * float * double * unsigned char * unsigned short * unsigned int * unsgined long long * string * * groupings: * multiple entries ordered as... * * fixed size array [ of basic types ] * variable size array [ of basic types ] * linked list [ of basic types ] * hash table [ of basic types ] * * need to provide builder/accessor funcs for: * * list_next * list_append * * hash_foreach * hash_add * */ /*---*/ typedef struct _Eet_Data_Element Eet_Data_Element; typedef struct _Eet_Data_Basic_Type_Decoder Eet_Data_Basic_Type_Decoder; typedef struct _Eet_Data_Chunk Eet_Data_Chunk; typedef struct _Eet_Data_Stream Eet_Data_Stream; typedef struct _JPEG_error_mgr *emptr; /*---*/ struct _Eet_Data_Basic_Type_Decoder { int size; int (*get) (void *src, void *src_end, void *dest); void *(*put) (void *src, int *size_ret); }; struct _Eet_Data_Chunk { char *name; int size; void *data; }; struct _Eet_Data_Stream { void *data; int size; int pos; }; struct _Eet_Data_Descriptor { char *name; int size; struct { void *(*list_next) (void *l); void *(*list_append) (void *l, void *d); void *(*list_data) (void *l); void (*hash_foreach) (void *h, int (*func) (void *h, const char *k, void *dt, void *fdt), void *fdt); void *(*hash_add) (void *h, const char *k, void *d); } func; struct { int num; Eet_Data_Element *set; } elements; }; struct _Eet_Data_Element { char *name; int type; int group_type; int offset; int count; char *counter_name; Eet_Data_Descriptor *subtype; }; struct _JPEG_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; /*---*/ static void _JPEGFatalErrorHandler(j_common_ptr cinfo); static void _JPEGErrorHandler(j_common_ptr cinfo); static void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level); static void *eet_data_image_jpeg_rgb_decode(void *data, int size, int *w, int *h); static void *eet_data_image_jpeg_alpha_decode(void *data, int size, unsigned int *d, int *w, int *h); static void *eet_data_image_lossless_convert(int *size, void *data, int w, int h, int alpha); static void *eet_data_image_lossless_compressed_convert(int *size, void *data, int w, int h, int alpha, int compression); static void *eet_data_image_jpeg_convert(int *size, void *data, int w, int h, int alpha, int quality); static void *eet_data_image_jpeg_alpha_convert(int *size, void *data, int w, int h, int alpha, int quality); static int eet_data_get_char(void *src, void *src_end, void *dest); static void *eet_data_put_char(void *src, int *size_ret); static int eet_data_get_short(void *src, void *src_end, void *dest); static void *eet_data_put_short(void *src, int *size_ret); static int eet_data_get_int(void *src, void *src_end, void *dest); static void *eet_data_put_int(void *src, int *size_ret); static int eet_data_get_long_long(void *src, void *src_end, void *dest); static void *eet_data_put_long_long(void *src, int *size_ret); static int eet_data_get_float(void *src, void *src_end, void *dest); static void *eet_data_put_float(void *src, int *size_ret); static int eet_data_get_double(void *src, void *src_end, void *dest); static void *eet_data_put_double(void *src, int *size_ret); static int eet_data_get_string(void *src, void *src_end, void *dest); static void *eet_data_put_string(void *src, int *size_ret); static int eet_data_get_type(int type, void *src, void *src_end, void *dest); static void *eet_data_put_type(int type, void *src, int *size_ret); static Eet_Data_Chunk *eet_data_chunk_get(void *src, int size); static Eet_Data_Chunk *eet_data_chunk_new(void *data, int size, char *name); static void eet_data_chunk_free(Eet_Data_Chunk *chnk); static Eet_Data_Stream *eet_data_stream_new(void); static void eet_data_stream_write(Eet_Data_Stream *ds, void *data, int size); static void eet_data_stream_free(Eet_Data_Stream *ds); static void eet_data_chunk_put(Eet_Data_Chunk *chnk, Eet_Data_Stream *ds); /*---*/ const Eet_Data_Basic_Type_Decoder eet_coder[] = { {sizeof(char), eet_data_get_char, eet_data_put_char }, {sizeof(short), eet_data_get_short, eet_data_put_short }, {sizeof(int), eet_data_get_int, eet_data_put_int }, {sizeof(long long), eet_data_get_long_long, eet_data_put_long_long}, {sizeof(float), eet_data_get_float, eet_data_put_float }, {sizeof(double), eet_data_get_double, eet_data_put_double }, {sizeof(char), eet_data_get_char, eet_data_put_char }, {sizeof(short), eet_data_get_short, eet_data_put_short }, {sizeof(int), eet_data_get_int, eet_data_put_int }, {sizeof(long long), eet_data_get_long_long, eet_data_put_long_long}, {sizeof(char *), eet_data_get_string, eet_data_put_string } }; static int words_bigendian = -1; /*---*/ #define SWAP64(x) (x) = \ ((((x) & 0x00000000000000ff ) << 56) |\ (((x) & 0x000000000000ff00 ) << 40) |\ (((x) & 0x0000000000ff0000 ) << 24) |\ (((x) & 0x00000000ff000000 ) << 8) |\ (((x) & 0x000000ff00000000 ) >> 8) |\ (((x) & 0x0000ff0000000000 ) >> 24) |\ (((x) & 0x00ff000000000000 ) >> 40) |\ (((x) & 0xff00000000000000 ) >> 56)) #define SWAP32(x) (x) = \ ((((x) & 0x000000ff ) << 24) |\ (((x) & 0x0000ff00 ) << 8) |\ (((x) & 0x00ff0000 ) >> 8) |\ (((x) & 0xff000000 ) >> 24)) #define SWAP16(x) (x) = \ ((((x) & 0x00ff ) << 8) |\ (((x) & 0xff00 ) >> 8)) #define CONV8(x) #define CONV16(x) {if (words_bigendian) SWAP16(x);} #define CONV32(x) {if (words_bigendian) SWAP32(x);} #define CONV64(x) {if (words_bigendian) SWAP64(x);} /*---*/ static void _JPEGFatalErrorHandler(j_common_ptr cinfo) { emptr errmgr; errmgr = (emptr) cinfo->err; /* cinfo->err->output_message(cinfo);*/ longjmp(errmgr->setjmp_buffer, 1); return; } static void _JPEGErrorHandler(j_common_ptr cinfo) { emptr errmgr; errmgr = (emptr) cinfo->err; /* cinfo->err->output_message(cinfo);*/ /* longjmp(errmgr->setjmp_buffer, 1);*/ return; } static void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level) { emptr errmgr; errmgr = (emptr) cinfo->err; /* cinfo->err->output_message(cinfo);*/ /* longjmp(errmgr->setjmp_buffer, 1);*/ return; msg_level = 0; } static void * eet_data_image_jpeg_rgb_decode(void *data, int size, int *w, int *h) { unsigned int *d; struct jpeg_decompress_struct cinfo; struct _JPEG_error_mgr jerr; unsigned char *ptr, *line[16], *tdata; unsigned int *ptr2; int x, y, l, i, scans, count, prevy; FILE *f; f = fmemopen(data, (size_t)size, "r"); if (!f) return NULL; cinfo.err = jpeg_std_error(&(jerr.pub)); jerr.pub.error_exit = _JPEGFatalErrorHandler; jerr.pub.emit_message = _JPEGErrorHandler2; jerr.pub.output_message = _JPEGErrorHandler; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); fclose(f); return NULL; } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, f); jpeg_read_header(&cinfo, TRUE); cinfo.do_fancy_upsampling = FALSE; cinfo.do_block_smoothing = FALSE; jpeg_start_decompress(&cinfo); /* head decoding */ *w = cinfo.output_width; *h = cinfo.output_height; /* end head decoding */ /* data decoding */ if (cinfo.rec_outbuf_height > 16) { jpeg_destroy_decompress(&cinfo); fclose(f); return NULL; } tdata = malloc((*w) * 16 * 3); if (!tdata) { jpeg_destroy_decompress(&cinfo); fclose(f); return NULL; } d = malloc((*w) * (*h) * 4); if (!d) { free(tdata); jpeg_destroy_decompress(&cinfo); fclose(f); return NULL; } ptr2 = d; count = 0; prevy = 0; if (cinfo.output_components == 3) { for (i = 0; i < cinfo.rec_outbuf_height; i++) line[i] = tdata + (i * (*w) * 3); for (l = 0; l < (*h); l += cinfo.rec_outbuf_height) { jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); scans = cinfo.rec_outbuf_height; if (((*h) - l) < scans) scans = (*h) - l; ptr = tdata; for (y = 0; y < scans; y++) { for (x = 0; x < (*w); x++) { *ptr2 = (0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) << 8) | (ptr[2]); ptr += 3; ptr2++; } } } } else if (cinfo.output_components == 1) { for (i = 0; i < cinfo.rec_outbuf_height; i++) line[i] = tdata + (i * (*w)); for (l = 0; l < (*h); l += cinfo.rec_outbuf_height) { jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); scans = cinfo.rec_outbuf_height; if (((*h) - l) < scans) scans = (*h) - l; ptr = tdata; for (y = 0; y < scans; y++) { for (x = 0; x < (*w); x++) { *ptr2 = (0xff000000) | ((ptr[0]) << 16) | ((ptr[0]) << 8) | (ptr[0]); ptr++; ptr2++; } } } } free(tdata); fclose(f); /* end data decoding */ jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return d; } static void * eet_data_image_jpeg_alpha_decode(void *data, int size, unsigned int *d, int *w, int *h) { struct jpeg_decompress_struct cinfo; struct _JPEG_error_mgr jerr; unsigned char *ptr, *line[16], *tdata; unsigned int *ptr2; int x, y, l, i, scans, count, prevy; FILE *f; f = fmemopen(data, (size_t)size, "r"); if (!f) return NULL; cinfo.err = jpeg_std_error(&(jerr.pub)); jerr.pub.error_exit = _JPEGFatalErrorHandler; jerr.pub.emit_message = _JPEGErrorHandler2; jerr.pub.output_message = _JPEGErrorHandler; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); fclose(f); return NULL; } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, f); jpeg_read_header(&cinfo, TRUE); cinfo.do_fancy_upsampling = FALSE; cinfo.do_block_smoothing = FALSE; jpeg_start_decompress(&cinfo); /* head decoding */ if ((*w) != cinfo.output_width) { jpeg_destroy_decompress(&cinfo); fclose(f); return NULL; } if ((*h) != cinfo.output_height) { jpeg_destroy_decompress(&cinfo); fclose(f); return NULL; } *w = cinfo.output_width; *h = cinfo.output_height; /* end head decoding */ /* data decoding */ if (cinfo.rec_outbuf_height > 16) { jpeg_destroy_decompress(&cinfo); fclose(f); return NULL; } tdata = malloc((*w) * 16 * 3); if (!tdata) { jpeg_destroy_decompress(&cinfo); fclose(f); return NULL; } ptr2 = d; count = 0; prevy = 0; if (cinfo.output_components == 3) { for (i = 0; i < cinfo.rec_outbuf_height; i++) line[i] = tdata + (i * (*w) * 3); for (l = 0; l < (*h); l += cinfo.rec_outbuf_height) { jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); scans = cinfo.rec_outbuf_height; if (((*h) - l) < scans) scans = (*h) - l; ptr = tdata; for (y = 0; y < scans; y++) { for (x = 0; x < (*w); x++) { *ptr2 = ((*ptr2) & 0x00ffffff) | (((ptr[0] + ptr[1] + ptr[2]) / 3) << 24); ptr += 3; ptr2++; } } } } else if (cinfo.output_components == 1) { for (i = 0; i < cinfo.rec_outbuf_height; i++) line[i] = tdata + (i * (*w)); for (l = 0; l < (*h); l += cinfo.rec_outbuf_height) { jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); scans = cinfo.rec_outbuf_height; if (((*h) - l) < scans) scans = (*h) - l; ptr = tdata; for (y = 0; y < scans; y++) { for (x = 0; x < (*w); x++) { *ptr2 = ((*ptr2) & 0x00ffffff) | ((ptr[0]) << 24); ptr++; ptr2++; } } } } free(tdata); fclose(f); /* end data decoding */ jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return d; } static void * eet_data_image_lossless_convert(int *size, void *data, int w, int h, int alpha) { if (words_bigendian == -1) { unsigned long int v; v = htonl(0x12345678); if (v == 0x12345678) words_bigendian = 1; else words_bigendian = 0; } { unsigned char *d; int *header; d = malloc((w * h * 4) + (8 * 4)); if (!d) return NULL; header = (int *)d; header[0] = 0xac1dfeed; header[1] = w; header[2] = h; header[3] = alpha; header[4] = 0; memcpy(d + 32, data, w * h * 4); if (words_bigendian) { int i; for (i = 0; i < ((w * h) + 8); i++) SWAP32(header[i]); } *size = ((w * h * 4) + (8 * 4)); return d; } } static void * eet_data_image_lossless_compressed_convert(int *size, void *data, int w, int h, int alpha, int compression) { if (words_bigendian == -1) { unsigned long int v; v = htonl(0x12345678); if (v == 0x12345678) words_bigendian = 1; else words_bigendian = 0; } { unsigned char *d; unsigned char *comp; int *header; int ret; uLongf buflen; d = malloc((w * h * 4) + (8 * 4)); if (!d) return NULL; buflen = (((w * h * 101) / 100) + 3) * 4; comp = malloc(buflen); if (!comp) { free(d); return NULL; } header = (int *)d; header[0] = 0xac1dfeed; header[1] = w; header[2] = h; header[3] = alpha; header[4] = compression; memcpy(d + 32, data, w * h * 4); if (words_bigendian) { int i; for (i = 0; i < ((w * h) + 8); i++) SWAP32(header[i]); } ret = compress2((Bytef *)comp, &buflen, (Bytef *)(d + 32), (uLong)(w * h * 4), compression); if (buflen > (w * h * 4)) { free(comp); *size = ((w * h * 4) + (8 * 4)); return d; } memcpy(d + 32, comp, buflen); *size = (8 * 4) + buflen; free(comp); return d; } } static void * eet_data_image_jpeg_convert(int *size, void *data, int w, int h, int alpha, int quality) { int *ptr; char *d = NULL; size_t sz = 0; struct _JPEG_error_mgr jerr; JSAMPROW *jbuf; struct jpeg_compress_struct cinfo; FILE *f; unsigned char *buf; f = open_memstream(&d, &sz); if (!f) return NULL; buf = malloc(3 * w); if (!buf) { fclose(f); if (d) free(d); return NULL; } cinfo.err = jpeg_std_error(&(jerr.pub)); jerr.pub.error_exit = _JPEGFatalErrorHandler; jerr.pub.emit_message = _JPEGErrorHandler2; jerr.pub.output_message = _JPEGErrorHandler; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&cinfo); if (buf) free(buf); fclose(f); if (d) free(d); return NULL; } jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, f); cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); ptr = data; while (cinfo.next_scanline < cinfo.image_height) { int i, j; /* convert scaline from ARGB to RGB packed */ for (j = 0, i = 0; i < w; i++) { buf[j++] = ((*ptr) >> 16) & 0xff; buf[j++] = ((*ptr) >> 8) & 0xff; buf[j++] = ((*ptr)) & 0xff; ptr++; } jbuf = (JSAMPROW *) (&buf); jpeg_write_scanlines(&cinfo, jbuf, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); *size = sz; if (buf) free(buf); fclose(f); return d; } static void * eet_data_image_jpeg_alpha_convert(int *size, void *data, int w, int h, int alpha, int quality) { unsigned char *d1, *d2; unsigned char *d; int *header; int sz1, sz2; if (words_bigendian == -1) { unsigned long int v; v = htonl(0x12345678); if (v == 0x12345678) words_bigendian = 1; else words_bigendian = 0; } { int *ptr; char *d = NULL; size_t sz = 0; struct _JPEG_error_mgr jerr; JSAMPROW *jbuf; struct jpeg_compress_struct cinfo; FILE *f; unsigned char *buf; f = open_memstream(&d, &sz); if (!f) return NULL; buf = malloc(3 * w); if (!buf) { fclose(f); if (d) free(d); return NULL; } cinfo.err = jpeg_std_error(&(jerr.pub)); jerr.pub.error_exit = _JPEGFatalErrorHandler; jerr.pub.emit_message = _JPEGErrorHandler2; jerr.pub.output_message = _JPEGErrorHandler; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&cinfo); if (buf) free(buf); fclose(f); if (d) free(d); return NULL; } jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, f); cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); ptr = data; while (cinfo.next_scanline < cinfo.image_height) { int i, j; /* convert scaline from ARGB to RGB packed */ for (j = 0, i = 0; i < w; i++) { buf[j++] = ((*ptr) >> 16) & 0xff; buf[j++] = ((*ptr) >> 8) & 0xff; buf[j++] = ((*ptr)) & 0xff; ptr++; } jbuf = (JSAMPROW *) (&buf); jpeg_write_scanlines(&cinfo, jbuf, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); if (buf) free(buf); fclose(f); d1 = d; sz1 = sz; } { int *ptr; char *d = NULL; size_t sz = 0; struct _JPEG_error_mgr jerr; JSAMPROW *jbuf; struct jpeg_compress_struct cinfo; FILE *f; unsigned char *buf; f = open_memstream(&d, &sz); if (!f) { free(d1); return NULL; } buf = malloc(3 * w); if (!buf) { fclose(f); if (d) free(d); free(d1); return NULL; } cinfo.err = jpeg_std_error(&(jerr.pub)); jerr.pub.error_exit = _JPEGFatalErrorHandler; jerr.pub.emit_message = _JPEGErrorHandler2; jerr.pub.output_message = _JPEGErrorHandler; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&cinfo); if (buf) free(buf); fclose(f); if (d) free(d); free(d1); return NULL; } jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, f); cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 1; cinfo.in_color_space = JCS_GRAYSCALE; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); ptr = data; while (cinfo.next_scanline < cinfo.image_height) { int i, j; /* convert scaline from ARGB to RGB packed */ for (j = 0, i = 0; i < w; i++) { buf[j++] = ((*ptr) >> 24) & 0xff; ptr++; } jbuf = (JSAMPROW *) (&buf); jpeg_write_scanlines(&cinfo, jbuf, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); if (buf) free(buf); fclose(f); d2 = d; sz2 = sz; } d = malloc(12 + sz1 + sz2); if (!d) { free(d1); free(d2); return NULL; } header = (int *)d; header[0] = 0xbeeff00d; header[1] = sz1; header[2] = sz2; if (words_bigendian) { int i; for (i = 0; i < ((w * h) + 3); i++) SWAP32(header[i]); } memcpy(d + 12, d1, sz1); memcpy(d + 12 + sz1, d2, sz2); free(d1); free(d2); *size = 12 + sz1 + sz2; return d; } /* CHAR TYPE */ static int eet_data_get_char(void *src, void *src_end, void *dst) { char *s, *d; if ((src + sizeof(char)) > src_end) return -1; s = (char *)src; d = (char *)dst; *s = *d; CONV8(*s); return sizeof(char); } static void * eet_data_put_char(void *src, int *size_ret) { char *s, *d; d = (char *)malloc(sizeof(char)); if (!d) return NULL; s = (char *)src; *d = *s; CONV8(*d); *size_ret = sizeof(char); return d; } /* SHORT TYPE */ static int eet_data_get_short(void *src, void *src_end, void *dst) { short *s, *d; short tmp; if ((src + sizeof(short)) > src_end) return -1; s = (short *)src; d = (short *)dst; /* alignment fixup */ if ((int)s & (sizeof(short) - 1)) { memcpy(&tmp, s, sizeof(short)); s = &tmp; } *d = *s; CONV16(*d); return sizeof(short); } static void * eet_data_put_short(void *src, int *size_ret) { short *s, *d; d = (short *)malloc(sizeof(short)); if (!d) return NULL; s = (short *)src; *d = *s; CONV16(*d); *size_ret = sizeof(short); return d; } /* INT TYPE */ static int eet_data_get_int(void *src, void *src_end, void *dst) { int *s, *d; int tmp; if ((src + sizeof(int)) > src_end) return -1; s = (int *)src; d = (int *)dst; /* alignment fixup */ if ((int)s & (sizeof(int) - 1)) { memcpy(&tmp, s, sizeof(int)); s = &tmp; } *d = *s; CONV32(*d); return sizeof(int); } static void * eet_data_put_int(void *src, int *size_ret) { int *s, *d; d = (int *)malloc(sizeof(int)); if (!d) return NULL; s = (int *)src; *d = *s; CONV32(*d); *size_ret = sizeof(int); return d; } /* LONG LONG TYPE */ static int eet_data_get_long_long(void *src, void *src_end, void *dst) { long long *s, *d; long long tmp; if ((src + sizeof(long long)) > src_end) return -1; s = (long long *)src; d = (long long *)dst; /* alignment fixup */ if ((int)s & (sizeof(long long) - 1)) { memcpy(&tmp, s, sizeof(long long)); s = &tmp; } *d = *s; CONV64(*d); return sizeof(long long); } static void * eet_data_put_long_long(void *src, int *size_ret) { long long *s, *d; d = (long long *)malloc(sizeof(long long)); if (!d) return NULL; s = (long long *)src; *d = *s; CONV64(*d); *size_ret = sizeof(long long); return d; } /* STRING TYPE */ static int eet_data_get_string(void *src, void *src_end, void *dst) { char *s, **d, *p; int len; s = (char *)src; d = (char **)dst; p = s; len = 0; while ((p < (char *)src_end) && (*p != 0)) {len++; p++;} *d = malloc(len + 1); if (!(*d)) return -1; memcpy(*d, s, len); (*d)[len] = 0; return len + 1; } static void * eet_data_put_string(void *src, int *size_ret) { char *s, *d; int len; if (!src) src = ""; s = (char *)(*((char **)src)); len = strlen(s); d = malloc(len + 1); if (!d) return NULL; strcpy(d, s); *size_ret = len + 1; return d; } /* FLOAT TYPE */ static int eet_data_get_float(void *src, void *src_end, void *dst) { float *d; char *s, *str, *p, *prev_locale; int len; s = (char *)src; d = (float *)dst; p = s; len = 0; while ((p < (char *)src_end) && (*p != 0)) {len++; p++;} str = malloc(len + 1); if (!str) return -1; memcpy(str, s, len); str[len] = 0; prev_locale = setlocale(LC_NUMERIC, "C"); *d = (float)atof(str); if (prev_locale) setlocale(LC_NUMERIC, prev_locale); free(str); return len + 1; } static void * eet_data_put_float(void *src, int *size_ret) { float *s; char *d, buf[64], *prev_locale; int len; s = (float *)src; prev_locale = setlocale(LC_NUMERIC, "C"); snprintf(buf, sizeof(buf), "%16.16f", (double)(*s)); if (prev_locale) setlocale(LC_NUMERIC, prev_locale); len = strlen(buf); d = malloc(len + 1); if (!d) return NULL; strcpy(d, buf); *size_ret = len + 1; return d; } /* DOUBLE TYPE */ static int eet_data_get_double(void *src, void *src_end, void *dst) { double *d; char *s, *str, *p, *prev_locale; int len; s = (char *)src; d = (double *)dst; p = s; len = 0; while ((p < (char *)src_end) && (*p != 0)) {len++; p++;} str = malloc(len + 1); if (!str) return -1; memcpy(str, s, len); str[len] = 0; prev_locale = setlocale(LC_NUMERIC, "C"); *d = (double)atof(str); if (prev_locale) setlocale(LC_NUMERIC, prev_locale); free(str); return len + 1; } static void * eet_data_put_double(void *src, int *size_ret) { double *s; char *d, buf[128], *prev_locale; int len; s = (double *)src; prev_locale = setlocale(LC_NUMERIC, "C"); snprintf(buf, sizeof(buf), "%32.32f", (double)(*s)); if (prev_locale) setlocale(LC_NUMERIC, prev_locale); len = strlen(buf); d = malloc(len + 1); if (!d) return NULL; strcpy(d, buf); *size_ret = len + 1; return d; } static int eet_data_get_type(int type, void *src, void *src_end, void *dest) { int ret; ret = eet_coder[type - 1].get(src, src_end, dest); return ret; } static void * eet_data_put_type(int type, void *src, int *size_ret) { void *ret; ret = eet_coder[type - 1].put(src, size_ret); return ret; } /* chunk format... * * char[4] = "CHnK"; * int = chunk size (including magic string); * char[] = chuck magic/name string (0 byte terminated); * ... sub-chunks (a chunk can contain chuncks recusrively) ... * or * ... payload data ... * */ static Eet_Data_Chunk * eet_data_chunk_get(void *src, int size) { Eet_Data_Chunk *chnk; char *s; int ret1, ret2; if (!src) return NULL; if (size <= 8) return NULL; chnk = calloc(1, sizeof(Eet_Data_Chunk)); if (!chnk) return NULL; s = src; if ((s[0] != 'C') || (s[1] != 'H') || (s[2] != 'n') || (s[3] != 'K')) { free(chnk); return NULL; } ret1 = eet_data_get_type(EET_T_INT, (void *)(s + 4), (void *)(s + size), &(chnk->size)); if (ret1 <= 0) { free(chnk); return NULL; } if ((chnk->size < 0) || ((chnk->size + 8) > size)) { free(chnk); return NULL; } ret2 = eet_data_get_type(EET_T_STRING, (void *)(s + 8), (void *)(s + size), &(chnk->name)); if (ret2 <= 0) { free(chnk); return NULL; } chnk->data = src + 4 + ret1 + ret2; chnk->size -= ret2; return chnk; } static Eet_Data_Chunk * eet_data_chunk_new(void *data, int size, char *name) { Eet_Data_Chunk *chnk; if (!name) return NULL; chnk = calloc(1, sizeof(Eet_Data_Chunk)); if (!chnk) return NULL; chnk->name = strdup(name); chnk->size = size; chnk->data = data; return chnk; } static void eet_data_chunk_free(Eet_Data_Chunk *chnk) { if (chnk->name) free(chnk->name); free(chnk); } static Eet_Data_Stream * eet_data_stream_new(void) { Eet_Data_Stream *ds; ds = calloc(1, sizeof(Eet_Data_Stream)); if (!ds) return NULL; return ds; } static void eet_data_stream_free(Eet_Data_Stream *ds) { if (ds->data) free(ds->data); free(ds); } static void eet_data_stream_write(Eet_Data_Stream *ds, void *data, int size) { char *p; if ((ds->pos + size) > ds->size) { ds->data = realloc(ds->data, ds->size + size + 256); if (!ds->data) { ds->pos = 0; ds->size = 0; return; } ds->size = ds->size + size + 256; } p = ds->data; memcpy(p + ds->pos, data, size); ds->pos += size; } static void eet_data_chunk_put(Eet_Data_Chunk *chnk, Eet_Data_Stream *ds) { int *size; int s; int size_ret; if (!chnk->data) return; /* chunk head */ eet_data_stream_write(ds, "CHnK", 4); /* size of chunk payload data + name */ s = strlen(chnk->name) + 1 + chnk->size; size = eet_data_put_int(&s, &size_ret); if (size) { eet_data_stream_write(ds, size, size_ret); free(size); } /* write chunk name */ eet_data_stream_write(ds, chnk->name, strlen(chnk->name) + 1); /* write payload */ eet_data_stream_write(ds, chnk->data, chnk->size); } /*---*/ int eet_data_image_write(Eet_File *ef, char *name, void *data, int w, int h, int alpha, int compress, int quality, int lossy) { void *d = NULL; int size = 0; d = eet_data_image_encode(data, &size, w, h, alpha, compress, quality, lossy); if (d) { int v; v = eet_write(ef, name, d, size, 0); free(d); return v; } return 0; } void * eet_data_image_read(Eet_File *ef, char *name, int *w, int *h, int *alpha, int *compress, int *quality, int *lossy) { void *data; int size; unsigned int *d = NULL; int header[8]; data = eet_read(ef, name, &size); if (!data) return NULL; d = eet_data_image_decode(data, size, w, h, alpha, compress, quality, lossy); free(data); return d; } void * eet_data_image_encode(void *data, int *size_ret, int w, int h, int alpha, int compress, int quality, int lossy) { void *d = NULL; int size = 0; if (lossy == 0) { if (compress <= 0) d = eet_data_image_lossless_convert(&size, data, w, h, alpha); else d = eet_data_image_lossless_compressed_convert(&size, data, w, h, alpha, compress); } else { if (!alpha) d = eet_data_image_jpeg_convert(&size, data, w, h, alpha, quality); else d = eet_data_image_jpeg_alpha_convert(&size, data, w, h, alpha, quality); } if (size_ret) *size_ret = size; return d; } void * eet_data_image_decode(void *data, int size, int *w, int *h, int *alpha, int *compress, int *quality, int *lossy) { unsigned int *d = NULL; int header[8]; if (words_bigendian == -1) { unsigned long int v; v = htonl(0x12345678); if (v == 0x12345678) words_bigendian = 1; else words_bigendian = 0; } if (size < 32) return NULL; memcpy(header, data, 32); if (words_bigendian) { int i; for (i = 0; i < 8; i++) SWAP32(header[i]); } if (header[0] == 0xac1dfeed) { int iw, ih, al, cp; unsigned int *body; iw = header[1]; ih = header[2]; al = header[3]; cp = header[4]; if ((iw > 8192) || (ih > 8192)) return NULL; if ((cp == 0) && (size < ((iw * ih * 4) + 32))) return NULL; body = ((unsigned int *)data) + 8; d = malloc(iw * ih * 4); if (!d) return NULL; if (!cp) { memcpy(d, body, iw * ih * 4); if (words_bigendian) { int x; for (x = 0; x < (iw * ih); x++) SWAP32(d[x]); } } else { uLongf dlen; dlen = iw * ih * 4; uncompress((Bytef *)d, &dlen, (Bytef *)body, (uLongf)(size - 32)); if (words_bigendian) { int x; for (x = 0; x < (iw * ih); x++) SWAP32(d[x]); } } if (d) { if (w) *w = iw; if (h) *h = ih; if (alpha) *alpha = al; if (compress) *compress = cp; if (lossy) *lossy = 0; if (quality) *quality = 100; } } else if (header[0] == 0xbeeff00d) { int iw = 0, ih = 0; int sz1, sz2; unsigned char *dt; sz1 = header[1]; sz2 = header[2]; dt = data; dt += 12; d = eet_data_image_jpeg_rgb_decode(dt, sz1, &iw, &ih); if (d) { dt += sz1; eet_data_image_jpeg_alpha_decode(dt, sz2, d, &iw, &ih); } if (d) { if (w) *w = iw; if (h) *h = ih; if (alpha) *alpha = 1; if (compress) *compress = 0; if (lossy) *lossy = 1; if (quality) *quality = 75; } } else { int iw = 0, ih = 0; d = eet_data_image_jpeg_rgb_decode(data, size, &iw, &ih); if (d) { if (w) *w = iw; if (h) *h = ih; if (alpha) *alpha = 0; if (compress) *compress = 0; if (lossy) *lossy = 1; if (quality) *quality = 75; } } return d; } Eet_Data_Descriptor * eet_data_descriptor_new(char *name, int size, void *(*func_list_next) (void *l), void *(*func_list_append) (void *l, void *d), void *(*func_list_data) (void *l), void (*func_hash_foreach) (void *h, int (*func) (void *h, const char *k, void *dt, void *fdt), void *fdt), void *(*func_hash_add) (void *h, const char *k, void *d)) { Eet_Data_Descriptor *edd; edd = calloc(1, sizeof(Eet_Data_Descriptor)); edd->name = strdup(name); edd->size = size; edd->func.list_next = func_list_next; edd->func.list_append = func_list_append; edd->func.list_data = func_list_data; edd->func.hash_foreach = func_hash_foreach; edd->func.hash_add = func_hash_add; return edd; } void eet_data_descriptor_free(Eet_Data_Descriptor *edd) { int i; if (edd->name) free(edd->name); for (i = 0; i < edd->elements.num; i++) { if (edd->elements.set[i].name) free(edd->elements.set[i].name); if (edd->elements.set[i].counter_name) free(edd->elements.set[i].counter_name); } if (edd->elements.set) free(edd->elements.set); free(edd); } void eet_data_descriptor_element_add(Eet_Data_Descriptor *edd, char *name, int type, int group_type, int offset, int count, char *counter_name, Eet_Data_Descriptor *subtype) { Eet_Data_Element *ede; edd->elements.num++; edd->elements.set = realloc(edd->elements.set, edd->elements.num * sizeof(Eet_Data_Element)); if (!edd->elements.set) return; ede = &(edd->elements.set[edd->elements.num - 1]); ede->name = strdup(name); ede->type = type; ede->group_type = group_type; ede->offset = offset; ede->count = count; if (counter_name) ede->counter_name = strdup(counter_name); else ede->counter_name = NULL; ede->subtype = subtype; } void * eet_data_read(Eet_File *ef, Eet_Data_Descriptor *edd, char *name) { void *data_dec; void *data; int size; data = eet_read(ef, name, &size); if (!data) return NULL; data_dec = eet_data_descriptor_decode(edd, data, size); free(data); return data_dec; } int eet_data_write(Eet_File *ef, Eet_Data_Descriptor *edd, char *name, void *data, int compress) { void *data_enc; int size; int val; data_enc = eet_data_descriptor_encode(edd, data, &size); if (!data_enc) return 0; val = eet_write(ef, name, data_enc, size, compress); free(data_enc); return val; } void * eet_data_descriptor_decode(Eet_Data_Descriptor *edd, void *data_in, int size_in) { void *data; char *p; int size; Eet_Data_Chunk *chnk; if (words_bigendian == -1) { unsigned long int v; v = htonl(0x12345678); if (v == 0x12345678) words_bigendian = 1; else words_bigendian = 0; } data = calloc(1, edd->size); if (!data) return NULL; chnk = eet_data_chunk_get(data_in, size_in); if (!chnk) { free(data); return NULL; } if (strcmp(chnk->name, edd->name)) { eet_data_chunk_free(chnk); free(data); return NULL; } p = chnk->data; size = size_in - (4 + 4 + strlen(chnk->name) + 1); while (size > 0) { Eet_Data_Chunk *echnk; int i; /* get next data chunk */ echnk = eet_data_chunk_get(p, size); if (!echnk) { /* FIXME: partially built data struct - leak!!!! */ free(data); eet_data_chunk_free(chnk); return NULL; } for (i = 0; i < edd->elements.num; i++) { Eet_Data_Element *ede; ede = &(edd->elements.set[i]); if (!strcmp(echnk->name, ede->name)) { if (ede->group_type == EET_G_UNKNOWN) { int ret; void *data_ret; if ((ede->type >= EET_T_CHAR) && (ede->type <= EET_T_STRING)) { ret = eet_data_get_type(ede->type, echnk->data, ((char *)echnk->data) + echnk->size, ((char *)data) + ede->offset); } else if (ede->subtype) { void **ptr; data_ret = eet_data_descriptor_decode(ede->subtype, echnk->data, echnk->size); ptr = (void **)(((char *)data) + ede->offset); *ptr = (void *)data_ret; } } else { switch (ede->group_type) { case EET_G_ARRAY: case EET_G_VAR_ARRAY: { printf("ARRAY TYPE NOT IMPLIMENTED YET!!!\n"); } break; case EET_G_LIST: { int ret; void *list = NULL; void **ptr; void *data_ret; ptr = (void **)(((char *)data) + ede->offset); list = *ptr; data_ret = NULL; if ((ede->type >= EET_T_CHAR) && (ede->type <= EET_T_STRING)) { data_ret = calloc(1, eet_coder[ede->type].size); if (data_ret) { ret = eet_data_get_type(ede->type, echnk->data, ((char *)echnk->data) + echnk->size, data_ret); if (ret <= 0) { free(data_ret); data_ret = NULL; } } } else if (ede->subtype) { data_ret = eet_data_descriptor_decode(ede->subtype, echnk->data, echnk->size); } if (data_ret) { list = edd->func.list_append(list, data_ret); *ptr = list; } } break; case EET_G_HASH: printf("HASH TYPE NOT IMPLIMENTED YET!!!\n"); break; default: break; } } break; } } /* advance to next chunk */ p += (4 + 4 + strlen(echnk->name) + 1 + echnk->size); size -= (4 + 4 + strlen(echnk->name) + 1 + echnk->size); eet_data_chunk_free(echnk); } eet_data_chunk_free(chnk); return data; } void * eet_data_descriptor_encode(Eet_Data_Descriptor *edd, void *data_in, int *size_ret) { Eet_Data_Chunk *chnk; Eet_Data_Stream *ds; int i; void *cdata; int csize; if (words_bigendian == -1) { unsigned long int v; v = htonl(0x12345678); if (v == 0x12345678) words_bigendian = 1; else words_bigendian = 0; } ds = eet_data_stream_new(); for (i = 0; i < edd->elements.num; i++) { Eet_Data_Element *ede; Eet_Data_Chunk *echnk; void *data; int size; ede = &(edd->elements.set[i]); data = NULL; if (ede->group_type == EET_G_UNKNOWN) { if ((ede->type >= EET_T_CHAR) && (ede->type <= EET_T_STRING)) data = eet_data_put_type(ede->type, ((char *)data_in) + ede->offset, &size); else if (ede->subtype) data = eet_data_descriptor_encode(ede->subtype, *((char **)(((char *)data_in) + ede->offset)), &size); if (data) { echnk = eet_data_chunk_new(data, size, ede->name); eet_data_chunk_put(echnk, ds); eet_data_chunk_free(echnk); free(data); data = NULL; } } else { switch (ede->group_type) { case EET_G_ARRAY: case EET_G_VAR_ARRAY: { printf("ARRAY TYPE NOT IMPLIMENTED YET!!!\n"); } break; case EET_G_LIST: { void *l; l = *((void **)(((char *)data_in) + ede->offset)); for (; l; l = edd->func.list_next(l)) { if ((ede->type >= EET_T_CHAR) && (ede->type <= EET_T_STRING)) data = eet_data_put_type(ede->type, edd->func.list_data(l), &size); else if (ede->subtype) data = eet_data_descriptor_encode(ede->subtype, edd->func.list_data(l), &size); if (data) { echnk = eet_data_chunk_new(data, size, ede->name); eet_data_chunk_put(echnk, ds); eet_data_chunk_free(echnk); free(data); data = NULL; } } } break; case EET_G_HASH: { printf("HASH TYPE NOT IMPLIMENTED YET!!!\n"); } break; default: break; } } } chnk = eet_data_chunk_new(ds->data, ds->pos, edd->name); ds->data = NULL; ds->size = 0; eet_data_stream_free(ds); ds = eet_data_stream_new(); eet_data_chunk_put(chnk, ds); cdata = ds->data; csize = ds->pos; ds->data = NULL; ds->size = 0; eet_data_stream_free(ds); *size_ret = csize; eet_data_chunk_free(chnk); return cdata; }