Desenchufar un programa que lee un PNG ... parece estar usando la biblioteca zlib.
Aquí está la salida cuando la ejecuto con una entrada dañada (imagen):
Reading 'crash.png'...
ptr:0x1b9e2c0
rowbytes:3
zbuf1:0x1b9b480
zbuf_size:11
zbuf2:0x1b9b4a0
zbuf_size:11
ret1:0
ret2:0
extracting frame 0 of 0
zstream1.buf:x+�?%
zstream1.count_out:11
Z_FINISH:4
ret5:-2
zstream1.buf:x+�?%
zstream1.count_out:11
zstream2.buf:x+�?%
zstream2.count_out:11
Z_FINISH:4
Segmentation fault
Es gracioso que la falla de Seg, no siempre sucede.
Aquí cómo se busca un PNG válido (1 píxel negro):
Reading 'input.png'...
ptr:0x17fb2c0
rowbytes:3
zbuf1:0x17f8480
zbuf_size:17
zbuf2:0x17f84a0
zbuf_size:17
ret1:0
ret2:0
extracting frame 0 of 0
ret3:0
ret4:0
zstream1.buf:���
zstream1.count_out:15
Z_FINISH:4
ret5:1
zstream1.buf:�
zstream1.count_out:5
zstream2.buf:���
zstream2.count_out:15
Z_FINISH:4
zstream2.buf:�
zstream2.count_out:5
ret6:1
ret7:0
ret8:0
ret9:0
ret10:0
all done
¿Alguien puede mirar el código a continuación y decirme por qué falla? Aquí:
ret = deflate (& zstream2, Z_FINISH);
Código completo:
void SavePNG(char * szPath, unsigned char * pdata, unsigned short * delays, unsigned int w, unsigned int h, unsigned int first, unsigned int last, unsigned int bpp, unsigned char coltype)
{
struct IHDR
{
unsigned int mWidth;
unsigned int mHeight;
unsigned char mDepth;
unsigned char mColorType;
unsigned char mCompression;
unsigned char mFilterMethod;
unsigned char mInterlaceMethod;
} ihdr = { swap32(w), swap32(h), 8, coltype, 0, 0, 0 };
char szOut[256];
z_stream zstream1;
z_stream zstream2;
FILE * f;
unsigned int i, j, n, len;
unsigned int rowbytes = w * bpp;
unsigned int idat_size = (rowbytes + 1) * h;
unsigned int zbuf_size = idat_size + ((idat_size + 7) >> 3) + ((idat_size + 63) >> 6) + 11;
unsigned char * row_buf = (unsigned char *)malloc(rowbytes + 1);
printf("ptr:%p\n",row_buf);
printf("rowbytes:%i\n",rowbytes);
unsigned char * sub_row = (unsigned char *)malloc(rowbytes + 1);
unsigned char * up_row = (unsigned char *)malloc(rowbytes + 1);
unsigned char * avg_row = (unsigned char *)malloc(rowbytes + 1);
unsigned char * paeth_row = (unsigned char *)malloc(rowbytes + 1);
unsigned char * zbuf1 = (unsigned char *)malloc(zbuf_size);
printf("zbuf1:%p\n",zbuf1);
printf("zbuf_size:%i\n",zbuf_size);
unsigned char * zbuf2 = (unsigned char *)malloc(zbuf_size);
printf("zbuf2:%p\n",zbuf2);
printf("zbuf_size:%i\n",zbuf_size);
if (!row_buf || !sub_row || !up_row || !avg_row || !paeth_row || !zbuf1 || !zbuf2)
return;
row_buf[0] = 0;
sub_row[0] = 1;
up_row[0] = 2;
avg_row[0] = 3;
paeth_row[0] = 4;
zstream1.data_type = Z_BINARY;
zstream1.zalloc = Z_NULL;
zstream1.zfree = Z_NULL;
zstream1.opaque = Z_NULL;
int ret;
ret=deflateInit2(&zstream1, Z_BEST_COMPRESSION, 8, 15, 8, Z_DEFAULT_STRATEGY);
printf("ret1:%i\n",ret);
zstream2.data_type = Z_BINARY;
zstream2.zalloc = Z_NULL;
zstream2.zfree = Z_NULL;
zstream2.opaque = Z_NULL;
ret=deflateInit2(&zstream2, Z_BEST_COMPRESSION, 8, 15, 8, Z_FILTERED);
printf("ret2:%i\n",ret);
len = sprintf(szOut, "%d", last);
for (n=first; n<=last; n++)
{
printf("extracting frame %d of %d\n", n, last);
if (n > 0)
{
sprintf(szOut, "%s%.*d.txt", szPath, len, n);
if ((f = fopen(szOut, "wt")) != 0)
{
fprintf(f, "delay=%d/%d\n", delays[n*2], delays[n*2+1]);
fclose(f);
}
}
sprintf(szOut, "%s%.*d.png", szPath, len, n);
if ((f = fopen(szOut, "wb")) != 0)
{
int a, b, c, pa, pb, pc, p, v;
unsigned char * prev;
unsigned char * row;
fwrite(png_sign, 1, 8, f);
write_chunk(f, "IHDR", (unsigned char *)(&ihdr), 13);
if (palsize > 0)
write_chunk(f, "PLTE", (unsigned char *)(&pal), palsize*3);
if (trnssize > 0)
write_chunk(f, "tRNS", trns, trnssize);
zstream1.next_out = zbuf1;
zstream1.avail_out = zbuf_size;
zstream2.next_out = zbuf2;
zstream2.avail_out = zbuf_size;
prev = NULL;
row = pdata + n*h*rowbytes;
for (j=0; j<h; j++)
{
unsigned char * out;
unsigned int sum = 0;
unsigned char * best_row = row_buf;
unsigned int mins = ((unsigned int)(-1)) >> 1;
out = row_buf+1;
for (i=0; i<rowbytes; i++)
{
v = out[i] = row[i];
sum += (v < 128) ? v : 256 - v;
}
mins = sum;
sum = 0;
out = sub_row+1;
for (i=0; i<bpp; i++)
{
v = out[i] = row[i];
sum += (v < 128) ? v : 256 - v;
}
for (i=bpp; i<rowbytes; i++)
{
v = out[i] = row[i] - row[i-bpp];
sum += (v < 128) ? v : 256 - v;
if (sum > mins) break;
}
if (sum < mins)
{
mins = sum;
best_row = sub_row;
}
if (prev)
{
sum = 0;
out = up_row+1;
for (i=0; i<rowbytes; i++)
{
v = out[i] = row[i] - prev[i];
sum += (v < 128) ? v : 256 - v;
if (sum > mins) break;
}
if (sum < mins)
{
mins = sum;
best_row = up_row;
}
sum = 0;
out = avg_row+1;
for (i=0; i<bpp; i++)
{
v = out[i] = row[i] - prev[i]/2;
sum += (v < 128) ? v : 256 - v;
}
for (i=bpp; i<rowbytes; i++)
{
v = out[i] = row[i] - (prev[i] + row[i-bpp])/2;
sum += (v < 128) ? v : 256 - v;
if (sum > mins) break;
}
if (sum < mins)
{
mins = sum;
best_row = avg_row;
}
sum = 0;
out = paeth_row+1;
for (i=0; i<bpp; i++)
{
v = out[i] = row[i] - prev[i];
sum += (v < 128) ? v : 256 - v;
}
for (i=bpp; i<rowbytes; i++)
{
a = row[i-bpp];
b = prev[i];
c = prev[i-bpp];
p = b - c;
pc = a - c;
pa = abs(p);
pb = abs(pc);
pc = abs(p + pc);
p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
v = out[i] = row[i] - p;
sum += (v < 128) ? v : 256 - v;
if (sum > mins) break;
}
if (sum < mins)
{
best_row = paeth_row;
}
}
zstream1.next_in = row_buf;
zstream1.avail_in = rowbytes + 1;
ret=deflate(&zstream1, Z_NO_FLUSH);
printf("ret3:%i\n",ret);
zstream2.next_in = best_row;
zstream2.avail_in = rowbytes + 1;
ret=deflate(&zstream2, Z_NO_FLUSH);
printf("ret4:%i\n",ret);
prev = row;
row += rowbytes;
}
printf("zstream1.buf:%s\n",zstream1.next_out);
printf("zstream1.count_out:%i\n",zstream1.avail_out);
printf("Z_FINISH:%i\n",Z_FINISH);
ret=deflate(&zstream1, Z_FINISH);
printf("ret5:%i\n",ret);
printf("zstream1.buf:%s\n",zstream1.next_out);
printf("zstream1.count_out:%i\n",zstream1.avail_out);
printf("zstream2.buf:%s\n",zstream2.next_out);
printf("zstream2.count_out:%i\n",zstream2.avail_out);
printf("Z_FINISH:%i\n",Z_FINISH);
ret=deflate(&zstream2, Z_FINISH);
printf("zstream2.buf:%s\n",zstream2.next_out);
printf("zstream2.count_out:%i\n",zstream2.avail_out);
printf("ret6:%i\n",ret);
if (zstream1.total_out <= zstream2.total_out)
write_IDATs(f, zbuf1, zstream1.total_out, idat_size);
else
write_IDATs(f, zbuf2, zstream2.total_out, idat_size);
ret=deflateReset(&zstream1);
printf("ret7:%i\n",ret);
zstream1.data_type = Z_BINARY;
ret=deflateReset(&zstream2);
printf("ret8:%i\n",ret);
zstream2.data_type = Z_BINARY;
write_chunk(f, "IEND", 0, 0);
fclose(f);
}
else
printf("Error: can't open the file '%s'\n", szOut);
}
ret=deflateEnd(&zstream1);
printf("ret9:%i\n",ret);
ret=deflateEnd(&zstream2);
printf("ret10:%i\n",ret);
free(zbuf1);
free(zbuf2);
free(row_buf);
free(sub_row);
free(up_row);
free(avg_row);
free(paeth_row);
}
ACTUALIZACIÓN 1:
OK .... modificó el código:
void SavePNG(char * szPath, unsigned char * pdata, unsigned short * delays, unsigned int w, unsigned int h, unsigned int first, unsigned int last, unsigned int bpp, unsigned char coltype)
{
struct IHDR
{
unsigned int mWidth;
unsigned int mHeight;
unsigned char mDepth;
unsigned char mColorType;
unsigned char mCompression;
unsigned char mFilterMethod;
unsigned char mInterlaceMethod;
} ihdr = { swap32(w), swap32(h), 8, coltype, 0, 0, 0 };
char szOut[256];
z_stream zstream1;
z_stream zstream2;
FILE * f;
unsigned int i, j, n, len;
unsigned int rowbytes = w * bpp;
unsigned int idat_size = (rowbytes + 1) * h;
unsigned int zbuf_size = idat_size + ((idat_size + 7) >> 3) + ((idat_size + 63) >> 6) + 11;
unsigned char * row_buf = (unsigned char *)malloc(rowbytes + 1);
printf("ptr:%p\n",row_buf);
printf("rowbytes:%i\n",rowbytes);
unsigned char * sub_row = (unsigned char *)malloc(rowbytes + 1);
unsigned char * up_row = (unsigned char *)malloc(rowbytes + 1);
unsigned char * avg_row = (unsigned char *)malloc(rowbytes + 1);
unsigned char * paeth_row = (unsigned char *)malloc(rowbytes + 1);
unsigned char * zbuf1 = (unsigned char *)malloc(zbuf_size);
printf("zbuf1:%p\n",zbuf1);
printf("zbuf_size:%i\n",zbuf_size);
unsigned char * zbuf2 = (unsigned char *)malloc(zbuf_size);
printf("zbuf2:%p\n",zbuf2);
printf("zbuf_size:%i\n",zbuf_size);
if (!row_buf || !sub_row || !up_row || !avg_row || !paeth_row || !zbuf1 || !zbuf2)
return;
row_buf[0] = 0;
sub_row[0] = 1;
up_row[0] = 2;
avg_row[0] = 3;
paeth_row[0] = 4;
zstream1.data_type = Z_BINARY;
zstream1.zalloc = Z_NULL;
zstream1.zfree = Z_NULL;
zstream1.opaque = Z_NULL;
int ret;
ret=deflateInit2(&zstream1, Z_BEST_COMPRESSION, 8, 15, 8, Z_DEFAULT_STRATEGY);
printf("ret1:%i\n",ret);
zstream2.data_type = Z_BINARY;
zstream2.zalloc = Z_NULL;
zstream2.zfree = Z_NULL;
zstream2.opaque = Z_NULL;
ret=deflateInit2(&zstream2, Z_BEST_COMPRESSION, 8, 15, 8, Z_FILTERED);
printf("ret2:%i\n",ret);
len = sprintf(szOut, "%d", last);
for (n=first; n<=last; n++)
{
printf("extracting frame %d of %d\n", n, last);
if (n > 0)
{
sprintf(szOut, "%s%.*d.txt", szPath, len, n);
if ((f = fopen(szOut, "wt")) != 0)
{
fprintf(f, "delay=%d/%d\n", delays[n*2], delays[n*2+1]);
fclose(f);
}
}
sprintf(szOut, "%s%.*d.png", szPath, len, n);
if ((f = fopen(szOut, "wb")) != 0)
{
int a, b, c, pa, pb, pc, p, v;
unsigned char * prev;
unsigned char * row;
fwrite(png_sign, 1, 8, f);
write_chunk(f, "IHDR", (unsigned char *)(&ihdr), 13);
if (palsize > 0)
write_chunk(f, "PLTE", (unsigned char *)(&pal), palsize*3);
if (trnssize > 0)
write_chunk(f, "tRNS", trns, trnssize);
zstream1.next_out = zbuf1;
zstream1.avail_out = zbuf_size;
zstream2.next_out = zbuf2;
zstream2.avail_out = zbuf_size;
prev = NULL;
row = pdata + n*h*rowbytes;
for (j=0; j<h; j++)
{
unsigned char * out;
unsigned int sum = 0;
unsigned char * best_row = row_buf;
unsigned int mins = ((unsigned int)(-1)) >> 1;
out = row_buf+1;
for (i=0; i<rowbytes; i++)
{
v = out[i] = row[i];
sum += (v < 128) ? v : 256 - v;
}
mins = sum;
sum = 0;
out = sub_row+1;
for (i=0; i<bpp; i++)
{
v = out[i] = row[i];
sum += (v < 128) ? v : 256 - v;
}
for (i=bpp; i<rowbytes; i++)
{
v = out[i] = row[i] - row[i-bpp];
sum += (v < 128) ? v : 256 - v;
if (sum > mins) break;
}
if (sum < mins)
{
mins = sum;
best_row = sub_row;
}
if (prev)
{
sum = 0;
out = up_row+1;
for (i=0; i<rowbytes; i++)
{
v = out[i] = row[i] - prev[i];
sum += (v < 128) ? v : 256 - v;
if (sum > mins) break;
}
if (sum < mins)
{
mins = sum;
best_row = up_row;
}
sum = 0;
out = avg_row+1;
for (i=0; i<bpp; i++)
{
v = out[i] = row[i] - prev[i]/2;
sum += (v < 128) ? v : 256 - v;
}
for (i=bpp; i<rowbytes; i++)
{
v = out[i] = row[i] - (prev[i] + row[i-bpp])/2;
sum += (v < 128) ? v : 256 - v;
if (sum > mins) break;
}
if (sum < mins)
{
mins = sum;
best_row = avg_row;
}
sum = 0;
out = paeth_row+1;
for (i=0; i<bpp; i++)
{
v = out[i] = row[i] - prev[i];
sum += (v < 128) ? v : 256 - v;
}
for (i=bpp; i<rowbytes; i++)
{
a = row[i-bpp];
b = prev[i];
c = prev[i-bpp];
p = b - c;
pc = a - c;
pa = abs(p);
pb = abs(pc);
pc = abs(p + pc);
p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
v = out[i] = row[i] - p;
sum += (v < 128) ? v : 256 - v;
if (sum > mins) break;
}
if (sum < mins)
{
best_row = paeth_row;
}
}
zstream1.next_in = row_buf;
zstream1.avail_in = rowbytes + 1;
ret=deflate(&zstream1, Z_NO_FLUSH);
printf("ret3:%i\n",ret);
zstream2.next_in = best_row;
zstream2.avail_in = rowbytes + 1;
ret=deflate(&zstream2, Z_NO_FLUSH);
printf("ret4:%i\n",ret);
prev = row;
row += rowbytes;
}
printf("zstream1.buf:%s\n",zstream1.next_out);
printf("zstream1.count_out:%i\n",zstream1.avail_out);
printf("Z_FINISH:%i\n",Z_FINISH);
ret=deflate(&zstream1, Z_FINISH);
printf("ret5:%i\n",ret);
printf("zstream1.buf:%s\n",zstream1.next_out);
printf("zstream1.count_out:%i\n",zstream1.avail_out);
printf("zstream2.buf:%s\n",zstream2.next_out);
printf("zstream2.count_out:%i\n",zstream2.avail_out);
printf("Z_FINISH:%i\n",Z_FINISH);
printf("zstream2.bufin:%s\n",zstream2.next_in);
printf("zstream2.count_in:%i\n",zstream2.avail_in);
printf("Z_FINISH:%i\n",Z_FINISH);
ret=deflate(&zstream2, Z_FINISH);
printf("zstream2.buf:%s\n",zstream2.next_out);
printf("zstream2.count_out:%i\n",zstream2.avail_out);
printf("ret6:%i\n",ret);
if (zstream1.total_out <= zstream2.total_out)
write_IDATs(f, zbuf1, zstream1.total_out, idat_size);
else
write_IDATs(f, zbuf2, zstream2.total_out, idat_size);
ret=deflateReset(&zstream1);
printf("ret7:%i\n",ret);
zstream1.data_type = Z_BINARY;
ret=deflateReset(&zstream2);
printf("ret8:%i\n",ret);
zstream2.data_type = Z_BINARY;
write_chunk(f, "IEND", 0, 0);
fclose(f);
}
else
printf("Error: can't open the file '%s'\n", szOut);
}
ret=deflateEnd(&zstream1);
printf("ret9:%i\n",ret);
ret=deflateEnd(&zstream2);
printf("ret10:%i\n",ret);
free(zbuf1);
free(zbuf2);
free(row_buf);
free(sub_row);
free(up_row);
free(avg_row);
free(paeth_row);
}
Ahora veo por qué se bloquea ....
pero ¿por qué
zstream2.next_in
zstream2.avail_in
¿Tiene tales valores aleatorios?
Reading 'crash.png'...
ptr:0x14c32c0
rowbytes:3
zbuf1:0x14c0480
zbuf_size:11
zbuf2:0x14c04a0
zbuf_size:11
ret1:0
ret2:0
extracting frame 0 of 0
zstream1.buf:x+��y
zstream1.count_out:11
Z_FINISH:4
ret5:-2
zstream1.buf:x+��y
zstream1.count_out:11
zstream2.buf:x+��y
zstream2.count_out:11
Z_FINISH:4
zstream2.bufin:
zstream2.count_in:-1681299629
Z_FINISH:4
Segmentation fault
Reading 'crash.png'...
ptr:0x8c22c0
rowbytes:3
zbuf1:0x8bf480
zbuf_size:11
zbuf2:0x8bf4a0
zbuf_size:11
ret1:0
ret2:0
extracting frame 0 of 0
zstream1.buf:x+\�*
zstream1.count_out:11
Z_FINISH:4
ret5:-2
zstream1.buf:x+\�*
zstream1.count_out:11
zstream2.buf:x+\�*
zstream2.count_out:11
Z_FINISH:4
zstream2.bufin:
zstream2.count_in:-1920964781
Z_FINISH:4
Segmentation fault