**********************************************************/
/*
- * graphics code generator wrapper
- *
* This library forms the socket for run-time loadable device plugins.
*/
#include "config.h"
#endif
-/* experimenting with in-memory compression so as to write compressed files to channels and strings */
-// #define IN_MEM_COMPRESSION
+/* experimenting with in-memory deflation so as to write compressed files to channels and strings */
+// #define IN_MEM_COMPRESSION
#include <stdarg.h>
#include <stdlib.h>
#endif
static unsigned char z_file_header[] =
{0x1f, 0x8b, /*magic*/ Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE};
+
+static z_stream z_strm;
+static unsigned char *df;
+static unsigned int dfallocated;
+static unsigned long int crc;
#endif
#endif
#include "gvcproc.h"
#include "logic.h"
+#ifdef WITH_CODEGENS
+extern FILE* Output_file;
+#endif
+
static const int PAGE_ALIGN = 4095; /* align to a 4K boundary (less one), typical for Linux, Mac OS X and Windows memory allocation */
-size_t gvdevice_write (GVJ_t * job, const unsigned char *s, unsigned int len)
+static size_t gvdevice_write_no_z (GVJ_t * job, const unsigned char *s, unsigned int len)
{
-#ifdef IN_MEM_COMPRESSION
- if (job->flags & GVDEVICE_COMPRESSED_FORMAT) {
-#ifdef HAVE_LIBZ
- static unsigned char *dest;
- static unsigned int destAllocated;
- unsigned long int destLen;
-
- destLen = compressBound(len);
- if (destAllocated < destLen) {
- dest = realloc(dest, len+100);
- if (! dest) {
- fprintf(stderr, "memory allocation failure\n");
- return 0;
- }
- }
-
- if (compress (dest, &destLen, s, len) != Z_OK) {
- fprintf(stderr, "failure compressing output string\n");
- return 0;
- }
-
- len = destLen;
- s = dest;
-#endif
- }
-#endif
-
if (job->gvc->write_fn) /* externally provided write dicipline */
return (job->gvc->write_fn)(job, (char*)s, len);
-#ifndef IN_MEM_COMPRESSION
- if (job->flags & GVDEVICE_COMPRESSED_FORMAT) {
-#ifdef HAVE_LIBZ
- return gzwrite((gzFile *) (job->output_file), s, len);
-#endif
- }
- else
-#endif
if (job->output_data) {
if (len > job->output_data_allocated - (job->output_data_position + 1)) {
/* ensure enough allocation for string = null terminator */
job->output_data_allocated = (job->output_data_position + len + 1 + PAGE_ALIGN) & ~PAGE_ALIGN;
job->output_data = realloc(job->output_data, job->output_data_allocated);
if (!job->output_data) {
- fprintf(stderr, "failure realloc'ing for result string\n");
- return 0;
+ (job->common->errorfn) ("memory allocation failure\n");
+ exit(1);
}
}
memcpy(job->output_data + job->output_data_position, s, len);
return 0;
}
+static void auto_output_filename(GVJ_t *job)
+{
+ static char *buf;
+ static int bufsz;
+ char gidx[100]; /* large enough for '.' plus any integer */
+ char *fn, *p;
+ int len;
+
+ if (job->graph_index)
+ sprintf(gidx, ".%d", job->graph_index + 1);
+ else
+ gidx[0] = '\0';
+ if (!(fn = job->input_filename))
+ fn = "noname.dot";
+ len = strlen(fn) /* typically "something.dot" */
+ + strlen(gidx) /* "", ".2", ".3", ".4", ... */
+ + 1 /* "." */
+ + strlen(job->output_langname) /* e.g. "png" */
+ + 1; /* null terminaor */
+ if (bufsz < len) {
+ bufsz = len + 10;
+ buf = realloc(buf, bufsz * sizeof(char));
+ }
+ strcpy(buf, fn);
+ strcat(buf, gidx);
+ strcat(buf, ".");
+ if ((p = strchr(job->output_langname, ':'))) {
+ strcat(buf, p+1);
+ strcat(buf, ".");
+ strncat(buf, job->output_langname, (p - job->output_langname));
+ }
+ else {
+ strcat(buf, job->output_langname);
+ }
+
+ job->output_filename = buf;
+}
+
+void gvdevice_initialize(GVJ_t * job)
+{
+ gvdevice_engine_t *gvde = job->device.engine;
+ GVC_t *gvc = job->gvc;
+
+ if (gvde && gvde->initialize) {
+ gvde->initialize(job);
+ }
+ else if (job->output_data) {
+ }
+ /* if the device has no initialization then it uses file output */
+ else if (!job->output_file) { /* if not yet opened */
+ if (gvc->common.auto_outfile_names)
+ auto_output_filename(job);
+ if (job->output_filename) {
+ job->output_file = fopen(job->output_filename, "w");
+ if (job->output_file == NULL) {
+ perror(job->output_filename);
+ exit(1);
+ }
+ }
+ else
+ job->output_file = stdout;
+
+#ifdef WITH_CODEGENS
+ Output_file = job->output_file;
+#endif
+
+#ifdef HAVE_SETMODE
+#ifdef O_BINARY
+ if (job->flags & GVDEVICE_BINARY_FORMAT)
+ setmode(fileno(job->output_file), O_BINARY);
+#endif
+#endif
+
+#ifndef IN_MEM_COMPRESSION
+ if (job->flags & GVDEVICE_COMPRESSED_FORMAT) {
+#if HAVE_LIBZ
+ int fd;
+
+ /* open dup so can gzclose independent of FILE close */
+ fd = dup(fileno(job->output_file));
+ job->output_file = (FILE *) (gzdopen(fd, "wb"));
+ if (!job->output_file) {
+ (job->common->errorfn) ("Error initializing deflation on output file\n");
+ exit(1);
+ }
+#else
+ (job->common->errorfn) ("No libz support.\n");
+ exit(1);
+#endif
+ }
+#endif
+ }
+
+#ifdef IN_MEM_COMPRESSION
+ if (job->flags & GVDEVICE_COMPRESSED_FORMAT) {
+#ifdef HAVE_LIBZ
+ z_stream *z = &z_strm;
+
+ z->zalloc = (alloc_func)0;
+ z->zfree = (free_func)0;
+ z->opaque = (voidpf)0;
+ z->next_in = NULL;
+ z->next_out = NULL;
+ z->avail_in = 0;
+
+ crc = crc32(0L, Z_NULL, 0);
+
+ if (deflateInit2(z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) {
+ (job->common->errorfn) ("Error initializing for deflation\n");
+ exit(1);
+ }
+ gvdevice_write_no_z(job, z_file_header, sizeof(z_file_header));
+#else
+ (job->common->errorfn) ("No libz support.\n");
+ exit(1);
+#endif
+ }
+#endif
+}
+
+size_t gvdevice_write (GVJ_t * job, const unsigned char *s, unsigned int len)
+{
+ if (!len || !s)
+ return 0;
+
+#ifdef IN_MEM_COMPRESSION
+ if (job->flags & GVDEVICE_COMPRESSED_FORMAT) {
+#ifdef HAVE_LIBZ
+ z_streamp z = &z_strm;
+ int ret, dflen;
+
+ dflen = deflateBound(z, len);
+ if (dfallocated < dflen) {
+ dfallocated = (dflen + 1 + PAGE_ALIGN) & ~PAGE_ALIGN;
+ df = realloc(df, dfallocated);
+ if (! df) {
+ (job->common->errorfn) ("memory allocation failure\n");
+ exit(1);
+ }
+ }
+
+ z->next_in = (unsigned char*)s;
+ z->avail_in = len;
+ z->next_out = df;
+ z->avail_out = dfallocated;
+ ret=deflate (z, Z_NO_FLUSH);
+ if (ret != Z_OK) {
+ (job->common->errorfn) ("deflation problem %d\n", ret);
+ exit(1);
+ }
+ crc = crc32(crc, s, len);
+ len = z->next_out - df;
+ s = df;
+#endif
+ }
+#else
+ if (!(job->gvc->write_fn) && (job->flags & GVDEVICE_COMPRESSED_FORMAT)) {
+#ifdef HAVE_LIBZ
+ return gzwrite((gzFile *) (job->output_file), s, len);
+#endif
+ }
+#endif
+ return gvdevice_write_no_z (job, s, len);
+}
+
void gvdevice_fputs(GVJ_t * job, char *s)
{
gvdevice_write (job, (unsigned char*)s, strlen(s));
}
+static void gvdevice_flush(GVJ_t * job)
+{
+ if (job->output_file
+ && ! job->external_context
+ && ! job->gvc->write_fn
+ && job->output_lang != TK
+ && ! (job->flags & GVDEVICE_COMPRESSED_FORMAT)) {
+ fflush(job->output_file);
+ }
+}
+
+static void gvdevice_close(GVJ_t * job)
+{
+ if (job->output_filename
+ && job->output_file != stdout
+ && ! job->external_context) {
+ if (job->output_file) {
+ fclose(job->output_file);
+ job->output_file = NULL;
+ }
+ job->output_filename = NULL;
+ }
+}
+
+void gvdevice_format(GVJ_t * job)
+{
+ gvdevice_engine_t *gvde = job->device.engine;
+
+ if (gvde && gvde->format)
+ gvde->format(job);
+ gvdevice_flush(job);
+}
+
+void gvdevice_finalize(GVJ_t * job)
+{
+ gvdevice_engine_t *gvde = job->device.engine;
+ boolean finalized_p = FALSE;
+
+#ifdef IN_MEM_COMPRESSION
+ if (job->flags & GVDEVICE_COMPRESSED_FORMAT) {
+#ifdef HAVE_LIBZ
+ z_streamp z = &z_strm;
+ unsigned char out[8] = "";
+ int ret;
+ int cnt = 0;
+
+ z->next_in = out;
+ z->avail_in = 0;
+ z->next_out = df;
+ z->avail_out = dfallocated;
+
+#if 1
+ while ((ret = deflate (z, Z_FINISH)) == Z_OK && (cnt++ <= 100)) {
+ gvdevice_write_no_z(job, df, z->next_out - df);
+ z->next_in = out;
+ z->avail_in = 0;
+ z->next_out = df;
+ z->avail_out = dfallocated;
+ }
+#else
+ ret = deflate (z, Z_FINISH);
+#endif
+ if (ret != Z_STREAM_END && ret != Z_OK) {
+ (job->common->errorfn) ("deflation finish problem %d cnt=%d\n", ret, cnt);
+ exit(1);
+ }
+ gvdevice_write_no_z(job, df, z->next_out - df);
+
+ ret = deflateEnd(z);
+ if (ret != Z_OK) {
+ (job->common->errorfn) ("deflation end problem %d\n", ret);
+ exit(1);
+ }
+ out[0] = (unsigned char)(crc);
+ out[1] = (unsigned char)(crc >> 8);
+ out[2] = (unsigned char)(crc >> 16);
+ out[3] = (unsigned char)(crc >> 24);
+ out[4] = (unsigned char)(z->total_in);
+ out[5] = (unsigned char)(z->total_in >> 8);
+ out[6] = (unsigned char)(z->total_in >> 16);
+ out[7] = (unsigned char)(z->total_in >> 24);
+ gvdevice_write_no_z(job, out, sizeof(out));
+#else
+ (job->common->errorfn) ("No libz support\n");
+ exit(1);
+#endif
+ }
+#endif
+
+ if (gvde) {
+ if (gvde->finalize) {
+ gvde->finalize(job);
+ finalized_p = TRUE;
+ }
+ }
+#ifdef WITH_CODEGENS
+ else {
+ codegen_t *cg = job->codegen;
+
+ if (cg && cg->reset)
+ cg->reset();
+ }
+#endif
+
+ if (! finalized_p) {
+ /* if the device has no finalization then it uses file output */
+#ifndef IN_MEM_COMPRESSION
+ if (job->flags & GVDEVICE_COMPRESSED_FORMAT) {
+#ifdef HAVE_LIBZ
+ gzclose((gzFile *) (job->output_file));
+ job->output_file = NULL;
+#else
+ (job->common->errorfn) ("No libz support\n");
+ exit(1);
+#endif
+ }
+#endif
+ gvdevice_flush(job);
+ gvdevice_close(job);
+ }
+}
/* gvdevice_printf:
* Note that this function is unsafe due to the fixed buffer size.
* It should only be used when the caller is sure the input will not
}
}
-static void auto_output_filename(GVJ_t *job)
-{
- static char *buf;
- static int bufsz;
- char gidx[100]; /* large enough for '.' plus any integer */
- char *fn, *p;
- int len;
-
- if (job->graph_index)
- sprintf(gidx, ".%d", job->graph_index + 1);
- else
- gidx[0] = '\0';
- if (!(fn = job->input_filename))
- fn = "noname.dot";
- len = strlen(fn) /* typically "something.dot" */
- + strlen(gidx) /* "", ".2", ".3", ".4", ... */
- + 1 /* "." */
- + strlen(job->output_langname) /* e.g. "png" */
- + 1; /* null terminaor */
- if (bufsz < len) {
- bufsz = len + 10;
- buf = realloc(buf, bufsz * sizeof(char));
- }
- strcpy(buf, fn);
- strcat(buf, gidx);
- strcat(buf, ".");
- if ((p = strchr(job->output_langname, ':'))) {
- strcat(buf, p+1);
- strcat(buf, ".");
- strncat(buf, job->output_langname, (p - job->output_langname));
- }
- else {
- strcat(buf, job->output_langname);
- }
-
- job->output_filename = buf;
-}
-
-#ifdef WITH_CODEGENS
-extern FILE* Output_file;
-#endif
-
-void gvdevice_initialize(GVJ_t * job)
-{
- gvdevice_engine_t *gvde = job->device.engine;
- GVC_t *gvc = job->gvc;
-
- if (gvde && gvde->initialize) {
- gvde->initialize(job);
- }
- else if (job->output_data) {
- }
- /* if the device has no initialization then it uses file output */
- else if (!job->output_file) { /* if not yet opened */
- if (gvc->common.auto_outfile_names)
- auto_output_filename(job);
- if (job->output_filename) {
- job->output_file = fopen(job->output_filename, "w");
- if (job->output_file == NULL) {
- perror(job->output_filename);
- exit(1);
- }
- }
- else
- job->output_file = stdout;
-
-#ifdef WITH_CODEGENS
- Output_file = job->output_file;
-#endif
-
-#ifdef HAVE_SETMODE
-#ifdef O_BINARY
- if (job->flags & GVDEVICE_BINARY_FORMAT)
- setmode(fileno(job->output_file), O_BINARY);
-#endif
-#endif
-
- if (job->flags & GVDEVICE_COMPRESSED_FORMAT) {
-#ifdef IN_MEM_COMPRESSION
- job->flags ^= GVDEVICE_COMPRESSED_FORMAT; /* don't complress header!!! */
- gvdevice_write(job, z_file_header, sizeof(z_file_header));
- job->flags ^= GVDEVICE_COMPRESSED_FORMAT;
-#else
-#if HAVE_LIBZ
- int fd;
-
- /* open dup so can gzclose independent of FILE close */
- fd = dup(fileno(job->output_file));
- job->output_file = (FILE *) (gzdopen(fd, "wb"));
- if (!job->output_file) {
- (job->common->errorfn) ("Error initializing compression on output file\n");
- exit(1);
- }
-#else
- (job->common->errorfn) ("No libz support.\n");
- exit(1);
-#endif
-#endif
- }
- }
-}
-
-static void gvdevice_flush(GVJ_t * job)
-{
- if (job->output_file
- && ! job->external_context
- && ! job->gvc->write_fn
- && job->output_lang != TK
- && ! (job->flags & GVDEVICE_COMPRESSED_FORMAT)) {
- fflush(job->output_file);
- }
-}
-
-static void gvdevice_close(GVJ_t * job)
-{
- if (job->output_filename
- && job->output_file != stdout
- && ! job->external_context) {
- if (job->output_file) {
- fclose(job->output_file);
- job->output_file = NULL;
- }
- job->output_filename = NULL;
- }
-}
-
-void gvdevice_format(GVJ_t * job)
-{
- gvdevice_engine_t *gvde = job->device.engine;
-
- if (gvde && gvde->format)
- gvde->format(job);
- gvdevice_flush(job);
-}
-
-void gvdevice_finalize(GVJ_t * job)
-{
- gvdevice_engine_t *gvde = job->device.engine;
- boolean finalized_p = FALSE;
-
- if (gvde) {
- if (gvde->finalize) {
- gvde->finalize(job);
- finalized_p = TRUE;
- }
- }
-#ifdef WITH_CODEGENS
- else {
- codegen_t *cg = job->codegen;
-
- if (cg && cg->reset)
- cg->reset();
- }
-#endif
-
- if (! finalized_p) {
- /* if the device has no finalization then it uses file output */
-#ifndef IN_MEM_COMPRESSION
- if (job->flags & GVDEVICE_COMPRESSED_FORMAT) {
-#ifdef HAVE_LIBZ
- gzclose((gzFile *) (job->output_file));
- job->output_file = NULL;
-#else
- (job->common->errorfn) ("No libz support\n");
- exit(1);
-#endif
- }
-#endif
- gvdevice_flush(job);
- gvdevice_close(job);
- }
-}