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