efl/legacy/eet/src/lib/eet_data.c

1766 lines
39 KiB
C

#include "Eet.h"
#define _GNU_SOURCE /* need this for fmemopen & open_memstream */
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <zlib.h>
#include <string.h>
#include <fnmatch.h>
#include <jpeglib.h>
#include <setjmp.h>
#include <zlib.h>
#include <locale.h>
/*
* 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;
}