gif.c: use malloc instead of alloca for LZW buffer as fails for large scale

This commit is contained in:
gitlost 2021-09-18 17:15:16 +01:00
parent 537990e32e
commit 5766b39845
3 changed files with 87 additions and 40 deletions

View File

@ -41,7 +41,8 @@
#include <malloc.h> #include <malloc.h>
#endif #endif
#define SSET "0123456789ABCDEF" /* Limit initial ZLW buffer size to this in expectation that compressed data will fit for typical scalings */
#define GIF_ZLW_PAGE_SIZE 0x100000 /* Megabyte */
typedef struct s_statestruct { typedef struct s_statestruct {
unsigned char *pOut; unsigned char *pOut;
@ -95,8 +96,15 @@ static int BufferNextByte(statestruct *pState) {
pState->OutByteCountPos = pState->OutPosCur; pState->OutByteCountPos = pState->OutPosCur;
(pState->OutPosCur)++; (pState->OutPosCur)++;
} }
if (pState->OutPosCur >= pState->OutLength) if (pState->OutPosCur >= pState->OutLength) {
unsigned char *pOut;
pState->OutLength += GIF_ZLW_PAGE_SIZE;
/* Note pState->pOut not free()d by realloc() on failure */
if (!(pOut = (unsigned char *) realloc(pState->pOut, pState->OutLength))) {
return 1; return 1;
}
pState->pOut = pOut;
}
(pState->pOut)[pState->OutPosCur] = 0x00; (pState->pOut)[pState->OutPosCur] = 0x00;
return 0; return 0;
@ -301,15 +309,9 @@ INTERNAL int gif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf)
/* Allow for overhead of 4 == code size + byte count + overflow byte + zero terminator */ /* Allow for overhead of 4 == code size + byte count + overflow byte + zero terminator */
unsigned int lzoutbufSize = bitmapSize + 4; unsigned int lzoutbufSize = bitmapSize + 4;
#ifdef _MSC_VER if (lzoutbufSize > GIF_ZLW_PAGE_SIZE) {
char *lzwoutbuf; lzoutbufSize = GIF_ZLW_PAGE_SIZE;
#endif }
#ifndef _MSC_VER
char lzwoutbuf[lzoutbufSize];
#else
lzwoutbuf = (char *) _alloca(lzoutbufSize);
#endif /* _MSC_VER */
/* /*
* Build a table of the used palette items. * Build a table of the used palette items.
@ -582,19 +584,27 @@ INTERNAL int gif_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf)
/* prepare state array */ /* prepare state array */
State.pIn = pixelbuf; State.pIn = pixelbuf;
State.InLen = bitmapSize; State.InLen = bitmapSize;
State.pOut = (unsigned char *) lzwoutbuf; if (!(State.pOut = (unsigned char *) malloc(lzoutbufSize))) {
if (!output_to_stdout) {
fclose(gif_file);
}
strcpy(symbol->errtxt, "614: Insufficient memory for LZW buffer");
return ZINT_ERROR_MEMORY;
}
State.OutLength = lzoutbufSize; State.OutLength = lzoutbufSize;
/* call lzw encoding */ /* call lzw encoding */
byte_out = gif_lzw(&State, paletteBitSize); byte_out = gif_lzw(&State, paletteBitSize);
if (byte_out <= 0) { if (byte_out <= 0) {
free(State.pOut);
if (!output_to_stdout) { if (!output_to_stdout) {
fclose(gif_file); fclose(gif_file);
} }
strcpy(symbol->errtxt, "613: Insufficient memory for LZW buffer"); strcpy(symbol->errtxt, "613: Insufficient memory for LZW buffer");
return ZINT_ERROR_MEMORY; return ZINT_ERROR_MEMORY;
} }
fwrite(lzwoutbuf, byte_out, 1, gif_file); fwrite((const char *) State.pOut, byte_out, 1, gif_file);
free(State.pOut);
/* GIF terminator */ /* GIF terminator */
fputc('\x3b', gif_file); fputc('\x3b', gif_file);

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -129,37 +129,40 @@ static void test_print(int index, int generate, int debug) {
int whitespace_height; int whitespace_height;
int option_1; int option_1;
int option_2; int option_2;
float height;
float scale; float scale;
float dot_size; float dot_size;
char *fgcolour; char *fgcolour;
char *bgcolour; char *bgcolour;
char *data; char *data;
char *expected_file; char *expected_file;
char *comment;
}; };
struct item data[] = { struct item data[] = {
/* 0*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, "", "", "12", "dotcode_1.0.gif" }, /* 0*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, 0, "", "", "12", "dotcode_1.0.gif", "" },
/* 1*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0.1, "", "", "12", "dotcode_1.0_ds0.1.gif" }, /* 1*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, 0.1, "", "", "12", "dotcode_1.0_ds0.1.gif", "" },
/* 2*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 1.1, "", "", "12", "dotcode_1.0_ds1.1.gif" }, /* 2*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, 1.1, "", "", "12", "dotcode_1.0_ds1.1.gif", "" },
/* 3*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 1.5, 0, "", "", "12", "dotcode_1.5.gif" }, /* 3*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 1.5, 0, "", "", "12", "dotcode_1.5.gif", "" },
/* 4*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 1.5, 0.4, "", "", "12", "dotcode_1.5_ds0.4.gif" }, /* 4*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 1.5, 0.4, "", "", "12", "dotcode_1.5_ds0.4.gif", "" },
/* 5*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 1.5, 1.1, "", "", "12", "dotcode_1.5_ds1.1.gif" }, /* 5*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 1.5, 1.1, "", "", "12", "dotcode_1.5_ds1.1.gif", "" },
/* 6*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 1.5, 2.1, "", "", "12", "dotcode_1.5_ds2.1.gif" }, /* 6*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 1.5, 2.1, "", "", "12", "dotcode_1.5_ds2.1.gif", "" },
/* 7*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 2, 0, "", "", "12", "dotcode_2.0.gif" }, /* 7*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 2, 0, "", "", "12", "dotcode_2.0.gif", "" },
/* 8*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 2, 0.9, "", "", "12", "dotcode_2.0_ds0.9.gif" }, /* 8*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 2, 0.9, "", "", "12", "dotcode_2.0_ds0.9.gif", "" },
/* 9*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 2, 1.1, "", "", "12", "dotcode_2.0_ds1.1.gif" }, /* 9*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 2, 1.1, "", "", "12", "dotcode_2.0_ds1.1.gif", "" },
/* 10*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3, 0, "", "", "12", "dotcode_3.0.gif" }, /* 10*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3, 0, "", "", "12", "dotcode_3.0.gif", "" },
/* 11*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3, 0.4, "", "", "12", "dotcode_3.0_ds0.4.gif" }, /* 11*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3, 0.4, "", "", "12", "dotcode_3.0_ds0.4.gif", "" },
/* 12*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3, 1.1, "", "", "12", "dotcode_3.0_ds1.1.gif" }, /* 12*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3, 1.1, "", "", "12", "dotcode_3.0_ds1.1.gif", "" },
/* 13*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3.5, 0, "", "", "12", "dotcode_3.5.gif" }, /* 13*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3.5, 0, "", "", "12", "dotcode_3.5.gif", "" },
/* 14*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3.5, 0.4, "", "", "12", "dotcode_3.5_ds0.4.gif" }, /* 14*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3.5, 0.4, "", "", "12", "dotcode_3.5_ds0.4.gif", "" },
/* 15*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 3.5, 1.1, "", "", "12", "dotcode_3.5_ds1.1.gif" }, /* 15*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 3.5, 1.1, "", "", "12", "dotcode_3.5_ds1.1.gif", "" },
/* 16*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 5, 0, "", "", "12", "dotcode_5.0.gif" }, /* 16*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 5, 0, "", "", "12", "dotcode_5.0.gif", "" },
/* 17*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 5, 0.2, "", "", "12", "dotcode_5.0_ds0.2.gif" }, /* 17*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 5, 0.2, "", "", "12", "dotcode_5.0_ds0.2.gif", "" },
/* 18*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 5, 1.1, "", "", "12", "dotcode_5.0_ds1.1.gif" }, /* 18*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 5, 1.1, "", "", "12", "dotcode_5.0_ds1.1.gif", "" },
/* 19*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 5, 1.7, "", "", "12", "dotcode_5.0_ds1.7.gif" }, /* 19*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 5, 1.7, "", "", "12", "dotcode_5.0_ds1.7.gif", "" },
/* 20*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, "2674C344", "FDFFC2CC", "12", "dotcode_bgfgalpha.gif" }, /* 20*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, 0, "2674C344", "FDFFC2CC", "12", "dotcode_bgfgalpha.gif", "" },
/* 21*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, "00000000", "FFFFFF00", "12", "dotcode_bgfgtrans.gif" }, /* 21*/ { BARCODE_DOTCODE, -1, -1, -1, -1, -1, -1, 0, 0, 0, "00000000", "FFFFFF00", "12", "dotcode_bgfgtrans.gif", "" },
/* 22*/ { BARCODE_ULTRA, 1, BARCODE_BOX, 1, 1, -1, -1, 0, 0, "0000FF", "FF0000", "12", "ultra_fgbg_hvwsp1_box1.gif" }, /* 22*/ { BARCODE_ULTRA, 1, BARCODE_BOX, 1, 1, -1, -1, 0, 0, 0, "0000FF", "FF0000", "12", "ultra_fgbg_hvwsp1_box1.gif", "" },
/* 23*/ { BARCODE_ITF14, 4, BARCODE_BIND, 24, -1, -1, -1, 61.8, 3, 0, "", "", "0501054800395", "itf14_height61.8_bind4_wsp24_3.gif", "#204 ARM-Cortex crash" },
}; };
int data_size = ARRAY_SIZE(data); int data_size = ARRAY_SIZE(data);
int i, length, ret; int i, length, ret;
@ -201,6 +204,9 @@ static void test_print(int index, int generate, int debug) {
if (data[i].whitespace_height != -1) { if (data[i].whitespace_height != -1) {
symbol->whitespace_height = data[i].whitespace_height; symbol->whitespace_height = data[i].whitespace_height;
} }
if (data[i].height) {
symbol->height = data[i].height;
}
if (data[i].scale) { if (data[i].scale) {
symbol->scale = data[i].scale; symbol->scale = data[i].scale;
} }
@ -224,11 +230,11 @@ static void test_print(int index, int generate, int debug) {
assert_nonzero(testUtilDataPath(expected_file, sizeof(expected_file), data_dir, data[i].expected_file), "i:%d testUtilDataPath == 0\n", i); assert_nonzero(testUtilDataPath(expected_file, sizeof(expected_file), data_dir, data[i].expected_file), "i:%d testUtilDataPath == 0\n", i);
if (generate) { if (generate) {
printf(" /*%3d*/ { %s, %d, %s, %d, %d, %d, %d, %.5g, %.5g, \"%s\", \"%s\", \"%s\", \"%s\" },\n", printf(" /*%3d*/ { %s, %d, %s, %d, %d, %d, %d, %.5g, %.5g, %.5g, \"%s\", \"%s\", \"%s\", \"%s\", \"%s\" },\n",
i, testUtilBarcodeName(data[i].symbology), data[i].border_width, testUtilOutputOptionsName(data[i].output_options), i, testUtilBarcodeName(data[i].symbology), data[i].border_width, testUtilOutputOptionsName(data[i].output_options),
data[i].whitespace_width, data[i].whitespace_height, data[i].whitespace_width, data[i].whitespace_height,
data[i].option_1, data[i].option_2, data[i].scale, data[i].dot_size, data[i].fgcolour, data[i].bgcolour, data[i].option_1, data[i].option_2, data[i].height, data[i].scale, data[i].dot_size, data[i].fgcolour, data[i].bgcolour,
testUtilEscape(data[i].data, length, escaped, escaped_size), data[i].expected_file); testUtilEscape(data[i].data, length, escaped, escaped_size), data[i].expected_file, data[i].comment);
ret = testUtilRename(symbol->outfile, expected_file); ret = testUtilRename(symbol->outfile, expected_file);
assert_zero(ret, "i:%d testUtilRename(%s, %s) ret %d != 0\n", i, symbol->outfile, expected_file, ret); assert_zero(ret, "i:%d testUtilRename(%s, %s) ret %d != 0\n", i, symbol->outfile, expected_file, ret);
if (have_identify) { if (have_identify) {
@ -275,12 +281,43 @@ static void test_outfile(void) {
testFinish(); testFinish();
} }
static void test_large_scale(int debug) {
int length, ret;
struct zint_symbol symbol = {0};
char data[] = "1";
testStart("test_large_scale");
length = (int) strlen(data);
symbol.symbology = BARCODE_ITF14;
strcpy(symbol.fgcolour, "000000");
strcpy(symbol.bgcolour, "ffffff");
strcpy(symbol.outfile, "out.gif");
// X-dimension 0.27mm * 95 = 25.65 ~ 25 pixels so 12.5 gives 95 dpmm (2400 dpi)
symbol.scale = 12.5f; // 70.0f would cause re-alloc as LZW > 1MB but very slow
symbol.dot_size = 4.0f / 5.0f;
ret = ZBarcode_Encode_and_Print(&symbol, (unsigned char *) data, length, 0 /*rotate_angle*/);
assert_zero(ret, "%s ZBarcode_Encode_and_Print ret %d != 0 %s\n", testUtilBarcodeName(symbol.symbology), ret, symbol.errtxt);
if (!(debug & ZINT_DEBUG_TEST_KEEP_OUTFILE)) { /* -d 64 */
// 129.1 kB file manually inspected and checked (1.1 MB file for scale 70.0f also checked)
assert_zero(remove(symbol.outfile), "remove(%s) != 0\n", symbol.outfile);
}
ZBarcode_Clear(&symbol);
testFinish();
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */ testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */
{ "test_pixel_plot", test_pixel_plot, 1, 0, 1 }, { "test_pixel_plot", test_pixel_plot, 1, 0, 1 },
{ "test_print", test_print, 1, 1, 1 }, { "test_print", test_print, 1, 1, 1 },
{ "test_outfile", test_outfile, 0, 0, 0 }, { "test_outfile", test_outfile, 0, 0, 0 },
{ "test_large_scale", test_large_scale, 0, 0, 1 },
}; };
testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); testRun(argc, argv, funcs, ARRAY_SIZE(funcs));