Cleanup: Get this rid of "this->" in fpdfsdk/
[pdfium.git] / samples / fx_lpng / lpng_v163 / fx_pngpread.c
1 /* pngpread.c - read a png file in push mode\r
2  *\r
3  * Last changed in libpng 1.6.0 [February 14, 2013]\r
4  * Copyright (c) 1998-2013 Glenn Randers-Pehrson\r
5  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)\r
6  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)\r
7  *\r
8  * This code is released under the libpng license.\r
9  * For conditions of distribution and use, see the disclaimer\r
10  * and license in png.h\r
11  */\r
12 \r
13 #include "pngpriv.h"\r
14 \r
15 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED\r
16 \r
17 /* Push model modes */\r
18 #define PNG_READ_SIG_MODE   0\r
19 #define PNG_READ_CHUNK_MODE 1\r
20 #define PNG_READ_IDAT_MODE  2\r
21 #define PNG_SKIP_MODE       3\r
22 #define PNG_READ_tEXt_MODE  4\r
23 #define PNG_READ_zTXt_MODE  5\r
24 #define PNG_READ_DONE_MODE  6\r
25 #define PNG_READ_iTXt_MODE  7\r
26 #define PNG_ERROR_MODE      8\r
27 \r
28 void PNGAPI\r
29 png_process_data(png_structrp png_ptr, png_inforp info_ptr,\r
30     png_bytep buffer, png_size_t buffer_size)\r
31 {\r
32    if (png_ptr == NULL || info_ptr == NULL)\r
33       return;\r
34 \r
35    png_push_restore_buffer(png_ptr, buffer, buffer_size);\r
36 \r
37    while (png_ptr->buffer_size)\r
38    {\r
39       png_process_some_data(png_ptr, info_ptr);\r
40    }\r
41 }\r
42 \r
43 png_size_t PNGAPI\r
44 png_process_data_pause(png_structrp png_ptr, int save)\r
45 {\r
46    if (png_ptr != NULL)\r
47    {\r
48       /* It's easiest for the caller if we do the save, then the caller doesn't\r
49        * have to supply the same data again:\r
50        */\r
51       if (save)\r
52          png_push_save_buffer(png_ptr);\r
53       else\r
54       {\r
55          /* This includes any pending saved bytes: */\r
56          png_size_t remaining = png_ptr->buffer_size;\r
57          png_ptr->buffer_size = 0;\r
58 \r
59          /* So subtract the saved buffer size, unless all the data\r
60           * is actually 'saved', in which case we just return 0\r
61           */\r
62          if (png_ptr->save_buffer_size < remaining)\r
63             return remaining - png_ptr->save_buffer_size;\r
64       }\r
65    }\r
66 \r
67    return 0;\r
68 }\r
69 \r
70 png_uint_32 PNGAPI\r
71 png_process_data_skip(png_structrp png_ptr)\r
72 {\r
73    png_uint_32 remaining = 0;\r
74 \r
75    if (png_ptr != NULL && png_ptr->process_mode == PNG_SKIP_MODE &&\r
76       png_ptr->skip_length > 0)\r
77    {\r
78       /* At the end of png_process_data the buffer size must be 0 (see the loop\r
79        * above) so we can detect a broken call here:\r
80        */\r
81       if (png_ptr->buffer_size != 0)\r
82          png_error(png_ptr,\r
83             "png_process_data_skip called inside png_process_data");\r
84 \r
85       /* If is impossible for there to be a saved buffer at this point -\r
86        * otherwise we could not be in SKIP mode.  This will also happen if\r
87        * png_process_skip is called inside png_process_data (but only very\r
88        * rarely.)\r
89        */\r
90       if (png_ptr->save_buffer_size != 0)\r
91          png_error(png_ptr, "png_process_data_skip called with saved data");\r
92 \r
93       remaining = png_ptr->skip_length;\r
94       png_ptr->skip_length = 0;\r
95       png_ptr->process_mode = PNG_READ_CHUNK_MODE;\r
96    }\r
97 \r
98    return remaining;\r
99 }\r
100 \r
101 /* What we do with the incoming data depends on what we were previously\r
102  * doing before we ran out of data...\r
103  */\r
104 void /* PRIVATE */\r
105 png_process_some_data(png_structrp png_ptr, png_inforp info_ptr)\r
106 {\r
107    if (png_ptr == NULL)\r
108       return;\r
109 \r
110    switch (png_ptr->process_mode)\r
111    {\r
112       case PNG_READ_SIG_MODE:\r
113       {\r
114          png_push_read_sig(png_ptr, info_ptr);\r
115          break;\r
116       }\r
117 \r
118       case PNG_READ_CHUNK_MODE:\r
119       {\r
120          png_push_read_chunk(png_ptr, info_ptr);\r
121          break;\r
122       }\r
123 \r
124       case PNG_READ_IDAT_MODE:\r
125       {\r
126          png_push_read_IDAT(png_ptr);\r
127          break;\r
128       }\r
129 \r
130       case PNG_SKIP_MODE:\r
131       {\r
132          png_push_crc_finish(png_ptr);\r
133          break;\r
134       }\r
135 \r
136       default:\r
137       {\r
138          png_ptr->buffer_size = 0;\r
139          break;\r
140       }\r
141    }\r
142 }\r
143 \r
144 /* Read any remaining signature bytes from the stream and compare them with\r
145  * the correct PNG signature.  It is possible that this routine is called\r
146  * with bytes already read from the signature, either because they have been\r
147  * checked by the calling application, or because of multiple calls to this\r
148  * routine.\r
149  */\r
150 void /* PRIVATE */\r
151 png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr)\r
152 {\r
153    png_size_t num_checked = png_ptr->sig_bytes, /* SAFE, does not exceed 8 */ \r
154              num_to_check = 8 - num_checked;\r
155 \r
156    if (png_ptr->buffer_size < num_to_check)\r
157    {\r
158       num_to_check = png_ptr->buffer_size;\r
159    }\r
160 \r
161    png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]),\r
162        num_to_check);\r
163    png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check);\r
164 \r
165    if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))\r
166    {\r
167       if (num_checked < 4 &&\r
168           png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))\r
169          png_error(png_ptr, "Not a PNG file");\r
170 \r
171       else\r
172          png_error(png_ptr, "PNG file corrupted by ASCII conversion");\r
173    }\r
174    else\r
175    {\r
176       if (png_ptr->sig_bytes >= 8)\r
177       {\r
178          png_ptr->process_mode = PNG_READ_CHUNK_MODE;\r
179       }\r
180    }\r
181 }\r
182 \r
183 void /* PRIVATE */\r
184 png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)\r
185 {\r
186    png_uint_32 chunk_name;\r
187 #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\r
188    int keep; /* unknown handling method */\r
189 #endif\r
190 \r
191    /* First we make sure we have enough data for the 4 byte chunk name\r
192     * and the 4 byte chunk length before proceeding with decoding the\r
193     * chunk data.  To fully decode each of these chunks, we also make\r
194     * sure we have enough data in the buffer for the 4 byte CRC at the\r
195     * end of every chunk (except IDAT, which is handled separately).\r
196     */\r
197    if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))\r
198    {\r
199       png_byte chunk_length[4];\r
200       png_byte chunk_tag[4];\r
201 \r
202       if (png_ptr->buffer_size < 8)\r
203       {\r
204          png_push_save_buffer(png_ptr);\r
205          return;\r
206       }\r
207 \r
208       png_push_fill_buffer(png_ptr, chunk_length, 4);\r
209       png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);\r
210       png_reset_crc(png_ptr);\r
211       png_crc_read(png_ptr, chunk_tag, 4);\r
212       png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);\r
213       png_check_chunk_name(png_ptr, png_ptr->chunk_name);\r
214       png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;\r
215    }\r
216 \r
217    chunk_name = png_ptr->chunk_name;\r
218 \r
219    if (chunk_name == png_IDAT)\r
220    {\r
221       if (png_ptr->mode & PNG_AFTER_IDAT)\r
222          png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;\r
223 \r
224       /* If we reach an IDAT chunk, this means we have read all of the\r
225        * header chunks, and we can start reading the image (or if this\r
226        * is called after the image has been read - we have an error).\r
227        */\r
228       if (!(png_ptr->mode & PNG_HAVE_IHDR))\r
229          png_error(png_ptr, "Missing IHDR before IDAT");\r
230 \r
231       else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&\r
232           !(png_ptr->mode & PNG_HAVE_PLTE))\r
233          png_error(png_ptr, "Missing PLTE before IDAT");\r
234 \r
235       png_ptr->mode |= PNG_HAVE_IDAT;\r
236 \r
237       if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))\r
238          if (png_ptr->push_length == 0)\r
239             return;\r
240 \r
241       if (png_ptr->mode & PNG_AFTER_IDAT)\r
242          png_benign_error(png_ptr, "Too many IDATs found");\r
243    }\r
244 \r
245    if (chunk_name == png_IHDR)\r
246    {\r
247       if (png_ptr->push_length != 13)\r
248          png_error(png_ptr, "Invalid IHDR length");\r
249 \r
250       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
251       {\r
252          png_push_save_buffer(png_ptr);\r
253          return;\r
254       }\r
255 \r
256       png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length);\r
257    }\r
258 \r
259    else if (chunk_name == png_IEND)\r
260    {\r
261       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
262       {\r
263          png_push_save_buffer(png_ptr);\r
264          return;\r
265       }\r
266 \r
267       png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length);\r
268 \r
269       png_ptr->process_mode = PNG_READ_DONE_MODE;\r
270       png_push_have_end(png_ptr, info_ptr);\r
271    }\r
272 \r
273 #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\r
274    else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)\r
275    {\r
276       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
277       {\r
278          png_push_save_buffer(png_ptr);\r
279          return;\r
280       }\r
281 \r
282       png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep);\r
283 \r
284       if (chunk_name == png_PLTE)\r
285          png_ptr->mode |= PNG_HAVE_PLTE;\r
286    }\r
287 \r
288 #endif\r
289    else if (chunk_name == png_PLTE)\r
290    {\r
291       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
292       {\r
293          png_push_save_buffer(png_ptr);\r
294          return;\r
295       }\r
296       png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length);\r
297    }\r
298 \r
299    else if (chunk_name == png_IDAT)\r
300    {\r
301       png_ptr->idat_size = png_ptr->push_length;\r
302       png_ptr->process_mode = PNG_READ_IDAT_MODE;\r
303       png_push_have_info(png_ptr, info_ptr);\r
304       png_ptr->zstream.avail_out =\r
305           (uInt) PNG_ROWBYTES(png_ptr->pixel_depth,\r
306           png_ptr->iwidth) + 1;\r
307       png_ptr->zstream.next_out = png_ptr->row_buf;\r
308       return;\r
309    }\r
310 \r
311 #ifdef PNG_READ_gAMA_SUPPORTED\r
312    else if (png_ptr->chunk_name == png_gAMA)\r
313    {\r
314       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
315       {\r
316          png_push_save_buffer(png_ptr);\r
317          return;\r
318       }\r
319 \r
320       png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length);\r
321    }\r
322 \r
323 #endif\r
324 #ifdef PNG_READ_sBIT_SUPPORTED\r
325    else if (png_ptr->chunk_name == png_sBIT)\r
326    {\r
327       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
328       {\r
329          png_push_save_buffer(png_ptr);\r
330          return;\r
331       }\r
332 \r
333       png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length);\r
334    }\r
335 \r
336 #endif\r
337 #ifdef PNG_READ_cHRM_SUPPORTED\r
338    else if (png_ptr->chunk_name == png_cHRM)\r
339    {\r
340       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
341       {\r
342          png_push_save_buffer(png_ptr);\r
343          return;\r
344       }\r
345 \r
346       png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);\r
347    }\r
348 \r
349 #endif\r
350 #ifdef PNG_READ_sRGB_SUPPORTED\r
351    else if (chunk_name == png_sRGB)\r
352    {\r
353       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
354       {\r
355          png_push_save_buffer(png_ptr);\r
356          return;\r
357       }\r
358 \r
359       png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length);\r
360    }\r
361 \r
362 #endif\r
363 #ifdef PNG_READ_iCCP_SUPPORTED\r
364    else if (png_ptr->chunk_name == png_iCCP)\r
365    {\r
366       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
367       {\r
368          png_push_save_buffer(png_ptr);\r
369          return;\r
370       }\r
371 \r
372       png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length);\r
373    }\r
374 \r
375 #endif\r
376 #ifdef PNG_READ_sPLT_SUPPORTED\r
377    else if (chunk_name == png_sPLT)\r
378    {\r
379       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
380       {\r
381          png_push_save_buffer(png_ptr);\r
382          return;\r
383       }\r
384 \r
385       png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length);\r
386    }\r
387 \r
388 #endif\r
389 #ifdef PNG_READ_tRNS_SUPPORTED\r
390    else if (chunk_name == png_tRNS)\r
391    {\r
392       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
393       {\r
394          png_push_save_buffer(png_ptr);\r
395          return;\r
396       }\r
397 \r
398       png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length);\r
399    }\r
400 \r
401 #endif\r
402 #ifdef PNG_READ_bKGD_SUPPORTED\r
403    else if (chunk_name == png_bKGD)\r
404    {\r
405       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
406       {\r
407          png_push_save_buffer(png_ptr);\r
408          return;\r
409       }\r
410 \r
411       png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length);\r
412    }\r
413 \r
414 #endif\r
415 #ifdef PNG_READ_hIST_SUPPORTED\r
416    else if (chunk_name == png_hIST)\r
417    {\r
418       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
419       {\r
420          png_push_save_buffer(png_ptr);\r
421          return;\r
422       }\r
423 \r
424       png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length);\r
425    }\r
426 \r
427 #endif\r
428 #ifdef PNG_READ_pHYs_SUPPORTED\r
429    else if (chunk_name == png_pHYs)\r
430    {\r
431       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
432       {\r
433          png_push_save_buffer(png_ptr);\r
434          return;\r
435       }\r
436 \r
437       png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length);\r
438    }\r
439 \r
440 #endif\r
441 #ifdef PNG_READ_oFFs_SUPPORTED\r
442    else if (chunk_name == png_oFFs)\r
443    {\r
444       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
445       {\r
446          png_push_save_buffer(png_ptr);\r
447          return;\r
448       }\r
449 \r
450       png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length);\r
451    }\r
452 #endif\r
453 \r
454 #ifdef PNG_READ_pCAL_SUPPORTED\r
455    else if (chunk_name == png_pCAL)\r
456    {\r
457       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
458       {\r
459          png_push_save_buffer(png_ptr);\r
460          return;\r
461       }\r
462 \r
463       png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length);\r
464    }\r
465 \r
466 #endif\r
467 #ifdef PNG_READ_sCAL_SUPPORTED\r
468    else if (chunk_name == png_sCAL)\r
469    {\r
470       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
471       {\r
472          png_push_save_buffer(png_ptr);\r
473          return;\r
474       }\r
475 \r
476       png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length);\r
477    }\r
478 \r
479 #endif\r
480 #ifdef PNG_READ_tIME_SUPPORTED\r
481    else if (chunk_name == png_tIME)\r
482    {\r
483       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
484       {\r
485          png_push_save_buffer(png_ptr);\r
486          return;\r
487       }\r
488 \r
489       png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length);\r
490    }\r
491 \r
492 #endif\r
493 #ifdef PNG_READ_tEXt_SUPPORTED\r
494    else if (chunk_name == png_tEXt)\r
495    {\r
496       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
497       {\r
498          png_push_save_buffer(png_ptr);\r
499          return;\r
500       }\r
501 \r
502       png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);\r
503    }\r
504 \r
505 #endif\r
506 #ifdef PNG_READ_zTXt_SUPPORTED\r
507    else if (chunk_name == png_zTXt)\r
508    {\r
509       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
510       {\r
511          png_push_save_buffer(png_ptr);\r
512          return;\r
513       }\r
514 \r
515       png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);\r
516    }\r
517 \r
518 #endif\r
519 #ifdef PNG_READ_iTXt_SUPPORTED\r
520    else if (chunk_name == png_iTXt)\r
521    {\r
522       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
523       {\r
524          png_push_save_buffer(png_ptr);\r
525          return;\r
526       }\r
527 \r
528       png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);\r
529    }\r
530 \r
531 #endif\r
532    else\r
533    {\r
534       if (png_ptr->push_length + 4 > png_ptr->buffer_size)\r
535       {\r
536          png_push_save_buffer(png_ptr);\r
537          return;\r
538       }\r
539       png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length,\r
540          PNG_HANDLE_CHUNK_AS_DEFAULT);\r
541    }\r
542 \r
543    png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;\r
544 }\r
545 \r
546 void /* PRIVATE */\r
547 png_push_crc_skip(png_structrp png_ptr, png_uint_32 skip)\r
548 {\r
549    png_ptr->process_mode = PNG_SKIP_MODE;\r
550    png_ptr->skip_length = skip;\r
551 }\r
552 \r
553 void /* PRIVATE */\r
554 png_push_crc_finish(png_structrp png_ptr)\r
555 {\r
556    if (png_ptr->skip_length && png_ptr->save_buffer_size)\r
557    {\r
558       png_size_t save_size = png_ptr->save_buffer_size;\r
559       png_uint_32 skip_length = png_ptr->skip_length;\r
560 \r
561       /* We want the smaller of 'skip_length' and 'save_buffer_size', but\r
562        * they are of different types and we don't know which variable has the\r
563        * fewest bits.  Carefully select the smaller and cast it to the type of\r
564        * the larger - this cannot overflow.  Do not cast in the following test\r
565        * - it will break on either 16 or 64 bit platforms.\r
566        */\r
567       if (skip_length < save_size)\r
568          save_size = (png_size_t)skip_length;\r
569 \r
570       else\r
571          skip_length = (png_uint_32)save_size;\r
572 \r
573       png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);\r
574 \r
575       png_ptr->skip_length -= skip_length;\r
576       png_ptr->buffer_size -= save_size;\r
577       png_ptr->save_buffer_size -= save_size;\r
578       png_ptr->save_buffer_ptr += save_size;\r
579    }\r
580    if (png_ptr->skip_length && png_ptr->current_buffer_size)\r
581    {\r
582       png_size_t save_size = png_ptr->current_buffer_size;\r
583       png_uint_32 skip_length = png_ptr->skip_length;\r
584 \r
585       /* We want the smaller of 'skip_length' and 'current_buffer_size', here,\r
586        * the same problem exists as above and the same solution.\r
587        */\r
588       if (skip_length < save_size)\r
589          save_size = (png_size_t)skip_length;\r
590 \r
591       else\r
592          skip_length = (png_uint_32)save_size;\r
593 \r
594       png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);\r
595 \r
596       png_ptr->skip_length -= skip_length;\r
597       png_ptr->buffer_size -= save_size;\r
598       png_ptr->current_buffer_size -= save_size;\r
599       png_ptr->current_buffer_ptr += save_size;\r
600    }\r
601    if (!png_ptr->skip_length)\r
602    {\r
603       if (png_ptr->buffer_size < 4)\r
604       {\r
605          png_push_save_buffer(png_ptr);\r
606          return;\r
607       }\r
608 \r
609       png_crc_finish(png_ptr, 0);\r
610       png_ptr->process_mode = PNG_READ_CHUNK_MODE;\r
611    }\r
612 }\r
613 \r
614 void PNGCBAPI\r
615 png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)\r
616 {\r
617    png_bytep ptr;\r
618 \r
619    if (png_ptr == NULL)\r
620       return;\r
621 \r
622    ptr = buffer;\r
623    if (png_ptr->save_buffer_size)\r
624    {\r
625       png_size_t save_size;\r
626 \r
627       if (length < png_ptr->save_buffer_size)\r
628          save_size = length;\r
629 \r
630       else\r
631          save_size = png_ptr->save_buffer_size;\r
632 \r
633       memcpy(ptr, png_ptr->save_buffer_ptr, save_size);\r
634       length -= save_size;\r
635       ptr += save_size;\r
636       png_ptr->buffer_size -= save_size;\r
637       png_ptr->save_buffer_size -= save_size;\r
638       png_ptr->save_buffer_ptr += save_size;\r
639    }\r
640    if (length && png_ptr->current_buffer_size)\r
641    {\r
642       png_size_t save_size;\r
643 \r
644       if (length < png_ptr->current_buffer_size)\r
645          save_size = length;\r
646 \r
647       else\r
648          save_size = png_ptr->current_buffer_size;\r
649 \r
650       memcpy(ptr, png_ptr->current_buffer_ptr, save_size);\r
651       png_ptr->buffer_size -= save_size;\r
652       png_ptr->current_buffer_size -= save_size;\r
653       png_ptr->current_buffer_ptr += save_size;\r
654    }\r
655 }\r
656 \r
657 void /* PRIVATE */\r
658 png_push_save_buffer(png_structrp png_ptr)\r
659 {\r
660    if (png_ptr->save_buffer_size)\r
661    {\r
662       if (png_ptr->save_buffer_ptr != png_ptr->save_buffer)\r
663       {\r
664          png_size_t i, istop;\r
665          png_bytep sp;\r
666          png_bytep dp;\r
667 \r
668          istop = png_ptr->save_buffer_size;\r
669          for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer;\r
670              i < istop; i++, sp++, dp++)\r
671          {\r
672             *dp = *sp;\r
673          }\r
674       }\r
675    }\r
676    if (png_ptr->save_buffer_size + png_ptr->current_buffer_size >\r
677        png_ptr->save_buffer_max)\r
678    {\r
679       png_size_t new_max;\r
680       png_bytep old_buffer;\r
681 \r
682       if (png_ptr->save_buffer_size > PNG_SIZE_MAX -\r
683           (png_ptr->current_buffer_size + 256))\r
684       {\r
685          png_error(png_ptr, "Potential overflow of save_buffer");\r
686       }\r
687 \r
688       new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256;\r
689       old_buffer = png_ptr->save_buffer;\r
690       png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr,\r
691           (png_size_t)new_max);\r
692 \r
693       if (png_ptr->save_buffer == NULL)\r
694       {\r
695          png_free(png_ptr, old_buffer);\r
696          png_error(png_ptr, "Insufficient memory for save_buffer");\r
697       }\r
698 \r
699       memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size);\r
700       png_free(png_ptr, old_buffer);\r
701       png_ptr->save_buffer_max = new_max;\r
702    }\r
703    if (png_ptr->current_buffer_size)\r
704    {\r
705       memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,\r
706          png_ptr->current_buffer_ptr, png_ptr->current_buffer_size);\r
707       png_ptr->save_buffer_size += png_ptr->current_buffer_size;\r
708       png_ptr->current_buffer_size = 0;\r
709    }\r
710    png_ptr->save_buffer_ptr = png_ptr->save_buffer;\r
711    png_ptr->buffer_size = 0;\r
712 }\r
713 \r
714 void /* PRIVATE */\r
715 png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer,\r
716    png_size_t buffer_length)\r
717 {\r
718    png_ptr->current_buffer = buffer;\r
719    png_ptr->current_buffer_size = buffer_length;\r
720    png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size;\r
721    png_ptr->current_buffer_ptr = png_ptr->current_buffer;\r
722 }\r
723 \r
724 void /* PRIVATE */\r
725 png_push_read_IDAT(png_structrp png_ptr)\r
726 {\r
727    if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))\r
728    {\r
729       png_byte chunk_length[4];\r
730       png_byte chunk_tag[4];\r
731 \r
732       /* TODO: this code can be commoned up with the same code in push_read */\r
733       if (png_ptr->buffer_size < 8)\r
734       {\r
735          png_push_save_buffer(png_ptr);\r
736          return;\r
737       }\r
738 \r
739       png_push_fill_buffer(png_ptr, chunk_length, 4);\r
740       png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);\r
741       png_reset_crc(png_ptr);\r
742       png_crc_read(png_ptr, chunk_tag, 4);\r
743       png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);\r
744       png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;\r
745 \r
746       if (png_ptr->chunk_name != png_IDAT)\r
747       {\r
748          png_ptr->process_mode = PNG_READ_CHUNK_MODE;\r
749 \r
750          if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))\r
751             png_error(png_ptr, "Not enough compressed data");\r
752 \r
753          return;\r
754       }\r
755 \r
756       png_ptr->idat_size = png_ptr->push_length;\r
757    }\r
758 \r
759    if (png_ptr->idat_size && png_ptr->save_buffer_size)\r
760    {\r
761       png_size_t save_size = png_ptr->save_buffer_size;\r
762       png_uint_32 idat_size = png_ptr->idat_size;\r
763 \r
764       /* We want the smaller of 'idat_size' and 'current_buffer_size', but they\r
765        * are of different types and we don't know which variable has the fewest\r
766        * bits.  Carefully select the smaller and cast it to the type of the\r
767        * larger - this cannot overflow.  Do not cast in the following test - it\r
768        * will break on either 16 or 64 bit platforms.\r
769        */\r
770       if (idat_size < save_size)\r
771          save_size = (png_size_t)idat_size;\r
772 \r
773       else\r
774          idat_size = (png_uint_32)save_size;\r
775 \r
776       png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);\r
777 \r
778       png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size);\r
779 \r
780       png_ptr->idat_size -= idat_size;\r
781       png_ptr->buffer_size -= save_size;\r
782       png_ptr->save_buffer_size -= save_size;\r
783       png_ptr->save_buffer_ptr += save_size;\r
784    }\r
785 \r
786    if (png_ptr->idat_size && png_ptr->current_buffer_size)\r
787    {\r
788       png_size_t save_size = png_ptr->current_buffer_size;\r
789       png_uint_32 idat_size = png_ptr->idat_size;\r
790 \r
791       /* We want the smaller of 'idat_size' and 'current_buffer_size', but they\r
792        * are of different types and we don't know which variable has the fewest\r
793        * bits.  Carefully select the smaller and cast it to the type of the\r
794        * larger - this cannot overflow.\r
795        */\r
796       if (idat_size < save_size)\r
797          save_size = (png_size_t)idat_size;\r
798 \r
799       else\r
800          idat_size = (png_uint_32)save_size;\r
801 \r
802       png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);\r
803 \r
804       png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size);\r
805 \r
806       png_ptr->idat_size -= idat_size;\r
807       png_ptr->buffer_size -= save_size;\r
808       png_ptr->current_buffer_size -= save_size;\r
809       png_ptr->current_buffer_ptr += save_size;\r
810    }\r
811    if (!png_ptr->idat_size)\r
812    {\r
813       if (png_ptr->buffer_size < 4)\r
814       {\r
815          png_push_save_buffer(png_ptr);\r
816          return;\r
817       }\r
818 \r
819       png_crc_finish(png_ptr, 0);\r
820       png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;\r
821       png_ptr->mode |= PNG_AFTER_IDAT;\r
822       png_ptr->zowner = 0;\r
823    }\r
824 }\r
825 \r
826 void /* PRIVATE */\r
827 png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,\r
828    png_size_t buffer_length)\r
829 {\r
830    /* The caller checks for a non-zero buffer length. */\r
831    if (!(buffer_length > 0) || buffer == NULL)\r
832       png_error(png_ptr, "No IDAT data (internal error)");\r
833 \r
834    /* This routine must process all the data it has been given\r
835     * before returning, calling the row callback as required to\r
836     * handle the uncompressed results.\r
837     */\r
838    png_ptr->zstream.next_in = buffer;\r
839    /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */\r
840    png_ptr->zstream.avail_in = (uInt)buffer_length;\r
841 \r
842    /* Keep going until the decompressed data is all processed\r
843     * or the stream marked as finished.\r
844     */\r
845    while (png_ptr->zstream.avail_in > 0 &&\r
846       !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))\r
847    {\r
848       int ret;\r
849 \r
850       /* We have data for zlib, but we must check that zlib\r
851        * has someplace to put the results.  It doesn't matter\r
852        * if we don't expect any results -- it may be the input\r
853        * data is just the LZ end code.\r
854        */\r
855       if (!(png_ptr->zstream.avail_out > 0))\r
856       {\r
857          /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */\r
858          png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth,\r
859              png_ptr->iwidth) + 1);\r
860 \r
861          png_ptr->zstream.next_out = png_ptr->row_buf;\r
862       }\r
863 \r
864       /* Using Z_SYNC_FLUSH here means that an unterminated\r
865        * LZ stream (a stream with a missing end code) can still\r
866        * be handled, otherwise (Z_NO_FLUSH) a future zlib\r
867        * implementation might defer output and therefore\r
868        * change the current behavior (see comments in inflate.c\r
869        * for why this doesn't happen at present with zlib 1.2.5).\r
870        */\r
871       ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH);\r
872 \r
873       /* Check for any failure before proceeding. */\r
874       if (ret != Z_OK && ret != Z_STREAM_END)\r
875       {\r
876          /* Terminate the decompression. */\r
877          png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;\r
878          png_ptr->zowner = 0;\r
879 \r
880          /* This may be a truncated stream (missing or\r
881           * damaged end code).  Treat that as a warning.\r
882           */\r
883          if (png_ptr->row_number >= png_ptr->num_rows ||\r
884              png_ptr->pass > 6)\r
885             png_warning(png_ptr, "Truncated compressed data in IDAT");\r
886 \r
887          else\r
888             png_error(png_ptr, "Decompression error in IDAT");\r
889 \r
890          /* Skip the check on unprocessed input */\r
891          return;\r
892       }\r
893 \r
894       /* Did inflate output any data? */\r
895       if (png_ptr->zstream.next_out != png_ptr->row_buf)\r
896       {\r
897          /* Is this unexpected data after the last row?\r
898           * If it is, artificially terminate the LZ output\r
899           * here.\r
900           */\r
901          if (png_ptr->row_number >= png_ptr->num_rows ||\r
902              png_ptr->pass > 6)\r
903          {\r
904             /* Extra data. */\r
905             png_warning(png_ptr, "Extra compressed data in IDAT");\r
906             png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;\r
907             png_ptr->zowner = 0;\r
908 \r
909             /* Do no more processing; skip the unprocessed\r
910              * input check below.\r
911              */\r
912             return;\r
913          }\r
914 \r
915          /* Do we have a complete row? */\r
916          if (png_ptr->zstream.avail_out == 0)\r
917             png_push_process_row(png_ptr);\r
918       }\r
919 \r
920       /* And check for the end of the stream. */\r
921       if (ret == Z_STREAM_END)\r
922          png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;\r
923    }\r
924 \r
925    /* All the data should have been processed, if anything\r
926     * is left at this point we have bytes of IDAT data\r
927     * after the zlib end code.\r
928     */\r
929    if (png_ptr->zstream.avail_in > 0)\r
930       png_warning(png_ptr, "Extra compression data in IDAT");\r
931 }\r
932 \r
933 void /* PRIVATE */\r
934 png_push_process_row(png_structrp png_ptr)\r
935 {\r
936    /* 1.5.6: row_info moved out of png_struct to a local here. */\r
937    png_row_info row_info;\r
938 \r
939    row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */\r
940    row_info.color_type = png_ptr->color_type;\r
941    row_info.bit_depth = png_ptr->bit_depth;\r
942    row_info.channels = png_ptr->channels;\r
943    row_info.pixel_depth = png_ptr->pixel_depth;\r
944    row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);\r
945 \r
946    if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE)\r
947    {\r
948       if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST)\r
949          png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1,\r
950             png_ptr->prev_row + 1, png_ptr->row_buf[0]);\r
951       else\r
952          png_error(png_ptr, "bad adaptive filter value");\r
953    }\r
954 \r
955    /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before\r
956     * 1.5.6, while the buffer really is this big in current versions of libpng\r
957     * it may not be in the future, so this was changed just to copy the\r
958     * interlaced row count:\r
959     */\r
960    memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1);\r
961 \r
962 #ifdef PNG_READ_TRANSFORMS_SUPPORTED\r
963    if (png_ptr->transformations)\r
964       png_do_read_transformations(png_ptr, &row_info);\r
965 #endif\r
966 \r
967    /* The transformed pixel depth should match the depth now in row_info. */\r
968    if (png_ptr->transformed_pixel_depth == 0)\r
969    {\r
970       png_ptr->transformed_pixel_depth = row_info.pixel_depth;\r
971       if (row_info.pixel_depth > png_ptr->maximum_pixel_depth)\r
972          png_error(png_ptr, "progressive row overflow");\r
973    }\r
974 \r
975    else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth)\r
976       png_error(png_ptr, "internal progressive row size calculation error");\r
977 \r
978 \r
979 #ifdef PNG_READ_INTERLACING_SUPPORTED\r
980    /* Blow up interlaced rows to full size */\r
981    if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))\r
982    {\r
983       if (png_ptr->pass < 6)\r
984          png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass,\r
985             png_ptr->transformations);\r
986 \r
987     switch (png_ptr->pass)\r
988     {\r
989          case 0:\r
990          {\r
991             int i;\r
992             for (i = 0; i < 8 && png_ptr->pass == 0; i++)\r
993             {\r
994                png_push_have_row(png_ptr, png_ptr->row_buf + 1);\r
995                png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */\r
996             }\r
997 \r
998             if (png_ptr->pass == 2) /* Pass 1 might be empty */\r
999             {\r
1000                for (i = 0; i < 4 && png_ptr->pass == 2; i++)\r
1001                {\r
1002                   png_push_have_row(png_ptr, NULL);\r
1003                   png_read_push_finish_row(png_ptr);\r
1004                }\r
1005             }\r
1006 \r
1007             if (png_ptr->pass == 4 && png_ptr->height <= 4)\r
1008             {\r
1009                for (i = 0; i < 2 && png_ptr->pass == 4; i++)\r
1010                {\r
1011                   png_push_have_row(png_ptr, NULL);\r
1012                   png_read_push_finish_row(png_ptr);\r
1013                }\r
1014             }\r
1015 \r
1016             if (png_ptr->pass == 6 && png_ptr->height <= 4)\r
1017             {\r
1018                 png_push_have_row(png_ptr, NULL);\r
1019                 png_read_push_finish_row(png_ptr);\r
1020             }\r
1021 \r
1022             break;\r
1023          }\r
1024 \r
1025          case 1:\r
1026          {\r
1027             int i;\r
1028             for (i = 0; i < 8 && png_ptr->pass == 1; i++)\r
1029             {\r
1030                png_push_have_row(png_ptr, png_ptr->row_buf + 1);\r
1031                png_read_push_finish_row(png_ptr);\r
1032             }\r
1033 \r
1034             if (png_ptr->pass == 2) /* Skip top 4 generated rows */\r
1035             {\r
1036                for (i = 0; i < 4 && png_ptr->pass == 2; i++)\r
1037                {\r
1038                   png_push_have_row(png_ptr, NULL);\r
1039                   png_read_push_finish_row(png_ptr);\r
1040                }\r
1041             }\r
1042 \r
1043             break;\r
1044          }\r
1045 \r
1046          case 2:\r
1047          {\r
1048             int i;\r
1049 \r
1050             for (i = 0; i < 4 && png_ptr->pass == 2; i++)\r
1051             {\r
1052                png_push_have_row(png_ptr, png_ptr->row_buf + 1);\r
1053                png_read_push_finish_row(png_ptr);\r
1054             }\r
1055 \r
1056             for (i = 0; i < 4 && png_ptr->pass == 2; i++)\r
1057             {\r
1058                png_push_have_row(png_ptr, NULL);\r
1059                png_read_push_finish_row(png_ptr);\r
1060             }\r
1061 \r
1062             if (png_ptr->pass == 4) /* Pass 3 might be empty */\r
1063             {\r
1064                for (i = 0; i < 2 && png_ptr->pass == 4; i++)\r
1065                {\r
1066                   png_push_have_row(png_ptr, NULL);\r
1067                   png_read_push_finish_row(png_ptr);\r
1068                }\r
1069             }\r
1070 \r
1071             break;\r
1072          }\r
1073 \r
1074          case 3:\r
1075          {\r
1076             int i;\r
1077 \r
1078             for (i = 0; i < 4 && png_ptr->pass == 3; i++)\r
1079             {\r
1080                png_push_have_row(png_ptr, png_ptr->row_buf + 1);\r
1081                png_read_push_finish_row(png_ptr);\r
1082             }\r
1083 \r
1084             if (png_ptr->pass == 4) /* Skip top two generated rows */\r
1085             {\r
1086                for (i = 0; i < 2 && png_ptr->pass == 4; i++)\r
1087                {\r
1088                   png_push_have_row(png_ptr, NULL);\r
1089                   png_read_push_finish_row(png_ptr);\r
1090                }\r
1091             }\r
1092 \r
1093             break;\r
1094          }\r
1095 \r
1096          case 4:\r
1097          {\r
1098             int i;\r
1099 \r
1100             for (i = 0; i < 2 && png_ptr->pass == 4; i++)\r
1101             {\r
1102                png_push_have_row(png_ptr, png_ptr->row_buf + 1);\r
1103                png_read_push_finish_row(png_ptr);\r
1104             }\r
1105 \r
1106             for (i = 0; i < 2 && png_ptr->pass == 4; i++)\r
1107             {\r
1108                png_push_have_row(png_ptr, NULL);\r
1109                png_read_push_finish_row(png_ptr);\r
1110             }\r
1111 \r
1112             if (png_ptr->pass == 6) /* Pass 5 might be empty */\r
1113             {\r
1114                png_push_have_row(png_ptr, NULL);\r
1115                png_read_push_finish_row(png_ptr);\r
1116             }\r
1117 \r
1118             break;\r
1119          }\r
1120 \r
1121          case 5:\r
1122          {\r
1123             int i;\r
1124 \r
1125             for (i = 0; i < 2 && png_ptr->pass == 5; i++)\r
1126             {\r
1127                png_push_have_row(png_ptr, png_ptr->row_buf + 1);\r
1128                png_read_push_finish_row(png_ptr);\r
1129             }\r
1130 \r
1131             if (png_ptr->pass == 6) /* Skip top generated row */\r
1132             {\r
1133                png_push_have_row(png_ptr, NULL);\r
1134                png_read_push_finish_row(png_ptr);\r
1135             }\r
1136 \r
1137             break;\r
1138          }\r
1139 \r
1140          default:\r
1141          case 6:\r
1142          {\r
1143             png_push_have_row(png_ptr, png_ptr->row_buf + 1);\r
1144             png_read_push_finish_row(png_ptr);\r
1145 \r
1146             if (png_ptr->pass != 6)\r
1147                break;\r
1148 \r
1149             png_push_have_row(png_ptr, NULL);\r
1150             png_read_push_finish_row(png_ptr);\r
1151          }\r
1152       }\r
1153    }\r
1154    else\r
1155 #endif\r
1156    {\r
1157       png_push_have_row(png_ptr, png_ptr->row_buf + 1);\r
1158       png_read_push_finish_row(png_ptr);\r
1159    }\r
1160 }\r
1161 \r
1162 void /* PRIVATE */\r
1163 png_read_push_finish_row(png_structrp png_ptr)\r
1164 {\r
1165 #ifdef PNG_READ_INTERLACING_SUPPORTED\r
1166    /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */\r
1167 \r
1168    /* Start of interlace block */\r
1169    static PNG_CONST png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};\r
1170 \r
1171    /* Offset to next interlace block */\r
1172    static PNG_CONST png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};\r
1173 \r
1174    /* Start of interlace block in the y direction */\r
1175    static PNG_CONST png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};\r
1176 \r
1177    /* Offset to next interlace block in the y direction */\r
1178    static PNG_CONST png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};\r
1179 \r
1180    /* Height of interlace block.  This is not currently used - if you need\r
1181     * it, uncomment it here and in png.h\r
1182    static PNG_CONST png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};\r
1183    */\r
1184 #endif\r
1185 \r
1186    png_ptr->row_number++;\r
1187    if (png_ptr->row_number < png_ptr->num_rows)\r
1188       return;\r
1189 \r
1190 #ifdef PNG_READ_INTERLACING_SUPPORTED\r
1191    if (png_ptr->interlaced)\r
1192    {\r
1193       png_ptr->row_number = 0;\r
1194       memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);\r
1195 \r
1196       do\r
1197       {\r
1198          png_ptr->pass++;\r
1199          if ((png_ptr->pass == 1 && png_ptr->width < 5) ||\r
1200              (png_ptr->pass == 3 && png_ptr->width < 3) ||\r
1201              (png_ptr->pass == 5 && png_ptr->width < 2))\r
1202             png_ptr->pass++;\r
1203 \r
1204          if (png_ptr->pass > 7)\r
1205             png_ptr->pass--;\r
1206 \r
1207          if (png_ptr->pass >= 7)\r
1208             break;\r
1209 \r
1210          png_ptr->iwidth = (png_ptr->width +\r
1211              png_pass_inc[png_ptr->pass] - 1 -\r
1212              png_pass_start[png_ptr->pass]) /\r
1213              png_pass_inc[png_ptr->pass];\r
1214 \r
1215          if (png_ptr->transformations & PNG_INTERLACE)\r
1216             break;\r
1217 \r
1218          png_ptr->num_rows = (png_ptr->height +\r
1219              png_pass_yinc[png_ptr->pass] - 1 -\r
1220              png_pass_ystart[png_ptr->pass]) /\r
1221              png_pass_yinc[png_ptr->pass];\r
1222 \r
1223       } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0);\r
1224    }\r
1225 #endif /* PNG_READ_INTERLACING_SUPPORTED */\r
1226 }\r
1227 \r
1228 void /* PRIVATE */\r
1229 png_push_have_info(png_structrp png_ptr, png_inforp info_ptr)\r
1230 {\r
1231    if (png_ptr->info_fn != NULL)\r
1232       (*(png_ptr->info_fn))(png_ptr, info_ptr);\r
1233 }\r
1234 \r
1235 void /* PRIVATE */\r
1236 png_push_have_end(png_structrp png_ptr, png_inforp info_ptr)\r
1237 {\r
1238    if (png_ptr->end_fn != NULL)\r
1239       (*(png_ptr->end_fn))(png_ptr, info_ptr);\r
1240 }\r
1241 \r
1242 void /* PRIVATE */\r
1243 png_push_have_row(png_structrp png_ptr, png_bytep row)\r
1244 {\r
1245    if (png_ptr->row_fn != NULL)\r
1246       (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number,\r
1247          (int)png_ptr->pass);\r
1248 }\r
1249 \r
1250 #ifdef PNG_READ_INTERLACING_SUPPORTED\r
1251 void PNGAPI\r
1252 png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row,\r
1253     png_const_bytep new_row)\r
1254 {\r
1255    if (png_ptr == NULL)\r
1256       return;\r
1257 \r
1258    /* new_row is a flag here - if it is NULL then the app callback was called\r
1259     * from an empty row (see the calls to png_struct::row_fn below), otherwise\r
1260     * it must be png_ptr->row_buf+1\r
1261     */\r
1262    if (new_row != NULL)\r
1263       png_combine_row(png_ptr, old_row, 1/*display*/);\r
1264 }\r
1265 #endif /* PNG_READ_INTERLACING_SUPPORTED */\r
1266 \r
1267 void PNGAPI\r
1268 png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr,\r
1269     png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,\r
1270     png_progressive_end_ptr end_fn)\r
1271 {\r
1272    if (png_ptr == NULL)\r
1273       return;\r
1274 \r
1275    png_ptr->info_fn = info_fn;\r
1276    png_ptr->row_fn = row_fn;\r
1277    png_ptr->end_fn = end_fn;\r
1278 \r
1279    png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);\r
1280 }\r
1281 \r
1282 png_voidp PNGAPI\r
1283 png_get_progressive_ptr(png_const_structrp png_ptr)\r
1284 {\r
1285    if (png_ptr == NULL)\r
1286       return (NULL);\r
1287 \r
1288    return png_ptr->io_ptr;\r
1289 }\r
1290 #endif /* PNG_PROGRESSIVE_READ_SUPPORTED */\r