From fdc00a7042d912aafaabddae4d9c84199921ef23 Mon Sep 17 00:00:00 2001 From: Bo Xu Date: Tue, 28 Oct 2014 23:03:33 -0700 Subject: Merge XFA to PDFium master at 4dc95e7 on 10/28/2014 --- core/src/fpdfdoc/doc_formfield.cpp | 71 + core/src/fxcodec/codec/codec_int.h | 89 +- core/src/fxcodec/codec/fx_codec.cpp | 341 ++ core/src/fxcodec/codec/fx_codec_bmp.cpp | 124 + core/src/fxcodec/codec/fx_codec_gif.cpp | 176 + core/src/fxcodec/codec/fx_codec_jpeg.cpp | 78 +- core/src/fxcodec/codec/fx_codec_png.cpp | 245 + core/src/fxcodec/codec/fx_codec_progress.cpp | 2263 ++++++++ core/src/fxcodec/codec/fx_codec_progress.h | 206 + core/src/fxcodec/codec/fx_codec_tiff.cpp | 532 ++ core/src/fxcodec/fx_lpng/include/fx_png.h | 7 + core/src/fxcodec/fx_lpng/lpng_v163/fx_png.c | 4299 +++++++++++++++ core/src/fxcodec/fx_lpng/lpng_v163/fx_pngerror.c | 933 ++++ core/src/fxcodec/fx_lpng/lpng_v163/fx_pngget.c | 1178 ++++ core/src/fxcodec/fx_lpng/lpng_v163/fx_pngmem.c | 291 + core/src/fxcodec/fx_lpng/lpng_v163/fx_pngpread.c | 1292 +++++ core/src/fxcodec/fx_lpng/lpng_v163/fx_pngread.c | 4001 ++++++++++++++ core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrio.c | 119 + core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrtran.c | 5104 ++++++++++++++++++ core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrutil.c | 4473 ++++++++++++++++ core/src/fxcodec/fx_lpng/lpng_v163/fx_pngset.c | 1598 ++++++ core/src/fxcodec/fx_lpng/lpng_v163/fx_pngtrans.c | 842 +++ core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwio.c | 165 + core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwrite.c | 2331 ++++++++ core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwtran.c | 638 +++ core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwutil.c | 3024 +++++++++++ core/src/fxcodec/fx_lpng/lpng_v163/png.h | 3563 +++++++++++++ core/src/fxcodec/fx_lpng/lpng_v163/pngconf.h | 617 +++ core/src/fxcodec/fx_lpng/lpng_v163/pngdebug.h | 157 + core/src/fxcodec/fx_lpng/lpng_v163/pnginfo.h | 260 + core/src/fxcodec/fx_lpng/lpng_v163/pnglibconf.h | 211 + core/src/fxcodec/fx_lpng/lpng_v163/pngpriv.h | 2006 +++++++ core/src/fxcodec/fx_lpng/lpng_v163/pngstruct.h | 489 ++ core/src/fxcodec/fx_lpng/src/fx_png.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngerror.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngget.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngmem.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngpread.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngread.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngrio.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngrtran.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngrutil.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngset.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngtrans.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngwio.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngwrite.c | 10 + core/src/fxcodec/fx_lpng/src/fx_pngwtran.c | 7 + core/src/fxcodec/fx_lpng/src/fx_pngwutil.c | 7 + core/src/fxcodec/fx_tiff/include/fx_tiffiop.h | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_aux.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_close.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_codec.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_color.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_compress.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_dir.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_dirinfo.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_dirread.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_dirwrite.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_dumpmode.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_error.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_extension.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_fax3.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_fax3sm.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_flush.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_getimage.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_jpeg.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_luv.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_lzw.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_next.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_ojpeg.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_open.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_packbits.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_pixarlog.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_predict.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_print.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_read.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_strip.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_swab.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_thunder.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_tile.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_version.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_warning.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_write.c | 7 + core/src/fxcodec/fx_tiff/src/fx_tif_zip.c | 7 + core/src/fxcodec/fx_tiff/tiff_v403/t4.h | 292 + core/src/fxcodec/fx_tiff/tiff_v403/tif_aux.c | 360 ++ core/src/fxcodec/fx_tiff/tiff_v403/tif_close.c | 143 + core/src/fxcodec/fx_tiff/tiff_v403/tif_codec.c | 168 + core/src/fxcodec/fx_tiff/tiff_v403/tif_color.c | 289 + core/src/fxcodec/fx_tiff/tiff_v403/tif_compress.c | 307 ++ core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.c | 1662 ++++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.h | 308 ++ core/src/fxcodec/fx_tiff/tiff_v403/tif_dirinfo.c | 978 ++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_dirread.c | 5616 ++++++++++++++++++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_dirwrite.c | 2912 ++++++++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_dumpmode.c | 146 + core/src/fxcodec/fx_tiff/tiff_v403/tif_error.c | 85 + core/src/fxcodec/fx_tiff/tiff_v403/tif_extension.c | 120 + core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.c | 1625 ++++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.h | 538 ++ core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3sm.c | 1263 +++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_flush.c | 121 + core/src/fxcodec/fx_tiff/tiff_v403/tif_getimage.c | 2991 +++++++++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_jpeg.c | 2311 ++++++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_luv.c | 1687 ++++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_lzw.c | 1169 ++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_next.c | 162 + core/src/fxcodec/fx_tiff/tiff_v403/tif_ojpeg.c | 2506 +++++++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_open.c | 728 +++ core/src/fxcodec/fx_tiff/tiff_v403/tif_packbits.c | 302 ++ core/src/fxcodec/fx_tiff/tiff_v403/tif_pixarlog.c | 1428 +++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.c | 813 +++ core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.h | 77 + core/src/fxcodec/fx_tiff/tiff_v403/tif_print.c | 719 +++ core/src/fxcodec/fx_tiff/tiff_v403/tif_read.c | 1116 ++++ core/src/fxcodec/fx_tiff/tiff_v403/tif_strip.c | 386 ++ core/src/fxcodec/fx_tiff/tiff_v403/tif_swab.c | 313 ++ core/src/fxcodec/fx_tiff/tiff_v403/tif_thunder.c | 210 + core/src/fxcodec/fx_tiff/tiff_v403/tif_tile.c | 302 ++ core/src/fxcodec/fx_tiff/tiff_v403/tif_version.c | 43 + core/src/fxcodec/fx_tiff/tiff_v403/tif_warning.c | 87 + core/src/fxcodec/fx_tiff/tiff_v403/tif_write.c | 774 +++ core/src/fxcodec/fx_tiff/tiff_v403/tif_zip.c | 471 ++ core/src/fxcodec/fx_tiff/tiff_v403/tiff.h | 678 +++ core/src/fxcodec/fx_tiff/tiff_v403/tiffconf.h | 250 + core/src/fxcodec/fx_tiff/tiff_v403/tiffio.h | 559 ++ core/src/fxcodec/fx_tiff/tiff_v403/tiffiop.h | 367 ++ core/src/fxcodec/fx_tiff/tiff_v403/tiffvers.h | 9 + core/src/fxcodec/fx_tiff/tiff_v403/uvcode.h | 180 + core/src/fxcodec/lbmp/fx_bmp.cpp | 917 ++++ core/src/fxcodec/lbmp/fx_bmp.h | 142 + core/src/fxcodec/lgif/fx_gif.cpp | 1368 +++++ core/src/fxcodec/lgif/fx_gif.h | 307 ++ core/src/fxcrt/extension.h | 38 + core/src/fxcrt/fx_arabic.cpp | 1078 ++++ core/src/fxcrt/fx_arabic.h | 175 +- core/src/fxcrt/fx_extension.cpp | 49 + core/src/fxcrt/fx_xml_parser.cpp | 4 +- core/src/fxge/ge/fx_ge_font.cpp | 231 +- core/src/fxge/ge/fx_ge_fontmap.cpp | 69 + core/src/fxge/ge/text_int.h | 21 +- 141 files changed, 84039 insertions(+), 14 deletions(-) create mode 100644 core/src/fxcodec/codec/fx_codec_bmp.cpp create mode 100644 core/src/fxcodec/codec/fx_codec_gif.cpp create mode 100644 core/src/fxcodec/codec/fx_codec_png.cpp create mode 100644 core/src/fxcodec/codec/fx_codec_progress.cpp create mode 100644 core/src/fxcodec/codec/fx_codec_progress.h create mode 100644 core/src/fxcodec/codec/fx_codec_tiff.cpp create mode 100644 core/src/fxcodec/fx_lpng/include/fx_png.h create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_png.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngerror.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngget.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngmem.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngpread.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngread.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrio.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrtran.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrutil.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngset.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngtrans.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwio.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwrite.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwtran.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwutil.c create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/png.h create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/pngconf.h create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/pngdebug.h create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/pnginfo.h create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/pnglibconf.h create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/pngpriv.h create mode 100644 core/src/fxcodec/fx_lpng/lpng_v163/pngstruct.h create mode 100644 core/src/fxcodec/fx_lpng/src/fx_png.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngerror.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngget.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngmem.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngpread.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngread.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngrio.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngrtran.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngrutil.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngset.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngtrans.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngwio.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngwrite.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngwtran.c create mode 100644 core/src/fxcodec/fx_lpng/src/fx_pngwutil.c create mode 100644 core/src/fxcodec/fx_tiff/include/fx_tiffiop.h create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_aux.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_close.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_codec.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_color.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_compress.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_dir.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_dirinfo.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_dirread.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_dirwrite.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_dumpmode.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_error.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_extension.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_fax3.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_fax3sm.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_flush.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_getimage.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_jpeg.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_luv.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_lzw.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_next.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_ojpeg.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_open.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_packbits.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_pixarlog.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_predict.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_print.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_read.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_strip.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_swab.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_thunder.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_tile.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_version.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_warning.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_write.c create mode 100644 core/src/fxcodec/fx_tiff/src/fx_tif_zip.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/t4.h create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_aux.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_close.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_codec.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_color.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_compress.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.h create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_dirinfo.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_dirread.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_dirwrite.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_dumpmode.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_error.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_extension.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.h create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3sm.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_flush.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_getimage.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_jpeg.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_luv.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_lzw.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_next.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_ojpeg.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_open.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_packbits.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_pixarlog.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.h create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_print.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_read.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_strip.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_swab.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_thunder.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_tile.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_version.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_warning.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_write.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tif_zip.c create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tiff.h create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tiffconf.h create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tiffio.h create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tiffiop.h create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/tiffvers.h create mode 100644 core/src/fxcodec/fx_tiff/tiff_v403/uvcode.h create mode 100644 core/src/fxcodec/lbmp/fx_bmp.cpp create mode 100644 core/src/fxcodec/lbmp/fx_bmp.h create mode 100644 core/src/fxcodec/lgif/fx_gif.cpp create mode 100644 core/src/fxcodec/lgif/fx_gif.h (limited to 'core/src') diff --git a/core/src/fpdfdoc/doc_formfield.cpp b/core/src/fpdfdoc/doc_formfield.cpp index a2f0fbd297..64e9c287cc 100644 --- a/core/src/fpdfdoc/doc_formfield.cpp +++ b/core/src/fpdfdoc/doc_formfield.cpp @@ -797,6 +797,77 @@ int CPDF_FormField::FindOptionValue(FX_LPCWSTR csOptValue, int iStartIndex) } return -1; } +int CPDF_FormField::InsertOption(CFX_WideString csOptLabel, int index, FX_BOOL bNotify) +{ + if (csOptLabel.IsEmpty()) return -1; + + if (bNotify && m_pForm->m_pFormNotify != NULL) + { + int iRet = 0; + if (GetType() == ListBox) iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csOptLabel); + if (GetType() == ComboBox) iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csOptLabel); + if (iRet < 0) return -1; + } + + CFX_ByteString csStr = PDF_EncodeText(csOptLabel, csOptLabel.GetLength()); + CPDF_Array* pOpt = NULL; + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt"); + if (pValue == NULL || pValue->GetType() != PDFOBJ_ARRAY) + { + pOpt = CPDF_Array::Create(); + if (pOpt == NULL) return -1; + m_pDict->SetAt("Opt", pOpt); + } + else + pOpt = (CPDF_Array*)pValue; + int iCount = (int)pOpt->GetCount(); + if (index < 0 || index >= iCount) + { + pOpt->AddString(csStr); + index = iCount; + } + else { + CPDF_String* pString = CPDF_String::Create(csStr); + if (pString == NULL) return -1; + pOpt->InsertAt(index, pString); + } + + if (bNotify && m_pForm->m_pFormNotify != NULL) + { + if (GetType() == ListBox) m_pForm->m_pFormNotify->AfterSelectionChange(this); + if (GetType() == ComboBox) m_pForm->m_pFormNotify->AfterValueChange(this); + } + m_pForm->m_bUpdated = TRUE; + return index; +} +FX_BOOL CPDF_FormField::ClearOptions(FX_BOOL bNotify) +{ + if (bNotify && m_pForm->m_pFormNotify != NULL) + { + int iRet = 0; + CFX_WideString csValue; + int iIndex = GetSelectedIndex(0); + if (iIndex >= 0) csValue = GetOptionLabel(iIndex); + if (GetType() == ListBox) iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue); + if (GetType() == ComboBox) iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue); + if (iRet < 0) return FALSE; + } + + m_pDict->RemoveAt("Opt"); + m_pDict->RemoveAt("V"); + m_pDict->RemoveAt("DV"); + m_pDict->RemoveAt("I"); + m_pDict->RemoveAt("TI"); + + if (bNotify && m_pForm->m_pFormNotify != NULL) + { + if (GetType() == ListBox) m_pForm->m_pFormNotify->AfterSelectionChange(this); + if (GetType() == ComboBox) m_pForm->m_pFormNotify->AfterValueChange(this); + } + + m_pForm->m_bUpdated = TRUE; + return TRUE; +} FX_BOOL CPDF_FormField::CheckControl(int iControlIndex, FX_BOOL bChecked, FX_BOOL bNotify) { ASSERT(GetType() == CheckBox || GetType() == RadioButton); diff --git a/core/src/fxcodec/codec/codec_int.h b/core/src/fxcodec/codec/codec_int.h index 78672e62ee..3cbdce9265 100644 --- a/core/src/fxcodec/codec/codec_int.h +++ b/core/src/fxcodec/codec/codec_int.h @@ -142,13 +142,67 @@ public: virtual void* Start(); virtual void Finish(void* pContext); virtual void Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size); - virtual int ReadHeader(void* pContext, int* width, int* height, int* nComps); + virtual int ReadHeader(void* pContext, int* width, int* height, int* nComps, CFX_DIBAttribute* pAttribute = NULL); virtual FX_BOOL StartScanline(void* pContext, int down_scale); virtual FX_BOOL ReadScanline(void* pContext, FX_LPBYTE dest_buf); virtual FX_DWORD GetAvailInput(void* pContext, FX_LPBYTE* avail_buf_ptr); protected: IFX_JpegProvider* m_pExtProvider; }; +#define PNG_ERROR_SIZE 256 +class CCodec_PngModule : public ICodec_PngModule +{ +public: + CCodec_PngModule() + { + FXSYS_memset8(m_szLastError, '\0', PNG_ERROR_SIZE); + } + + virtual void* Start(void* pModule); + virtual void Finish(void* pContext); + virtual FX_BOOL Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_DIBAttribute* pAttribute); +protected: + FX_CHAR m_szLastError[PNG_ERROR_SIZE]; +}; +class CCodec_GifModule : public ICodec_GifModule +{ +public: + CCodec_GifModule() + { + FXSYS_memset8(m_szLastError, '\0', 256); + } + virtual void* Start(void* pModule); + virtual void Finish(void* pContext); + virtual FX_DWORD GetAvailInput(void* pContext, FX_LPBYTE* avail_buf_ptr); + virtual void Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size); + + virtual FX_INT32 ReadHeader(void* pContext, int* width, int* height, + int* pal_num, void** pal_pp, int* bg_index, CFX_DIBAttribute* pAttribute); + + virtual FX_INT32 LoadFrameInfo(void* pContext, int* frame_num); + + virtual FX_INT32 LoadFrame(void* pContext, int frame_num, CFX_DIBAttribute* pAttribute); + +protected: + FX_CHAR m_szLastError[256]; +}; +class CCodec_BmpModule : public ICodec_BmpModule +{ +public: + CCodec_BmpModule() + { + FXSYS_memset8(m_szLastError, '\0', 256); + } + virtual void* Start(void* pModule); + virtual void Finish(void* pContext); + virtual FX_DWORD GetAvailInput(void* pContext, FX_LPBYTE* avail_buf_ptr); + virtual void Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size); + virtual FX_INT32 ReadHeader(void* pContext, FX_INT32* width, FX_INT32* height, FX_BOOL* tb_flag, FX_INT32* components, FX_INT32* pal_num, FX_DWORD** pal_pp, CFX_DIBAttribute* pAttribute); + virtual FX_INT32 LoadImage(void* pContext); + +protected: + FX_CHAR m_szLastError[256]; +}; class CCodec_IccModule : public ICodec_IccModule { public: @@ -196,6 +250,15 @@ public: FX_BOOL Decode(void* ctx, FX_LPBYTE dest_data, int pitch, FX_BOOL bTranslateColor, FX_LPBYTE offsets); void DestroyDecoder(void* ctx); }; +class CCodec_TiffModule : public ICodec_TiffModule +{ +public: + virtual FX_LPVOID CreateDecoder(IFX_FileRead* file_ptr); + virtual void GetFrames(FX_LPVOID ctx, FX_INT32& frames); + virtual FX_BOOL LoadFrameInfo(FX_LPVOID ctx, FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute = NULL); + virtual FX_BOOL Decode(FX_LPVOID ctx, class CFX_DIBitmap* pDIBitmap); + virtual void DestroyDecoder(FX_LPVOID ctx); +}; #include "../jbig2/JBig2_Context.h" class CPDF_Jbig2Interface : public CFX_Object, public CJBig2_Module { @@ -270,3 +333,27 @@ public: CPDF_Jbig2Interface m_Module; private: }; +class CFX_DIBAttributeExif : public IFX_DIBAttributeExif +{ +public: + CFX_DIBAttributeExif(); + ~CFX_DIBAttributeExif(); + virtual FX_BOOL GetInfo(FX_WORD tag, FX_LPVOID val); + + FX_BOOL ParseExif(CFX_MapPtrTemplate* pHead, FX_LPBYTE data, FX_DWORD len, CFX_MapPtrTemplate* pVal); + + typedef FX_WORD (*_Read2Bytes)(FX_LPBYTE data); + typedef FX_DWORD (*_Read4Bytes)(FX_LPBYTE data); + FX_LPBYTE ParseExifIFH(FX_LPBYTE data, FX_DWORD len, _Read2Bytes* pReadWord, _Read4Bytes* pReadDword); + FX_BOOL ParseExifIFD(CFX_MapPtrTemplate* pMap, FX_LPBYTE data, FX_DWORD len); + + FX_LPBYTE m_pExifData; + + FX_DWORD m_dwExifDataLen; + + void clear(); + _Read2Bytes m_readWord; + _Read4Bytes m_readDword; + CFX_MapPtrTemplate m_TagHead; + CFX_MapPtrTemplate m_TagVal; +}; diff --git a/core/src/fxcodec/codec/fx_codec.cpp b/core/src/fxcodec/codec/fx_codec.cpp index 456ec40fea..b2f70c73d1 100644 --- a/core/src/fxcodec/codec/fx_codec.cpp +++ b/core/src/fxcodec/codec/fx_codec.cpp @@ -14,6 +14,10 @@ CCodec_ModuleMgr::CCodec_ModuleMgr() m_pJpxModule = FX_NEW CCodec_JpxModule; m_pJbig2Module = FX_NEW CCodec_Jbig2Module; m_pIccModule = FX_NEW CCodec_IccModule; + m_pPngModule = FX_NEW CCodec_PngModule; + m_pGifModule = FX_NEW CCodec_GifModule; + m_pBmpModule = FX_NEW CCodec_BmpModule; + m_pTiffModule = FX_NEW CCodec_TiffModule; m_pFlateModule = FX_NEW CCodec_FlateModule; } CCodec_ModuleMgr::~CCodec_ModuleMgr() @@ -249,6 +253,343 @@ void CCodec_ModuleMgr::Destroy() { delete this; } +CFX_DIBAttribute::CFX_DIBAttribute() +{ + FXSYS_memset32(this, 0, sizeof(CFX_DIBAttribute)); + m_nXDPI = -1; + m_nYDPI = -1; + m_fAspectRatio = -1.0f; + m_pExif = FX_NEW CFX_DIBAttributeExif; +} +CFX_DIBAttribute::~CFX_DIBAttribute() +{ + if (m_pExif) { + delete m_pExif; + } +} +CFX_DIBAttributeExif::CFX_DIBAttributeExif() +{ + m_pExifData = NULL; + m_dwExifDataLen = 0; +} +CFX_DIBAttributeExif::~CFX_DIBAttributeExif() +{ + clear(); +} +void CFX_DIBAttributeExif::clear() +{ + if (m_pExifData) { + FX_Free(m_pExifData); + } + m_pExifData = NULL; + FX_DWORD key = 0; + FX_LPBYTE buf = NULL; + FX_POSITION pos = NULL; + pos = m_TagHead.GetStartPosition(); + while (pos) { + m_TagHead.GetNextAssoc(pos, key, buf); + if (buf) { + FX_Free(buf); + } + } + m_TagHead.RemoveAll(); + pos = m_TagVal.GetStartPosition(); + while (pos) { + m_TagVal.GetNextAssoc(pos, key, buf); + if (buf) { + FX_Free(buf); + } + } + m_TagVal.RemoveAll(); +} +static FX_WORD _Read2BytesL(FX_LPBYTE data) +{ + ASSERT(data); + return data[0] | (data[1] << 8); +} +static FX_WORD _Read2BytesB(FX_LPBYTE data) +{ + ASSERT(data); + return data[1] | (data[0] << 8); +} +static FX_DWORD _Read4BytesL(FX_LPBYTE data) +{ + return _Read2BytesL(data) | (_Read2BytesL(data + 2) << 16); +} +static FX_DWORD _Read4BytesB(FX_LPBYTE data) +{ + return _Read2BytesB(data + 2) | (_Read2BytesB(data) << 16); +} +typedef FX_WORD (*_Read2Bytes) (FX_LPBYTE data); +typedef FX_DWORD (*_Read4Bytes) (FX_LPBYTE data); +typedef void (*_Write2Bytes) (FX_LPBYTE data, FX_WORD val); +typedef void (*_Write4Bytes) (FX_LPBYTE data, FX_DWORD val); +FX_LPBYTE CFX_DIBAttributeExif::ParseExifIFH(FX_LPBYTE data, FX_DWORD len, _Read2Bytes* pReadWord, _Read4Bytes* pReadDword) +{ + if (len > 8) { + FX_BOOL tag = FALSE; + if (FXSYS_memcmp32(data, "\x49\x49\x2a\x00", 4) == 0) { + if (pReadWord) { + *pReadWord = _Read2BytesL; + } + if (pReadDword) { + *pReadDword = _Read4BytesL; + } + tag = TRUE; + } else if (FXSYS_memcmp32(data, "\x4d\x4d\x00\x2a", 4) == 0) { + if (pReadWord) { + *pReadWord = _Read2BytesB; + } + if (pReadDword) { + *pReadDword = _Read4BytesB; + } + tag = TRUE; + } + if (tag) { + data += 4; + if (pReadDword) { + data += (*pReadDword)(data) - 4; + } else { + data += 4; + } + } + } + return data; +} +FX_BOOL CFX_DIBAttributeExif::ParseExifIFD(CFX_MapPtrTemplate* pMap, FX_LPBYTE data, FX_DWORD len) +{ + if (pMap && data) { + if (len > 8) { + FX_WORD wTagNum = m_readWord(data); + data += 2; + FX_DWORD wTag; + FX_LPBYTE buf; + while (wTagNum--) { + wTag = m_readWord(data); + data += 2; + if (!pMap->Lookup(wTag, buf)) { + buf = FX_Alloc(FX_BYTE, 10); + if (buf == NULL) { + return FALSE; + } + FXSYS_memcpy32(buf, data, 10); + pMap->SetAt(wTag, buf); + } + data += 10; + } + FX_DWORD dwIFDOffset; + dwIFDOffset = m_readDword(data); + while (dwIFDOffset && dwIFDOffset < len) { + data = m_pExifData + dwIFDOffset; + wTagNum = m_readWord(data); + data += 2; + while (wTagNum--) { + wTag = m_readWord(data); + data += 2; + if (!pMap->Lookup(wTag, buf)) { + buf = FX_Alloc(FX_BYTE, 10); + if (buf == NULL) { + return FALSE; + } + FXSYS_memcpy32(buf, data, 10); + pMap->SetAt(wTag, buf); + } + data += 10; + } + dwIFDOffset = m_readDword(data); + } + return TRUE; + } + } + return FALSE; +} +enum FX_ExifDataType { + FX_UnsignedByte = 1, + FX_AscString, + FX_UnsignedShort, + FX_UnsignedLong, + FX_UnsignedRation, + FX_SignedByte, + FX_Undefined, + FX_SignedShort, + FX_SignedLong, + FX_SignedRation, + FX_SignedFloat, + FX_DoubleFloat +}; +FX_BOOL CFX_DIBAttributeExif::ParseExif(CFX_MapPtrTemplate* pHead, FX_LPBYTE data, FX_DWORD len, CFX_MapPtrTemplate* pVal) +{ + if (pHead && data && pVal) { + if (len > 8) { + FX_LPBYTE old_data = data; + data = ParseExifIFH(data, len, &m_readWord, &m_readDword); + if (data == old_data) { + return FALSE; + } + if (pHead->GetCount() == 0) { + if (!ParseExifIFD(pHead, data, len)) { + return FALSE; + } + } + FX_DWORD dwModuleNum; + FX_WORD type; + FX_DWORD dwSize; + FX_DWORD tag; + FX_LPBYTE head; + FX_POSITION pos = pHead->GetStartPosition(); + while (pos) { + pHead->GetNextAssoc(pos, tag, head); + FX_LPBYTE val = NULL, buf = NULL, temp = NULL; + int i; + if (head) { + type = m_readWord(head); + head += 2; + dwModuleNum = m_readDword(head); + head += 4; + switch (type) { + case FX_UnsignedByte: + case FX_AscString: + case FX_SignedByte: + case FX_Undefined: + dwSize = dwModuleNum; + val = FX_Alloc(FX_BYTE, dwSize); + if (val == NULL) { + return FALSE; + } + if (dwSize > 4) { + FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize); + } else { + FXSYS_memcpy32(val, head, dwSize); + } + break; + case FX_UnsignedShort: + case FX_SignedShort: + dwSize = dwModuleNum << 1; + val = FX_Alloc(FX_BYTE, dwSize); + if (val == NULL) { + return FALSE; + } + if (dwSize > 4) { + FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize); + } else { + FXSYS_memcpy32(val, head, dwSize); + } + buf = val; + for(i = 0; i < (int)dwModuleNum; i ++) { + *(FX_WORD*)buf = m_readWord(buf); + buf += 2; + } + break; + case FX_UnsignedLong: + case FX_SignedLong: + case FX_SignedFloat: + dwSize = dwModuleNum << 2; + val = FX_Alloc(FX_BYTE, dwSize); + if (val == NULL) { + return FALSE; + } + if (dwSize > 4) { + FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize); + } else { + FXSYS_memcpy32(val, head, dwSize); + } + buf = val; + for(i = 0; i < (int)dwModuleNum; i ++) { + *(FX_DWORD*)buf = m_readDword(buf); + buf += 4; + } + break; + case FX_UnsignedRation: + case FX_SignedRation: { + dwSize = dwModuleNum << 3; + buf = FX_Alloc(FX_BYTE, dwSize); + if (buf == NULL) { + return FALSE; + } + if (dwSize > 4) { + FXSYS_memcpy32(buf, old_data + m_readDword(head), dwSize); + } else { + FXSYS_memcpy32(buf, head, dwSize); + } + temp = buf; + val = FX_Alloc(FX_BYTE, dwSize / 2); + if (val == NULL) { + FX_Free(buf); + return FALSE; + } + for(i = 0; i < (int)dwModuleNum; i ++) { + *(FX_DWORD*)temp = m_readDword(temp); + *(FX_DWORD*)(temp + 4) = m_readDword(temp + 4); + FX_DWORD* lNumerator = (FX_DWORD*)temp; + FX_DWORD* lNenominator = (FX_DWORD*)(temp + 4); + *(FX_FLOAT*)(val + i * 4) = (FX_FLOAT)(*lNumerator) / (FX_FLOAT)(*lNenominator); + temp += 8; + } + FX_Free(buf); + } + break; + case FX_DoubleFloat: + dwSize = dwModuleNum << 3; + val = FX_Alloc(FX_BYTE, dwSize); + if (val == NULL) { + return FALSE; + } + if (dwSize > 4) { + FXSYS_memcpy32(val, old_data + m_readDword(head), dwSize); + } else { + FXSYS_memcpy32(val, head, dwSize); + } + buf = val; + for(i = 0; i < (int)dwModuleNum; i ++) { + *(FX_DWORD*)buf = m_readDword(buf); + *(FX_DWORD*)(buf + 4) = m_readDword(buf + 4); + buf += 8; + } + break; + default: + return FALSE; + } + } + pVal->SetAt(tag, val); + } + return TRUE; + } + } + return FALSE; +} +#define FXEXIF_INFOCONVERT(T) {T* src = (T*)ptr; T* dst = (T*)val; *dst = *src;} +FX_BOOL CFX_DIBAttributeExif::GetInfo( FX_WORD tag, FX_LPVOID val ) +{ + if (m_TagVal.GetCount() == 0) { + if (!ParseExif(&m_TagHead, m_pExifData, m_dwExifDataLen, &m_TagVal)) { + return FALSE; + } + } + FX_LPBYTE ptr = NULL; + if (m_TagVal.Lookup(tag, ptr)) { + switch (tag) { + case EXIFTAG_USHORT_RESUNIT: + FXEXIF_INFOCONVERT(FX_WORD); + { + FX_WORD* ptr = (FX_WORD*)val; + *ptr -= 1; + } + break; + case EXIFTAG_FLOAT_DPIX: + case EXIFTAG_FLOAT_DPIY: + FXEXIF_INFOCONVERT(FX_FLOAT); + break; + case EXIFTAG_USHORT_ORIENTATION: + FXEXIF_INFOCONVERT(FX_WORD); + break; + default: { + FX_LPBYTE* dst = (FX_LPBYTE*)val; + *dst = ptr; + } + } + } + return TRUE; +} class CCodec_RLScanlineDecoder : public CCodec_ScanlineDecoder { public: diff --git a/core/src/fxcodec/codec/fx_codec_bmp.cpp b/core/src/fxcodec/codec/fx_codec_bmp.cpp new file mode 100644 index 0000000000..4e974e2124 --- /dev/null +++ b/core/src/fxcodec/codec/fx_codec_bmp.cpp @@ -0,0 +1,124 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../../../include/fxcodec/fx_codec.h" +#include "../../../include/fxge/fx_dib.h" +#include "codec_int.h" +#include "../lbmp/fx_bmp.h" +struct FXBMP_Context { + bmp_decompress_struct_p bmp_ptr; + void* parent_ptr; + void* child_ptr; + + void* (*m_AllocFunc)(unsigned int); + void (*m_FreeFunc)(void*); +}; +extern "C" { + static void* _bmp_alloc_func(unsigned int size) + { + return FX_Alloc(char, size); + } + static void _bmp_free_func(void* p) + { + if(p != NULL) { + FX_Free(p); + } + } +}; +static void _bmp_error_data(bmp_decompress_struct_p bmp_ptr, FX_LPCSTR err_msg) +{ + FXSYS_strncpy((char*)bmp_ptr->err_ptr, err_msg, BMP_MAX_ERROR_SIZE - 1); + longjmp(bmp_ptr->jmpbuf, 1); +} +static void _bmp_read_scanline(bmp_decompress_struct_p bmp_ptr, FX_INT32 row_num, FX_LPBYTE row_buf) +{ + FXBMP_Context* p = (FXBMP_Context*)bmp_ptr->context_ptr; + CCodec_BmpModule* pModule = (CCodec_BmpModule*)p->parent_ptr; + pModule->ReadScanlineCallback(p->child_ptr, row_num, row_buf); +} +static FX_BOOL _bmp_get_data_position(bmp_decompress_struct_p bmp_ptr, FX_DWORD rcd_pos) +{ + FXBMP_Context* p = (FXBMP_Context*)bmp_ptr->context_ptr; + CCodec_BmpModule* pModule = (CCodec_BmpModule*)p->parent_ptr; + return pModule->InputImagePositionBufCallback(p->child_ptr, rcd_pos); +} +void* CCodec_BmpModule::Start(void* pModule) +{ + FXBMP_Context* p = (FXBMP_Context*)FX_Alloc(FX_BYTE, sizeof(FXBMP_Context)); + if (p == NULL) { + return NULL; + } + FXSYS_memset32(p, 0, sizeof(FXBMP_Context)); + if(p == NULL) { + return NULL; + } + p->m_AllocFunc = _bmp_alloc_func; + p->m_FreeFunc = _bmp_free_func; + p->bmp_ptr = NULL; + p->parent_ptr = (void*)this; + p->child_ptr = pModule; + p->bmp_ptr = _bmp_create_decompress(); + if (p->bmp_ptr == NULL) { + FX_Free(p); + return NULL; + } + p->bmp_ptr->context_ptr = (void*)p; + p->bmp_ptr->err_ptr = m_szLastError; + p->bmp_ptr->_bmp_error_fn = _bmp_error_data; + p->bmp_ptr->_bmp_get_row_fn = _bmp_read_scanline; + p->bmp_ptr->_bmp_get_data_position_fn = _bmp_get_data_position; + return p; +} +void CCodec_BmpModule::Finish(void* pContext) +{ + FXBMP_Context* p = (FXBMP_Context*)pContext; + if(p != NULL) { + _bmp_destroy_decompress(&p->bmp_ptr); + p->m_FreeFunc(p); + } +} +FX_INT32 CCodec_BmpModule::ReadHeader(void* pContext, FX_INT32* width, FX_INT32* height, FX_BOOL* tb_flag, FX_INT32* components, FX_INT32* pal_num, FX_DWORD** pal_pp, CFX_DIBAttribute* pAttribute) +{ + FXBMP_Context* p = (FXBMP_Context*)pContext; + if(setjmp(p->bmp_ptr->jmpbuf)) { + return 0; + } + FX_INT32 ret = _bmp_read_header(p->bmp_ptr); + if (ret != 1) { + return ret; + } + *width = p->bmp_ptr->width; + *height = p->bmp_ptr->height; + *tb_flag = p->bmp_ptr->imgTB_flag; + *components = p->bmp_ptr->components; + *pal_num = p->bmp_ptr->pal_num; + *pal_pp = p->bmp_ptr->pal_ptr; + if (pAttribute) { + pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_METER; + pAttribute->m_nXDPI = p->bmp_ptr->dpi_x; + pAttribute->m_nYDPI = p->bmp_ptr->dpi_y; + pAttribute->m_nBmpCompressType = p->bmp_ptr->compress_flag; + } + return 1; +} +FX_INT32 CCodec_BmpModule::LoadImage(void* pContext) +{ + FXBMP_Context* p = (FXBMP_Context*)pContext; + if(setjmp(p->bmp_ptr->jmpbuf)) { + return 0; + } + return _bmp_decode_image(p->bmp_ptr); +} +FX_DWORD CCodec_BmpModule::GetAvailInput(void* pContext, FX_LPBYTE* avial_buf_ptr) +{ + FXBMP_Context* p = (FXBMP_Context*)pContext; + return _bmp_get_avail_input(p->bmp_ptr, avial_buf_ptr); +} +void CCodec_BmpModule::Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size) +{ + FXBMP_Context* p = (FXBMP_Context*)pContext; + _bmp_input_buffer(p->bmp_ptr, (FX_LPBYTE)src_buf, src_size); +} diff --git a/core/src/fxcodec/codec/fx_codec_gif.cpp b/core/src/fxcodec/codec/fx_codec_gif.cpp new file mode 100644 index 0000000000..1fc708db5c --- /dev/null +++ b/core/src/fxcodec/codec/fx_codec_gif.cpp @@ -0,0 +1,176 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../../../include/fxcodec/fx_codec.h" +#include "../../../include/fxge/fx_dib.h" +#include "codec_int.h" +#include "../lgif/fx_gif.h" +struct FXGIF_Context { + gif_decompress_struct_p gif_ptr; + void* parent_ptr; + void* child_ptr; + + void* (*m_AllocFunc)(unsigned int); + void (*m_FreeFunc)(void*); +}; +extern "C" { + static void* _gif_alloc_func(unsigned int size) + { + return FX_Alloc(char, size); + } + static void _gif_free_func(void* p) + { + if(p != NULL) { + FX_Free(p); + } + } +}; +static void _gif_error_data(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg) +{ + FXSYS_strncpy((char*)gif_ptr->err_ptr, err_msg, GIF_MAX_ERROR_SIZE - 1); + longjmp(gif_ptr->jmpbuf, 1); +} +static FX_LPBYTE _gif_ask_buf_for_pal(gif_decompress_struct_p gif_ptr, FX_INT32 pal_size) +{ + FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr; + CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr; + return pModule->AskLocalPaletteBufCallback(p->child_ptr, + _gif_get_frame_num(gif_ptr), + pal_size); +} +static void _gif_record_current_position(gif_decompress_struct_p gif_ptr, FX_DWORD* cur_pos_ptr) +{ + FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr; + CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr; + pModule->RecordCurrentPositionCallback(p->child_ptr, *cur_pos_ptr); +} +static void _gif_read_scanline(gif_decompress_struct_p gif_ptr, FX_INT32 row_num, FX_LPBYTE row_buf) +{ + FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr; + CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr; + pModule->ReadScanlineCallback(p->child_ptr, row_num, row_buf); +} +static FX_BOOL _gif_get_record_position(gif_decompress_struct_p gif_ptr, FX_DWORD cur_pos, + FX_INT32 left, FX_INT32 top, FX_INT32 width, FX_INT32 height, + FX_INT32 pal_num, void* pal_ptr, + FX_INT32 delay_time, FX_BOOL user_input, + FX_INT32 trans_index, FX_INT32 disposal_method, FX_BOOL interlace) +{ + FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr; + CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr; + return pModule->InputRecordPositionBufCallback(p->child_ptr, cur_pos, FX_RECT(left, top, left + width, top + height), + pal_num, pal_ptr, delay_time, user_input, trans_index, disposal_method, interlace); +} +void* CCodec_GifModule::Start(void* pModule) +{ + FXGIF_Context* p = (FXGIF_Context*)FX_Alloc(FX_BYTE, sizeof(FXGIF_Context)); + if (p == NULL) { + return NULL; + } + FXSYS_memset32(p, 0, sizeof(FXGIF_Context)); + p->m_AllocFunc = _gif_alloc_func; + p->m_FreeFunc = _gif_free_func; + p->gif_ptr = NULL; + p->parent_ptr = (void*)this; + p->child_ptr = pModule; + p->gif_ptr = _gif_create_decompress(); + if (p->gif_ptr == NULL) { + FX_Free(p); + return NULL; + } + p->gif_ptr->context_ptr = (void*)p; + p->gif_ptr->err_ptr = m_szLastError; + p->gif_ptr->_gif_error_fn = _gif_error_data; + p->gif_ptr->_gif_ask_buf_for_pal_fn = _gif_ask_buf_for_pal; + p->gif_ptr->_gif_record_current_position_fn = _gif_record_current_position; + p->gif_ptr->_gif_get_row_fn = _gif_read_scanline; + p->gif_ptr->_gif_get_record_position_fn = _gif_get_record_position; + return p; +} +void CCodec_GifModule::Finish(void* pContext) +{ + FXGIF_Context* p = (FXGIF_Context*)pContext; + if(p != NULL) { + _gif_destroy_decompress(&p->gif_ptr); + p->m_FreeFunc(p); + } +} +FX_INT32 CCodec_GifModule::ReadHeader(void* pContext, int* width, int* height, + int* pal_num, void** pal_pp, int* bg_index, CFX_DIBAttribute* pAttribute) +{ + FXGIF_Context* p = (FXGIF_Context*)pContext; + if(setjmp(p->gif_ptr->jmpbuf)) { + return 0; + } + FX_INT32 ret = _gif_read_header(p->gif_ptr); + if (ret != 1) { + return ret; + } + if (pAttribute) { + } + *width = p->gif_ptr->width; + *height = p->gif_ptr->height; + *pal_num = p->gif_ptr->global_pal_num; + *pal_pp = p->gif_ptr->global_pal_ptr; + *bg_index = p->gif_ptr->bc_index; + return 1; +} +FX_INT32 CCodec_GifModule::LoadFrameInfo(void* pContext, int* frame_num) +{ + FXGIF_Context* p = (FXGIF_Context*)pContext; + if(setjmp(p->gif_ptr->jmpbuf)) { + return 0; + } + FX_INT32 ret = _gif_get_frame(p->gif_ptr); + if (ret != 1) { + return ret; + } + *frame_num = _gif_get_frame_num(p->gif_ptr); + return 1; +} +FX_INT32 CCodec_GifModule::LoadFrame(void* pContext, int frame_num, CFX_DIBAttribute* pAttribute) +{ + FXGIF_Context* p = (FXGIF_Context*)pContext; + if(setjmp(p->gif_ptr->jmpbuf)) { + return 0; + } + FX_INT32 ret = _gif_load_frame(p->gif_ptr, frame_num); + if (ret == 1) { + if (pAttribute) { + pAttribute->m_nGifLeft = p->gif_ptr->img_ptr_arr_ptr->GetAt(frame_num)->image_info_ptr->left; + pAttribute->m_nGifTop = p->gif_ptr->img_ptr_arr_ptr->GetAt(frame_num)->image_info_ptr->top; + pAttribute->m_fAspectRatio = p->gif_ptr->pixel_aspect; + if (p->gif_ptr->cmt_data_ptr) { + FX_LPCBYTE buf = (FX_LPCBYTE)p->gif_ptr->cmt_data_ptr->GetBuffer(0); + FX_DWORD len = p->gif_ptr->cmt_data_ptr->GetLength(); + if (len > 21) { + FX_BYTE size = *buf++; + if (size) { + pAttribute->m_strAuthor = CFX_ByteString(buf, size); + } else { + pAttribute->m_strAuthor.Empty(); + } + buf += size; + size = *buf++; + if (size == 20) { + FXSYS_memcpy32(pAttribute->m_strTime, buf, size); + } + } + } + } + } + return ret; +} +FX_DWORD CCodec_GifModule::GetAvailInput(void* pContext, FX_LPBYTE* avial_buf_ptr) +{ + FXGIF_Context* p = (FXGIF_Context*)pContext; + return _gif_get_avail_input(p->gif_ptr, avial_buf_ptr); +} +void CCodec_GifModule::Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size) +{ + FXGIF_Context* p = (FXGIF_Context*)pContext; + _gif_input_buffer(p->gif_ptr, (FX_LPBYTE)src_buf, src_size); +} diff --git a/core/src/fxcodec/codec/fx_codec_jpeg.cpp b/core/src/fxcodec/codec/fx_codec_jpeg.cpp index 489f099bf8..95770ea26e 100644 --- a/core/src/fxcodec/codec/fx_codec_jpeg.cpp +++ b/core/src/fxcodec/codec/fx_codec_jpeg.cpp @@ -73,6 +73,68 @@ extern "C" { #define JPEG_MARKER_AUTHORTIME (JPEG_APP0 + 3) #define JPEG_MARKER_MAXSIZE 0xFFFF #define JPEG_OVERHEAD_LEN 14 +static FX_BOOL _JpegIsIccMarker(jpeg_saved_marker_ptr marker) +{ + if (marker->marker == JPEG_MARKER_ICC && + marker->data_length >= JPEG_OVERHEAD_LEN && + (FXSYS_memcmp32(marker->data, "\x49\x43\x43\x5f\x50\x52\x4f\x46\x49\x4c\x45\x00", 12) == 0)) { + return TRUE; + } + return FALSE; +} +static FX_BOOL _JpegLoadIccProfile(j_decompress_ptr cinfo, FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length) +{ + if(icc_buf_ptr == NULL || icc_length == NULL) { + return FALSE; + } + *icc_buf_ptr = NULL; + *icc_length = 0; + FX_LPBYTE icc_data_ptr = NULL; + FX_DWORD icc_data_len = 0; + FX_BYTE count_icc_marker = 0; + FX_BYTE num_icc_marker = 0; + jpeg_saved_marker_ptr marker_list[256] = {NULL}; + for (jpeg_saved_marker_ptr cur_marker = cinfo->marker_list; + cur_marker != NULL; + cur_marker = cur_marker->next) { + if(_JpegIsIccMarker(cur_marker)) { + if(count_icc_marker == 0) { + num_icc_marker = cur_marker->data[13]; + } else if(num_icc_marker != cur_marker->data[13]) { + return FALSE; + } + int sn = cur_marker->data[12] - 1; + if(sn < 0 || sn >= num_icc_marker) { + return FALSE; + } + if(marker_list[sn] == NULL) { + marker_list[sn] = cur_marker; + } else { + return FALSE; + } + count_icc_marker ++; + icc_data_len += (cur_marker->data_length - JPEG_OVERHEAD_LEN); + } + } + if(count_icc_marker != num_icc_marker) { + return FALSE; + } + if(num_icc_marker == 0) { + return TRUE; + } + icc_data_ptr = FX_Alloc(FX_BYTE, icc_data_len); + if(icc_buf_ptr == NULL) { + return FALSE; + } + *icc_buf_ptr = icc_data_ptr; + *icc_length = icc_data_len; + for (int idx = 0; idx < num_icc_marker; idx++) { + icc_data_len = marker_list[idx]->data_length - JPEG_OVERHEAD_LEN; + FXSYS_memcpy32(icc_data_ptr, marker_list[idx]->data + JPEG_OVERHEAD_LEN, icc_data_len); + icc_data_ptr += icc_data_len; + } + return TRUE; +} static FX_BOOL _JpegEmbedIccProfile(j_compress_ptr cinfo, FX_LPCBYTE icc_buf_ptr, FX_DWORD icc_length) { if(icc_buf_ptr == NULL || icc_length == 0) { @@ -207,6 +269,17 @@ static void _JpegEncode(const CFX_DIBSource* pSource, FX_LPBYTE& dest_buf, FX_ST } dest_size = dest_buf_length - (FX_STRSIZE)dest.free_in_buffer; } +static void _JpegLoadAttribute(struct jpeg_decompress_struct* pInfo, CFX_DIBAttribute* pAttribute) +{ + if (pInfo == NULL || pAttribute == NULL) { + return; + } + if (pAttribute) { + pAttribute->m_nXDPI = pInfo->X_density; + pAttribute->m_nYDPI = pInfo->Y_density; + pAttribute->m_wDPIUnit = pInfo->density_unit; + } +} static FX_BOOL _JpegLoadInfo(FX_LPCBYTE src_buf, FX_DWORD src_size, int& width, int& height, int& num_components, int& bits_per_components, FX_BOOL& color_transform, FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length) @@ -613,10 +686,10 @@ void CCodec_JpegModule::Input(void* pContext, const unsigned char* src_buf, FX_D p->m_SrcMgr.next_input_byte = src_buf; p->m_SrcMgr.bytes_in_buffer = src_size; } -int CCodec_JpegModule::ReadHeader(void* pContext, int* width, int* height, int* nComps) +int CCodec_JpegModule::ReadHeader(void* pContext, int* width, int* height, int* nComps, CFX_DIBAttribute* pAttribute) { if (m_pExtProvider) { - return m_pExtProvider->ReadHeader(pContext, width, height, nComps); + return m_pExtProvider->ReadHeader(pContext, width, height, nComps, pAttribute); } FXJPEG_Context* p = (FXJPEG_Context*)pContext; if (setjmp(p->m_JumpMark) == -1) { @@ -632,6 +705,7 @@ int CCodec_JpegModule::ReadHeader(void* pContext, int* width, int* height, int* *width = p->m_Info.image_width; *height = p->m_Info.image_height; *nComps = p->m_Info.num_components; + _JpegLoadAttribute(&p->m_Info, pAttribute); return 0; } FX_BOOL CCodec_JpegModule::StartScanline(void* pContext, int down_scale) diff --git a/core/src/fxcodec/codec/fx_codec_png.cpp b/core/src/fxcodec/codec/fx_codec_png.cpp new file mode 100644 index 0000000000..0ddae7a7cd --- /dev/null +++ b/core/src/fxcodec/codec/fx_codec_png.cpp @@ -0,0 +1,245 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../../../include/fxcodec/fx_codec.h" +#include "../../../include/fxge/fx_dib.h" +#include "codec_int.h" +extern "C" { +#undef FAR +#include "../fx_lpng/include/fx_png.h" +} +static void _png_error_data(png_structp png_ptr, png_const_charp error_msg) +{ + if(png_get_error_ptr(png_ptr)) { + FXSYS_strncpy((char*)png_get_error_ptr(png_ptr), error_msg, PNG_ERROR_SIZE - 1); + } + longjmp(png_jmpbuf(png_ptr), 1); +} +static void _png_warning_data(png_structp png_ptr, png_const_charp error_msg) +{ +} +static void _png_load_bmp_attribute(png_structp png_ptr, png_infop info_ptr, CFX_DIBAttribute* pAttribute) +{ + if (pAttribute) { +#if defined(PNG_pHYs_SUPPORTED) + pAttribute->m_nXDPI = png_get_x_pixels_per_meter(png_ptr, info_ptr); + pAttribute->m_nYDPI = png_get_y_pixels_per_meter(png_ptr, info_ptr); + png_uint_32 res_x, res_y; + int unit_type; + png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type); + switch (unit_type) { + case PNG_RESOLUTION_METER: + pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_METER; + break; + default: + pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_NONE; + } +#endif +#if defined(PNG_iCCP_SUPPORTED) + png_charp icc_name; + png_bytep icc_profile; + png_uint_32 icc_proflen; + int compress_type; + png_get_iCCP(png_ptr, info_ptr, &icc_name, &compress_type, &icc_profile, &icc_proflen); +#endif + int bTime = 0; +#if defined(PNG_tIME_SUPPORTED) + png_timep t = NULL; + png_get_tIME(png_ptr, info_ptr, &t); + if (t) { + FXSYS_memset32(pAttribute->m_strTime, 0, 20); + FXSYS_sprintf((FX_LPSTR)pAttribute->m_strTime, "%4d:%2d:%2d %2d:%2d:%2d", t->year, t->month, t->day, t->hour, t->minute, t->second); + bTime = 1; + } +#endif +#if defined(PNG_TEXT_SUPPORTED) + int i; + FX_DWORD len; + FX_LPCSTR buf; + int num_text; + png_textp text = NULL; + png_get_text(png_ptr, info_ptr, &text, &num_text); + for (i = 0; i < num_text; i++) { + len = (FX_DWORD)FXSYS_strlen(text[i].key); + buf = "Time"; + if (!FXSYS_memcmp32(buf, text[i].key, FX_MIN(len, FXSYS_strlen(buf)))) { + if (!bTime) { + FXSYS_memset32(pAttribute->m_strTime, 0, 20); + FXSYS_memcpy32(pAttribute->m_strTime, text[i].text, text[i].text_length); + } + } else { + buf = "Author"; + if (!FXSYS_memcmp32(buf, text[i].key, FX_MIN(len, FXSYS_strlen(buf)))) { + pAttribute->m_strAuthor.Empty(); + pAttribute->m_strAuthor.Load((FX_LPBYTE)text[i].text, (FX_STRSIZE)text[i].text_length); + } + } + } +#endif + } +} +struct FXPNG_Context { + png_structp png_ptr; + png_infop info_ptr; + void* parent_ptr; + void* child_ptr; + + void* (*m_AllocFunc)(unsigned int); + void (*m_FreeFunc)(void*); +}; +extern "C" { + static void* _png_alloc_func(unsigned int size) + { + return FX_Alloc(char, size); + } + static void _png_free_func(void* p) + { + if(p != NULL) { + FX_Free(p); + } + } +}; +static void _png_get_header_func(png_structp png_ptr, png_infop info_ptr) +{ + FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr); + if(p == NULL) { + return; + } + CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr; + if(pModule == NULL) { + return; + } + png_uint_32 width = 0, height = 0; + int bpc = 0, color_type = 0 , color_type1 = 0, pass = 0; + double gamma = 1.0; + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bpc, &color_type, NULL, NULL, NULL); + color_type1 = color_type; + if(bpc > 8) { + png_set_strip_16(png_ptr); + } else if(bpc < 8) { + png_set_expand_gray_1_2_4_to_8(png_ptr); + } + bpc = 8; + if(color_type == PNG_COLOR_TYPE_PALETTE) { + png_set_palette_to_rgb(png_ptr); + } + pass = png_set_interlace_handling(png_ptr); + if(!pModule->ReadHeaderCallback(p->child_ptr, width, height, bpc, pass, &color_type, &gamma)) { + png_error(p->png_ptr, "Read Header Callback Error"); + } + int intent; + if (png_get_sRGB(png_ptr, info_ptr, &intent)) { + png_set_gamma(png_ptr, gamma, 0.45455); + } else { + double image_gamma; + if(png_get_gAMA(png_ptr, info_ptr, &image_gamma)) { + png_set_gamma(png_ptr, gamma, image_gamma); + } else { + png_set_gamma(png_ptr, gamma, 0.45455); + } + } + switch(color_type) { + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_GRAY_ALPHA: { + if(color_type1 & PNG_COLOR_MASK_COLOR) { + png_set_rgb_to_gray(png_ptr, 1, 0.299, 0.587); + } + } + break; + case PNG_COLOR_TYPE_PALETTE: + if(color_type1 != PNG_COLOR_TYPE_PALETTE) { + png_error(p->png_ptr, "Not Support Output Palette Now"); + } + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + if(!(color_type1 & PNG_COLOR_MASK_COLOR)) { + png_set_gray_to_rgb(png_ptr); + } + png_set_bgr(png_ptr); + break; + } + if(!(color_type & PNG_COLOR_MASK_ALPHA)) { + png_set_strip_alpha(png_ptr); + } + if(color_type & PNG_COLOR_MASK_ALPHA && !(color_type1 & PNG_COLOR_MASK_ALPHA)) { + png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + } + png_read_update_info(png_ptr, info_ptr); +} +static void _png_get_end_func(png_structp png_ptr, png_infop info_ptr) {} +static void _png_get_row_func(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass) +{ + FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr); + if(p == NULL) { + return; + } + CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr; + FX_LPBYTE src_buf = NULL; + if(!pModule->AskScanlineBufCallback(p->child_ptr, row_num, src_buf)) { + png_error(png_ptr, "Ask Scanline buffer Callback Error"); + } + if(src_buf != NULL) { + png_progressive_combine_row(png_ptr, src_buf, new_row); + } + pModule->FillScanlineBufCompletedCallback(p->child_ptr, pass, row_num); +} +void* CCodec_PngModule::Start(void* pModule) +{ + FXPNG_Context* p = (FXPNG_Context*)FX_Alloc(FX_BYTE, sizeof(FXPNG_Context)); + if(p == NULL) { + return NULL; + } + p->m_AllocFunc = _png_alloc_func; + p->m_FreeFunc = _png_free_func; + p->png_ptr = NULL; + p->info_ptr = NULL; + p->parent_ptr = (void*)this; + p->child_ptr = pModule; + p->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (p->png_ptr == NULL) { + FX_Free(p); + return NULL; + } + p->info_ptr = png_create_info_struct(p->png_ptr); + if (p->info_ptr == NULL) { + png_destroy_read_struct(&(p->png_ptr), (png_infopp)NULL, (png_infopp)NULL); + FX_Free(p); + return NULL; + } + if (setjmp(png_jmpbuf(p->png_ptr))) { + if(p != NULL) { + png_destroy_read_struct(&(p->png_ptr), &(p->info_ptr), (png_infopp)NULL); + FX_Free(p); + } + return NULL; + } + png_set_progressive_read_fn(p->png_ptr, p, + _png_get_header_func, + _png_get_row_func, + _png_get_end_func); + png_set_error_fn(p->png_ptr, m_szLastError, (png_error_ptr)_png_error_data, (png_error_ptr)_png_warning_data); + return p; +} +void CCodec_PngModule::Finish(void* pContext) +{ + FXPNG_Context* p = (FXPNG_Context*)pContext; + if(p != NULL) { + png_destroy_read_struct(&(p->png_ptr), &(p->info_ptr), (png_infopp)NULL); + p->m_FreeFunc(p); + } +} +FX_BOOL CCodec_PngModule::Input(void* pContext, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_DIBAttribute* pAttribute) +{ + FXPNG_Context* p = (FXPNG_Context*)pContext; + if(setjmp(png_jmpbuf(p->png_ptr))) { + if (pAttribute && 0 == FXSYS_strcmp(m_szLastError, "Read Header Callback Error")) { + _png_load_bmp_attribute(p->png_ptr, p->info_ptr, pAttribute); + } + return FALSE; + } + png_process_data(p->png_ptr, p->info_ptr, (FX_LPBYTE)src_buf, src_size); + return TRUE; +} diff --git a/core/src/fxcodec/codec/fx_codec_progress.cpp b/core/src/fxcodec/codec/fx_codec_progress.cpp new file mode 100644 index 0000000000..542ac681e6 --- /dev/null +++ b/core/src/fxcodec/codec/fx_codec_progress.cpp @@ -0,0 +1,2263 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../../../include/fxge/fx_dib.h" +#include "../../../include/fxcodec/fx_codec.h" +#include "fx_codec_progress.h" +void CFXCODEC_WeightTable::Calc(int dest_len, int dest_min, int dest_max, int src_len, int src_min, int src_max, FX_BOOL bInterpol) +{ + if (m_pWeightTables) { + FX_Free(m_pWeightTables); + } + double scale, base; + scale = FXSYS_Div((FX_FLOAT)(src_len), (FX_FLOAT)(dest_len)); + if (dest_len < 0) { + base = (FX_FLOAT)(src_len); + } else { + base = 0.0f; + } + m_ItemSize = (int)(sizeof(int) * 2 + sizeof(int) * (FXSYS_ceil(FXSYS_fabs((FX_FLOAT)scale)) + 1)); + m_DestMin = dest_min; + m_pWeightTables = FX_Alloc(FX_BYTE, (dest_max - dest_min) * m_ItemSize + 4); + if(m_pWeightTables == NULL) { + return; + } + if (FXSYS_fabs((FX_FLOAT)scale) < 1.0f) { + for (int dest_pixel = dest_min; dest_pixel < dest_max; dest_pixel ++) { + PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel); + double src_pos = dest_pixel * scale + scale / 2 + base; + if (bInterpol) { + pixel_weights.m_SrcStart = (int)FXSYS_floor((FX_FLOAT)src_pos - 1.0f / 2); + pixel_weights.m_SrcEnd = (int)FXSYS_floor((FX_FLOAT)src_pos + 1.0f / 2); + if (pixel_weights.m_SrcStart < src_min) { + pixel_weights.m_SrcStart = src_min; + } + if (pixel_weights.m_SrcEnd >= src_max) { + pixel_weights.m_SrcEnd = src_max - 1; + } + if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) { + pixel_weights.m_Weights[0] = 65536; + } else { + pixel_weights.m_Weights[1] = FXSYS_round((FX_FLOAT)(src_pos - pixel_weights.m_SrcStart - 1.0f / 2) * 65536); + pixel_weights.m_Weights[0] = 65536 - pixel_weights.m_Weights[1]; + } + } else { + pixel_weights.m_SrcStart = pixel_weights.m_SrcEnd = (int)FXSYS_floor((FX_FLOAT)src_pos); + pixel_weights.m_Weights[0] = 65536; + } + } + return; + } + for (int dest_pixel = dest_min; dest_pixel < dest_max; dest_pixel ++) { + PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel); + double src_start = dest_pixel * scale + base; + double src_end = src_start + scale; + int start_i, end_i; + if (src_start < src_end) { + start_i = (int)FXSYS_floor((FX_FLOAT)src_start); + end_i = (int)FXSYS_ceil((FX_FLOAT)src_end); + } else { + start_i = (int)FXSYS_floor((FX_FLOAT)src_end); + end_i = (int)FXSYS_ceil((FX_FLOAT)src_start); + } + if (start_i < src_min) { + start_i = src_min; + } + if (end_i >= src_max) { + end_i = src_max - 1; + } + if (start_i > end_i) { + pixel_weights.m_SrcStart = start_i; + pixel_weights.m_SrcEnd = start_i; + continue; + } + pixel_weights.m_SrcStart = start_i; + pixel_weights.m_SrcEnd = end_i; + for (int j = start_i; j <= end_i; j ++) { + double dest_start = FXSYS_Div((FX_FLOAT)(j) - base, scale); + double dest_end = FXSYS_Div((FX_FLOAT)(j + 1) - base, scale); + if (dest_start > dest_end) { + double temp = dest_start; + dest_start = dest_end; + dest_end = temp; + } + double area_start = dest_start > (FX_FLOAT)(dest_pixel) ? dest_start : (FX_FLOAT)(dest_pixel); + double area_end = dest_end > (FX_FLOAT)(dest_pixel + 1) ? (FX_FLOAT)(dest_pixel + 1) : dest_end; + double weight = area_start >= area_end ? 0.0f : area_end - area_start; + if (weight == 0 && j == end_i) { + pixel_weights.m_SrcEnd --; + break; + } + pixel_weights.m_Weights[j - start_i] = FXSYS_round((FX_FLOAT)(weight * 65536)); + } + } +} +void CFXCODEC_HorzTable::Calc(int dest_len, int src_len, FX_BOOL bInterpol) +{ + if (m_pWeightTables) { + FX_Free(m_pWeightTables); + } + double scale = (double)dest_len / (double)src_len; + m_ItemSize = sizeof(int) * 4; + int size = dest_len * m_ItemSize + 4; + m_pWeightTables = FX_Alloc(FX_BYTE, size); + if(m_pWeightTables == NULL) { + return; + } + FXSYS_memset32(m_pWeightTables, 0, size); + if(scale > 1) { + int pre_des_col = 0; + for (int src_col = 0; src_col < src_len; src_col++) { + double des_col_f = src_col * scale; + int des_col = FXSYS_round((FX_FLOAT)des_col_f); + PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + des_col * m_ItemSize); + pWeight->m_SrcStart = pWeight->m_SrcEnd = src_col; + pWeight->m_Weights[0] = 65536; + pWeight->m_Weights[1] = 0; + if(src_col == src_len - 1 && des_col < dest_len - 1) { + for (int des_col_index = pre_des_col + 1; des_col_index < dest_len; des_col_index++) { + pWeight = (PixelWeight*)(m_pWeightTables + des_col_index * m_ItemSize); + pWeight->m_SrcStart = pWeight->m_SrcEnd = src_col; + pWeight->m_Weights[0] = 65536; + pWeight->m_Weights[1] = 0; + } + return; + } + int des_col_len = des_col - pre_des_col; + for (int des_col_index = pre_des_col + 1; des_col_index < des_col; des_col_index++) { + pWeight = (PixelWeight*)(m_pWeightTables + des_col_index * m_ItemSize); + pWeight->m_SrcStart = src_col - 1; + pWeight->m_SrcEnd = src_col; + pWeight->m_Weights[0] = bInterpol ? FXSYS_round((FX_FLOAT) + ( + ((FX_FLOAT)des_col - (FX_FLOAT)des_col_index) + / (FX_FLOAT)des_col_len * 65536 + ) + ) : 65536; + pWeight->m_Weights[1] = 65536 - pWeight->m_Weights[0]; + } + pre_des_col = des_col; + } + return; + } + for (int des_col = 0; des_col < dest_len; des_col++) { + double src_col_f = des_col / scale; + int src_col = FXSYS_round((FX_FLOAT)src_col_f); + PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + des_col * m_ItemSize); + pWeight->m_SrcStart = pWeight->m_SrcEnd = src_col; + pWeight->m_Weights[0] = 65536; + pWeight->m_Weights[1] = 0; + } +} +void CFXCODEC_VertTable::Calc(int dest_len, int src_len) +{ + if (m_pWeightTables) { + FX_Free(m_pWeightTables); + } + double scale = (double)dest_len / (double)src_len; + m_ItemSize = sizeof(int) * 4; + int size = dest_len * m_ItemSize + 4; + m_pWeightTables = FX_Alloc(FX_BYTE, size); + if(m_pWeightTables == NULL) { + return; + } + FXSYS_memset32(m_pWeightTables, 0, size); + if(scale > 1) { + double step = 0.0; + int src_row = 0; + while ( step < (double)dest_len ) { + int start_step = (int)step; + step = scale * (++src_row); + int end_step = (int)step; + if(end_step >= dest_len) { + end_step = dest_len; + for (int des_row = start_step; des_row < end_step; des_row++) { + PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + des_row * m_ItemSize); + pWeight->m_SrcStart = start_step; + pWeight->m_SrcEnd = start_step; + pWeight->m_Weights[0] = 65536; + pWeight->m_Weights[1] = 0; + } + return; + } + int length = end_step - start_step; + { + PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + start_step * m_ItemSize); + pWeight->m_SrcStart = start_step; + pWeight->m_SrcEnd = start_step; + pWeight->m_Weights[0] = 65536; + pWeight->m_Weights[1] = 0; + } + for (int des_row = start_step + 1; des_row < end_step; des_row++) { + PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + des_row * m_ItemSize); + pWeight->m_SrcStart = start_step; + pWeight->m_SrcEnd = end_step; + pWeight->m_Weights[0] = FXSYS_round((FX_FLOAT)(end_step - des_row) / (FX_FLOAT)length * 65536); + pWeight->m_Weights[1] = 65536 - pWeight->m_Weights[0]; + } + } + } else { + for (int des_row = 0; des_row < dest_len; des_row++) { + PixelWeight* pWeight = (PixelWeight*)(m_pWeightTables + des_row * m_ItemSize); + pWeight->m_SrcStart = des_row; + pWeight->m_SrcEnd = des_row; + pWeight->m_Weights[0] = 65536; + pWeight->m_Weights[1] = 0; + } + } +} +CCodec_ProgressiveDecoder::CCodec_ProgressiveDecoder(CCodec_ModuleMgr* pCodecMgr) +{ + m_pFile = NULL; + m_pJpegContext = NULL; + m_pPngContext = NULL; + m_pGifContext = NULL; + m_pBmpContext = NULL; + m_pTiffContext = NULL; + m_pCodecMgr = NULL; + m_pSrcBuf = NULL; + m_pDecodeBuf = NULL; + m_pDeviceBitmap = NULL; + m_pSrcPalette = NULL; + m_pCodecMgr = pCodecMgr; + m_offSet = 0; + m_SrcSize = 0; + m_ScanlineSize = 0; + m_SrcWidth = m_SrcHeight = 0; + m_SrcComponents = 0; + m_SrcBPC = 0; + m_SrcPassNumber = 0; + m_clipBox = FX_RECT(0, 0, 0, 0); + m_imagType = FXCODEC_IMAGE_UNKNOWN; + m_status = FXCODEC_STATUS_DECODE_FINISH; + m_TransMethod = -1; + m_SrcRow = 0; + m_SrcFormat = FXCodec_Invalid; + m_bInterpol = TRUE; + m_FrameNumber = 0; + m_FrameCur = 0; + m_SrcPaletteNumber = 0; + m_GifPltNumber = 0; + m_GifBgIndex = 0; + m_pGifPalette = NULL; + m_GifTransIndex = -1; + m_GifFrameRect = FX_RECT(0, 0, 0, 0); + m_BmpIsTopBottom = FALSE; +} +CCodec_ProgressiveDecoder::~CCodec_ProgressiveDecoder() +{ + m_pFile = NULL; + if(m_pJpegContext != NULL) { + m_pCodecMgr->GetJpegModule()->Finish(m_pJpegContext); + } + if(m_pPngContext != NULL) { + m_pCodecMgr->GetPngModule()->Finish(m_pPngContext); + } + if(m_pGifContext != NULL) { + m_pCodecMgr->GetGifModule()->Finish(m_pGifContext); + } + if(m_pBmpContext != NULL) { + m_pCodecMgr->GetBmpModule()->Finish(m_pBmpContext); + } + if(m_pTiffContext != NULL) { + m_pCodecMgr->GetTiffModule()->DestroyDecoder(m_pTiffContext); + } + if(m_pSrcBuf != NULL) { + FX_Free(m_pSrcBuf); + } + if(m_pDecodeBuf != NULL) { + FX_Free(m_pDecodeBuf); + } + if(m_pSrcPalette != NULL) { + FX_Free(m_pSrcPalette); + } +} +FX_BOOL CCodec_ProgressiveDecoder::JpegReadMoreData(ICodec_JpegModule* pJpegModule, FXCODEC_STATUS& err_status) +{ + FX_DWORD dwSize = (FX_DWORD)m_pFile->GetSize(); + if (dwSize <= m_offSet) { + return FALSE; + } + dwSize = dwSize - m_offSet; + FX_DWORD dwAvail = pJpegModule->GetAvailInput(m_pJpegContext, NULL); + if (dwAvail == m_SrcSize) { + if (dwSize > FXCODEC_BLOCK_SIZE) { + dwSize = FXCODEC_BLOCK_SIZE; + } + m_SrcSize = (dwSize + dwAvail + FXCODEC_BLOCK_SIZE - 1) / FXCODEC_BLOCK_SIZE * FXCODEC_BLOCK_SIZE; + m_pSrcBuf = FX_Realloc(FX_BYTE, m_pSrcBuf, m_SrcSize); + if (!m_pSrcBuf) { + err_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + } else { + FX_DWORD dwConsume = m_SrcSize - dwAvail; + if (dwAvail) { + FXSYS_memcpy32(m_pSrcBuf, m_pSrcBuf + dwConsume, dwAvail); + } + if (dwSize > dwConsume) { + dwSize = dwConsume; + } + } + if (!m_pFile->ReadBlock(m_pSrcBuf + dwAvail, m_offSet, dwSize)) { + err_status = FXCODEC_STATUS_ERR_READ; + return FALSE; + } + m_offSet += dwSize; + pJpegModule->Input(m_pJpegContext, m_pSrcBuf, dwSize + dwAvail); + return TRUE; +} +FX_BOOL CCodec_ProgressiveDecoder::PngReadHeaderFunc(void* pModule, int width, int height, int bpc, int pass, int* color_type, double* gamma) +{ + CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule; + if(pCodec->m_pDeviceBitmap == NULL) { + pCodec->m_SrcWidth = width; + pCodec->m_SrcHeight = height; + pCodec->m_SrcBPC = bpc; + pCodec->m_SrcPassNumber = pass; + pCodec->m_SrcComponents = *color_type == 0 ? 1 : + *color_type == 2 ? 3 : + *color_type == 3 ? 4 : + *color_type == 4 ? 2 : + *color_type == 6 ? 4 : 0; + pCodec->m_clipBox = FX_RECT(0, 0, width, height); + return FALSE; + } + FXDIB_Format format = pCodec->m_pDeviceBitmap->GetFormat(); + switch(format) { + case FXDIB_1bppMask: + case FXDIB_1bppRgb: + ASSERT(FALSE); + return FALSE; + case FXDIB_8bppMask: + case FXDIB_8bppRgb: + *color_type = 0; + break; + case FXDIB_Rgb: + *color_type = 2; + break; + case FXDIB_Rgb32: + case FXDIB_Argb: + *color_type = 6; + break; + default: + ASSERT(FALSE); + return FALSE; + } + *gamma = FXCODEC_PNG_GAMMA; + return TRUE; +} +FX_BOOL CCodec_ProgressiveDecoder::PngAskScanlineBufFunc(void* pModule, int line, FX_LPBYTE& src_buf) +{ + CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule; + CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap; + ASSERT(pDIBitmap != NULL); + if(pDIBitmap == NULL) { + return FALSE; + } + if(line >= pCodec->m_clipBox.top && line < pCodec->m_clipBox.bottom) { + double scale_y = (double)pCodec->m_sizeY / (double)pCodec->m_clipBox.Height(); + FX_INT32 row = (FX_INT32)((line - pCodec->m_clipBox.top) * scale_y) + pCodec->m_startY; + FX_LPBYTE src_scan = (FX_LPBYTE)pDIBitmap->GetScanline(row); + FX_LPBYTE des_scan = pCodec->m_pDecodeBuf; + src_buf = pCodec->m_pDecodeBuf; + FX_INT32 src_Bpp = pDIBitmap->GetBPP() >> 3; + FX_INT32 des_Bpp = (pCodec->m_SrcFormat & 0xff) >> 3; + FX_INT32 src_left = pCodec->m_startX; + FX_INT32 des_left = pCodec->m_clipBox.left; + src_scan += src_left * src_Bpp; + des_scan += des_left * des_Bpp; + for (FX_INT32 src_col = 0; src_col < pCodec->m_sizeX; src_col++) { + PixelWeight* pPixelWeights = pCodec->m_WeightHorzOO.GetPixelWeight(src_col); + if(pPixelWeights->m_SrcStart != pPixelWeights->m_SrcEnd) { + continue; + } + switch(pDIBitmap->GetFormat()) { + case FXDIB_1bppMask: + case FXDIB_1bppRgb: + ASSERT(FALSE); + return FALSE; + case FXDIB_8bppMask: + case FXDIB_8bppRgb: { + if(pDIBitmap->GetPalette() != NULL) { + return FALSE; + } + FX_DWORD des_g = 0; + des_g += pPixelWeights->m_Weights[0] * src_scan[src_col]; + des_scan[pPixelWeights->m_SrcStart] = (FX_BYTE)(des_g >> 16); + } + break; + case FXDIB_Rgb: + case FXDIB_Rgb32: { + FX_DWORD des_b = 0, des_g = 0, des_r = 0; + FX_LPCBYTE p = src_scan + src_col * src_Bpp; + des_b += pPixelWeights->m_Weights[0] * (*p++); + des_g += pPixelWeights->m_Weights[0] * (*p++); + des_r += pPixelWeights->m_Weights[0] * (*p); + FX_LPBYTE pDes = &des_scan[pPixelWeights->m_SrcStart * des_Bpp]; + *pDes++ = (FX_BYTE)((des_b) >> 16); + *pDes++ = (FX_BYTE)((des_g) >> 16); + *pDes = (FX_BYTE)((des_r) >> 16); + } + break; + case FXDIB_Argb: { + FX_DWORD des_r = 0, des_g = 0, des_b = 0; + FX_LPCBYTE p = src_scan + src_col * src_Bpp; + des_b += pPixelWeights->m_Weights[0] * (*p++); + des_g += pPixelWeights->m_Weights[0] * (*p++); + des_r += pPixelWeights->m_Weights[0] * (*p++); + FX_LPBYTE pDes = &des_scan[pPixelWeights->m_SrcStart * des_Bpp]; + *pDes++ = (FX_BYTE)((des_b) >> 16); + *pDes++ = (FX_BYTE)((des_g) >> 16); + *pDes++ = (FX_BYTE)((des_r) >> 16); + *pDes = *p; + } + break; + default: + return FALSE; + } + } + } + return TRUE; +} +void CCodec_ProgressiveDecoder::PngOneOneMapResampleHorz(CFX_DIBitmap* pDeviceBitmap, FX_INT32 des_line, FX_LPBYTE src_scan, FXCodec_Format src_format) +{ + FX_LPBYTE des_scan = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_line); + FX_INT32 src_Bpp = (m_SrcFormat & 0xff) >> 3; + FX_INT32 des_Bpp = pDeviceBitmap->GetBPP() >> 3; + FX_INT32 src_left = m_clipBox.left; + FX_INT32 des_left = m_startX; + src_scan += src_left * src_Bpp; + des_scan += des_left * des_Bpp; + for (FX_INT32 des_col = 0; des_col < m_sizeX; des_col++) { + PixelWeight* pPixelWeights = m_WeightHorzOO.GetPixelWeight(des_col); + switch(pDeviceBitmap->GetFormat()) { + case FXDIB_1bppMask: + case FXDIB_1bppRgb: + ASSERT(FALSE); + return; + case FXDIB_8bppMask: + case FXDIB_8bppRgb: { + if(pDeviceBitmap->GetPalette() != NULL) { + return; + } + FX_DWORD des_g = 0; + des_g += pPixelWeights->m_Weights[0] * src_scan[pPixelWeights->m_SrcStart]; + des_g += pPixelWeights->m_Weights[1] * src_scan[pPixelWeights->m_SrcEnd]; + *des_scan++ = (FX_BYTE)(des_g >> 16); + } + break; + case FXDIB_Rgb: + case FXDIB_Rgb32: { + FX_DWORD des_b = 0, des_g = 0, des_r = 0; + FX_LPCBYTE p = src_scan; + p = src_scan + pPixelWeights->m_SrcStart * src_Bpp; + des_b += pPixelWeights->m_Weights[0] * (*p++); + des_g += pPixelWeights->m_Weights[0] * (*p++); + des_r += pPixelWeights->m_Weights[0] * (*p); + p = src_scan + pPixelWeights->m_SrcEnd * src_Bpp; + des_b += pPixelWeights->m_Weights[1] * (*p++); + des_g += pPixelWeights->m_Weights[1] * (*p++); + des_r += pPixelWeights->m_Weights[1] * (*p); + *des_scan++ = (FX_BYTE)((des_b) >> 16); + *des_scan++ = (FX_BYTE)((des_g) >> 16); + *des_scan++ = (FX_BYTE)((des_r) >> 16); + des_scan += des_Bpp - 3; + } + break; + case FXDIB_Argb: { + FX_DWORD des_a = 0, des_b = 0, des_g = 0, des_r = 0; + FX_LPCBYTE p = src_scan; + p = src_scan + pPixelWeights->m_SrcStart * src_Bpp; + des_b += pPixelWeights->m_Weights[0] * (*p++); + des_g += pPixelWeights->m_Weights[0] * (*p++); + des_r += pPixelWeights->m_Weights[0] * (*p++); + des_a += pPixelWeights->m_Weights[0] * (*p); + p = src_scan + pPixelWeights->m_SrcEnd * src_Bpp; + des_b += pPixelWeights->m_Weights[1] * (*p++); + des_g += pPixelWeights->m_Weights[1] * (*p++); + des_r += pPixelWeights->m_Weights[1] * (*p++); + des_a += pPixelWeights->m_Weights[1] * (*p); + *des_scan++ = (FX_BYTE)((des_b) >> 16); + *des_scan++ = (FX_BYTE)((des_g) >> 16); + *des_scan++ = (FX_BYTE)((des_r) >> 16); + *des_scan++ = (FX_BYTE)((des_a) >> 16); + } + break; + default: + return; + } + } +} +void CCodec_ProgressiveDecoder::PngFillScanlineBufCompletedFunc(void* pModule, int pass, int line) +{ + CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule; + CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap; + ASSERT(pDIBitmap != NULL); + int src_top = pCodec->m_clipBox.top; + int src_bottom = pCodec->m_clipBox.bottom; + int des_top = pCodec->m_startY; + int src_hei = pCodec->m_clipBox.Height(); + int des_hei = pCodec->m_sizeY; + if(line >= src_top && line < src_bottom) { + double scale_y = (double)des_hei / (double)src_hei; + int src_row = line - src_top; + int des_row = (int)(src_row * scale_y) + des_top; + if(des_row >= des_top + des_hei) { + return; + } + pCodec->PngOneOneMapResampleHorz(pDIBitmap, des_row, pCodec->m_pDecodeBuf, pCodec->m_SrcFormat); + if(pCodec->m_SrcPassNumber == 1 && scale_y > 1.0) { + pCodec->ResampleVert(pDIBitmap, scale_y, des_row); + return; + } + if(pass == 6 && scale_y > 1.0) { + pCodec->ResampleVert(pDIBitmap, scale_y, des_row); + } + } +} +FX_BOOL CCodec_ProgressiveDecoder::GifReadMoreData(ICodec_GifModule* pGifModule, FXCODEC_STATUS& err_status) +{ + FX_DWORD dwSize = (FX_DWORD)m_pFile->GetSize(); + if (dwSize <= m_offSet) { + return FALSE; + } + dwSize = dwSize - m_offSet; + FX_DWORD dwAvail = pGifModule->GetAvailInput(m_pGifContext, NULL); + if (dwAvail == m_SrcSize) { + if (dwSize > FXCODEC_BLOCK_SIZE) { + dwSize = FXCODEC_BLOCK_SIZE; + } + m_SrcSize = (dwSize + dwAvail + FXCODEC_BLOCK_SIZE - 1) / FXCODEC_BLOCK_SIZE * FXCODEC_BLOCK_SIZE; + m_pSrcBuf = FX_Realloc(FX_BYTE, m_pSrcBuf, m_SrcSize); + if (!m_pSrcBuf) { + err_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + } else { + FX_DWORD dwConsume = m_SrcSize - dwAvail; + if (dwAvail) { + FXSYS_memcpy32(m_pSrcBuf, m_pSrcBuf + dwConsume, dwAvail); + } + if (dwSize > dwConsume) { + dwSize = dwConsume; + } + } + if (!m_pFile->ReadBlock(m_pSrcBuf + dwAvail, m_offSet, dwSize)) { + err_status = FXCODEC_STATUS_ERR_READ; + return FALSE; + } + m_offSet += dwSize; + pGifModule->Input(m_pGifContext, m_pSrcBuf, dwSize + dwAvail); + return TRUE; +} +void CCodec_ProgressiveDecoder::GifRecordCurrentPositionCallback(void* pModule, FX_DWORD& cur_pos) +{ + CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule; + FX_DWORD remain_size = pCodec->m_pCodecMgr->GetGifModule()->GetAvailInput(pCodec->m_pGifContext); + cur_pos = pCodec->m_offSet - remain_size; +} +FX_LPBYTE CCodec_ProgressiveDecoder::GifAskLocalPaletteBufCallback(void* pModule, FX_INT32 frame_num, FX_INT32 pal_size) +{ + return FX_Alloc(FX_BYTE, pal_size); +} +FX_BOOL CCodec_ProgressiveDecoder::GifInputRecordPositionBufCallback(void* pModule, FX_DWORD rcd_pos, const FX_RECT& img_rc, + FX_INT32 pal_num, void* pal_ptr, + FX_INT32 delay_time, FX_BOOL user_input, + FX_INT32 trans_index, FX_INT32 disposal_method, FX_BOOL interlace) +{ + CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule; + pCodec->m_offSet = rcd_pos; + FXCODEC_STATUS error_status = FXCODEC_STATUS_ERROR; + if(!pCodec->GifReadMoreData(pCodec->m_pCodecMgr->GetGifModule(), error_status)) { + return FALSE; + } + FX_LPBYTE pPalette = NULL; + if(pal_num != 0 && pal_ptr) { + pPalette = (FX_LPBYTE)pal_ptr; + } else { + pal_num = pCodec->m_GifPltNumber; + pPalette = pCodec->m_pGifPalette; + } + if(pCodec->m_pSrcPalette == NULL) { + pCodec->m_pSrcPalette = FX_Alloc(FX_ARGB, pal_num); + } else if(pal_num > pCodec->m_SrcPaletteNumber) { + pCodec->m_pSrcPalette = FX_Realloc(FX_ARGB, pCodec->m_pSrcPalette, pal_num); + } + if(pCodec->m_pSrcPalette == NULL) { + return FALSE; + } + pCodec->m_SrcPaletteNumber = pal_num; + for (int i = 0; i < pal_num; i++) { + register FX_DWORD j = i * 3; + pCodec->m_pSrcPalette[i] = + ArgbEncode(0xff, pPalette[j], pPalette[j + 1], pPalette[j + 2]); + } + pCodec->m_GifTransIndex = trans_index; + pCodec->m_GifFrameRect = img_rc; + pCodec->m_SrcPassNumber = interlace ? 4 : 1; + FX_INT32 pal_index = pCodec->m_GifBgIndex; + CFX_DIBitmap* pDevice = pCodec->m_pDeviceBitmap; + if (trans_index >= pal_num) { + trans_index = -1; + } + if (trans_index != -1) { + pCodec->m_pSrcPalette[trans_index] &= 0x00ffffff; + if (pDevice->HasAlpha()) { + pal_index = trans_index; + } + } + int startX = pCodec->m_startX; + int startY = pCodec->m_startY; + int sizeX = pCodec->m_sizeX; + int sizeY = pCodec->m_sizeY; + int Bpp = pDevice->GetBPP() / 8; + FX_ARGB argb = pCodec->m_pSrcPalette[pal_index]; + for (int row = 0; row < sizeY; row ++) { + FX_LPBYTE pScanline = (FX_LPBYTE)pDevice->GetScanline(row + startY) + startX * Bpp; + switch(pCodec->m_TransMethod) { + case 3: { + FX_BYTE gray = FXRGB2GRAY(FXARGB_R(argb), FXARGB_G(argb), FXARGB_B(argb)); + FXSYS_memset8(pScanline, gray, sizeX); + break; + } + case 8: { + for (int col = 0; col < sizeX; col ++) { + *pScanline++ = FXARGB_B(argb); + *pScanline++ = FXARGB_G(argb); + *pScanline++ = FXARGB_R(argb); + pScanline += Bpp - 3; + } + break; + } + case 12: { + for (int col = 0; col < sizeX; col ++) { + FXARGB_SETDIB(pScanline, argb); + pScanline += 4; + } + break; + } + } + } + return TRUE; +} +void CCodec_ProgressiveDecoder::GifReadScanlineCallback(void* pModule, FX_INT32 row_num, FX_LPBYTE row_buf) +{ + CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule; + CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap; + ASSERT(pDIBitmap != NULL); + FX_INT32 img_width = pCodec->m_GifFrameRect.Width(); + if (!pDIBitmap->HasAlpha()) { + FX_LPBYTE byte_ptr = row_buf; + for (int i = 0; i < img_width; i++ ) { + if(*byte_ptr == pCodec->m_GifTransIndex) { + *byte_ptr = pCodec->m_GifBgIndex; + } + byte_ptr++; + } + } + FX_INT32 pal_index = pCodec->m_GifBgIndex; + if (pCodec->m_GifTransIndex != -1 && pCodec->m_pDeviceBitmap->HasAlpha()) { + pal_index = pCodec->m_GifTransIndex; + } + FXSYS_memset8(pCodec->m_pDecodeBuf, pal_index, pCodec->m_SrcWidth); + FX_BOOL bLastPass = ((row_num % 2) == 1) ? TRUE : FALSE; + FX_INT32 line = row_num + pCodec->m_GifFrameRect.top; + FX_INT32 left = pCodec->m_GifFrameRect.left; + FXSYS_memcpy32(pCodec->m_pDecodeBuf + left, row_buf, img_width); + int src_top = pCodec->m_clipBox.top; + int src_bottom = pCodec->m_clipBox.bottom; + int des_top = pCodec->m_startY; + int src_hei = pCodec->m_clipBox.Height(); + int des_hei = pCodec->m_sizeY; + if(line >= src_top && line < src_bottom) { + double scale_y = (double)des_hei / (double)src_hei; + int src_row = line - src_top; + int des_row = (int)(src_row * scale_y) + des_top; + if(des_row >= des_top + des_hei) { + return; + } + pCodec->ReSampleScanline(pDIBitmap, des_row, pCodec->m_pDecodeBuf, pCodec->m_SrcFormat); + if(scale_y > 1.0 && (!pCodec->m_bInterpol || pCodec->m_SrcPassNumber == 1)) { + pCodec->ResampleVert(pDIBitmap, scale_y, des_row); + return; + } + if(scale_y > 1.0) { + int des_bottom = des_top + pCodec->m_sizeY; + int des_Bpp = pDIBitmap->GetBPP() >> 3; + FX_DWORD des_ScanOffet = pCodec->m_startX * des_Bpp; + if(des_row + (int)scale_y >= des_bottom - 1) { + FX_LPBYTE scan_src = (FX_LPBYTE)pDIBitmap->GetScanline(des_row) + des_ScanOffet; + int cur_row = des_row; + while (++cur_row < des_bottom) { + FX_LPBYTE scan_des = (FX_LPBYTE)pDIBitmap->GetScanline(cur_row) + des_ScanOffet; + FX_DWORD size = pCodec->m_sizeX * des_Bpp; + FXSYS_memcpy32(scan_des, scan_src, size); + } + } + if(bLastPass) { + pCodec->GifDoubleLineResampleVert(pDIBitmap, scale_y, des_row); + } + } + } +} +void CCodec_ProgressiveDecoder::GifDoubleLineResampleVert(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row) +{ + int des_Bpp = pDeviceBitmap->GetBPP() >> 3; + FX_DWORD des_ScanOffet = m_startX * des_Bpp; + int des_top = m_startY; + int des_row_1 = des_row - int(2 * scale_y); + if(des_row_1 < des_top) { + des_row_1 = des_top; + } + for (; des_row_1 < des_row; des_row_1++) { + FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row_1) + des_ScanOffet; + PixelWeight* pWeight = m_WeightVert.GetPixelWeight(des_row_1 - des_top); + FX_LPCBYTE scan_src1 = pDeviceBitmap->GetScanline(pWeight->m_SrcStart + des_top) + des_ScanOffet; + FX_LPCBYTE scan_src2 = pDeviceBitmap->GetScanline(pWeight->m_SrcEnd + des_top) + des_ScanOffet; + for (int des_col = 0; des_col < m_sizeX; des_col++) { + switch(pDeviceBitmap->GetFormat()) { + case FXDIB_Invalid: + case FXDIB_1bppMask: + case FXDIB_1bppRgb: + return; + case FXDIB_8bppMask: + case FXDIB_8bppRgb: { + if(pDeviceBitmap->GetPalette() != NULL) { + return; + } + int des_g = 0; + des_g += pWeight->m_Weights[0] * (*scan_src1++); + des_g += pWeight->m_Weights[1] * (*scan_src2++); + *scan_des++ = (FX_BYTE)(des_g >> 16); + } + break; + case FXDIB_Rgb: + case FXDIB_Rgb32: { + FX_DWORD des_b = 0, des_g = 0, des_r = 0; + des_b += pWeight->m_Weights[0] * (*scan_src1++); + des_g += pWeight->m_Weights[0] * (*scan_src1++); + des_r += pWeight->m_Weights[0] * (*scan_src1++); + scan_src1 += des_Bpp - 3; + des_b += pWeight->m_Weights[1] * (*scan_src2++); + des_g += pWeight->m_Weights[1] * (*scan_src2++); + des_r += pWeight->m_Weights[1] * (*scan_src2++); + scan_src2 += des_Bpp - 3; + *scan_des++ = (FX_BYTE)((des_b) >> 16); + *scan_des++ = (FX_BYTE)((des_g) >> 16); + *scan_des++ = (FX_BYTE)((des_r) >> 16); + scan_des += des_Bpp - 3; + } + break; + case FXDIB_Argb: { + FX_DWORD des_a = 0, des_b = 0, des_g = 0, des_r = 0; + des_b += pWeight->m_Weights[0] * (*scan_src1++); + des_g += pWeight->m_Weights[0] * (*scan_src1++); + des_r += pWeight->m_Weights[0] * (*scan_src1++); + des_a += pWeight->m_Weights[0] * (*scan_src1++); + des_b += pWeight->m_Weights[1] * (*scan_src2++); + des_g += pWeight->m_Weights[1] * (*scan_src2++); + des_r += pWeight->m_Weights[1] * (*scan_src2++); + des_a += pWeight->m_Weights[1] * (*scan_src2++); + *scan_des++ = (FX_BYTE)((des_b) >> 16); + *scan_des++ = (FX_BYTE)((des_g) >> 16); + *scan_des++ = (FX_BYTE)((des_r) >> 16); + *scan_des++ = (FX_BYTE)((des_a) >> 16); + } + break; + default: + return; + } + } + } + int des_bottom = des_top + m_sizeY - 1; + if(des_row + (int)(2 * scale_y) >= des_bottom && des_row + (int)scale_y < des_bottom) { + GifDoubleLineResampleVert(pDeviceBitmap, scale_y, des_row + (int)scale_y); + } +} +FX_BOOL CCodec_ProgressiveDecoder::BmpReadMoreData(ICodec_BmpModule* pBmpModule, FXCODEC_STATUS& err_status) +{ + FX_DWORD dwSize = (FX_DWORD)m_pFile->GetSize(); + if (dwSize <= m_offSet) { + return FALSE; + } + dwSize = dwSize - m_offSet; + FX_DWORD dwAvail = pBmpModule->GetAvailInput(m_pBmpContext, NULL); + if (dwAvail == m_SrcSize) { + if (dwSize > FXCODEC_BLOCK_SIZE) { + dwSize = FXCODEC_BLOCK_SIZE; + } + m_SrcSize = (dwSize + dwAvail + FXCODEC_BLOCK_SIZE - 1) / FXCODEC_BLOCK_SIZE * FXCODEC_BLOCK_SIZE; + m_pSrcBuf = FX_Realloc(FX_BYTE, m_pSrcBuf, m_SrcSize); + if (!m_pSrcBuf) { + err_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + } else { + FX_DWORD dwConsume = m_SrcSize - dwAvail; + if (dwAvail) { + FXSYS_memcpy32(m_pSrcBuf, m_pSrcBuf + dwConsume, dwAvail); + } + if (dwSize > dwConsume) { + dwSize = dwConsume; + } + } + if (!m_pFile->ReadBlock(m_pSrcBuf + dwAvail, m_offSet, dwSize)) { + err_status = FXCODEC_STATUS_ERR_READ; + return FALSE; + } + m_offSet += dwSize; + pBmpModule->Input(m_pBmpContext, m_pSrcBuf, dwSize + dwAvail); + return TRUE; +} +FX_BOOL CCodec_ProgressiveDecoder::BmpInputImagePositionBufCallback(void* pModule, FX_DWORD rcd_pos) +{ + CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule; + pCodec->m_offSet = rcd_pos; + FXCODEC_STATUS error_status = FXCODEC_STATUS_ERROR; + if(!pCodec->BmpReadMoreData(pCodec->m_pCodecMgr->GetBmpModule(), error_status)) { + return FALSE; + } + return TRUE; +} +void CCodec_ProgressiveDecoder::BmpReadScanlineCallback(void* pModule, FX_INT32 row_num, FX_LPBYTE row_buf) +{ + CCodec_ProgressiveDecoder* pCodec = (CCodec_ProgressiveDecoder*)pModule; + CFX_DIBitmap* pDIBitmap = pCodec->m_pDeviceBitmap; + ASSERT(pDIBitmap != NULL); + FXSYS_memcpy32(pCodec->m_pDecodeBuf, row_buf, pCodec->m_ScanlineSize); + int src_top = pCodec->m_clipBox.top; + int src_bottom = pCodec->m_clipBox.bottom; + int des_top = pCodec->m_startY; + int src_hei = pCodec->m_clipBox.Height(); + int des_hei = pCodec->m_sizeY; + if(row_num >= src_top && row_num < src_bottom) { + double scale_y = (double)des_hei / (double)src_hei; + int src_row = row_num - src_top; + int des_row = (int)(src_row * scale_y) + des_top; + if(des_row >= des_top + des_hei) { + return; + } + pCodec->ReSampleScanline(pDIBitmap, des_row, pCodec->m_pDecodeBuf, pCodec->m_SrcFormat); + if(scale_y > 1.0) { + if(pCodec->m_BmpIsTopBottom || !pCodec->m_bInterpol) { + pCodec->ResampleVert(pDIBitmap, scale_y, des_row); + return; + } else { + pCodec->ResampleVertBT(pDIBitmap, scale_y, des_row); + } + } + } +} +void CCodec_ProgressiveDecoder::ResampleVertBT(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row) +{ + int des_Bpp = pDeviceBitmap->GetBPP() >> 3; + FX_DWORD des_ScanOffet = m_startX * des_Bpp; + int des_top = m_startY; + int des_bottom = m_startY + m_sizeY; + int des_row_1 = des_row + int(scale_y); + if(des_row_1 >= des_bottom - 1) { + FX_LPBYTE scan_src = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet; + while (++des_row < des_bottom) { + FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet; + FX_DWORD size = m_sizeX * des_Bpp; + FXSYS_memcpy32(scan_des, scan_src, size); + } + return; + } + for (; des_row_1 > des_row; des_row_1--) { + FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row_1) + des_ScanOffet; + PixelWeight* pWeight = m_WeightVert.GetPixelWeight(des_row_1 - des_top); + FX_LPCBYTE scan_src1 = pDeviceBitmap->GetScanline(pWeight->m_SrcStart + des_top) + des_ScanOffet; + FX_LPCBYTE scan_src2 = pDeviceBitmap->GetScanline(pWeight->m_SrcEnd + des_top) + des_ScanOffet; + for (int des_col = 0; des_col < m_sizeX; des_col++) { + switch(pDeviceBitmap->GetFormat()) { + case FXDIB_Invalid: + case FXDIB_1bppMask: + case FXDIB_1bppRgb: + return; + case FXDIB_8bppMask: + case FXDIB_8bppRgb: { + if(pDeviceBitmap->GetPalette() != NULL) { + return; + } + int des_g = 0; + des_g += pWeight->m_Weights[0] * (*scan_src1++); + des_g += pWeight->m_Weights[1] * (*scan_src2++); + *scan_des++ = (FX_BYTE)(des_g >> 16); + } + break; + case FXDIB_Rgb: + case FXDIB_Rgb32: { + FX_DWORD des_b = 0, des_g = 0, des_r = 0; + des_b += pWeight->m_Weights[0] * (*scan_src1++); + des_g += pWeight->m_Weights[0] * (*scan_src1++); + des_r += pWeight->m_Weights[0] * (*scan_src1++); + scan_src1 += des_Bpp - 3; + des_b += pWeight->m_Weights[1] * (*scan_src2++); + des_g += pWeight->m_Weights[1] * (*scan_src2++); + des_r += pWeight->m_Weights[1] * (*scan_src2++); + scan_src2 += des_Bpp - 3; + *scan_des++ = (FX_BYTE)((des_b) >> 16); + *scan_des++ = (FX_BYTE)((des_g) >> 16); + *scan_des++ = (FX_BYTE)((des_r) >> 16); + scan_des += des_Bpp - 3; + } + break; + case FXDIB_Argb: { + FX_DWORD des_a = 0, des_b = 0, des_g = 0, des_r = 0; + des_b += pWeight->m_Weights[0] * (*scan_src1++); + des_g += pWeight->m_Weights[0] * (*scan_src1++); + des_r += pWeight->m_Weights[0] * (*scan_src1++); + des_a += pWeight->m_Weights[0] * (*scan_src1++); + des_b += pWeight->m_Weights[1] * (*scan_src2++); + des_g += pWeight->m_Weights[1] * (*scan_src2++); + des_r += pWeight->m_Weights[1] * (*scan_src2++); + des_a += pWeight->m_Weights[1] * (*scan_src2++); + *scan_des++ = (FX_BYTE)((des_b) >> 16); + *scan_des++ = (FX_BYTE)((des_g) >> 16); + *scan_des++ = (FX_BYTE)((des_r) >> 16); + *scan_des++ = (FX_BYTE)((des_a) >> 16); + } + break; + default: + return; + } + } + } +} +FX_BOOL CCodec_ProgressiveDecoder::DetectImageType(FXCODEC_IMAGE_TYPE imageType, CFX_DIBAttribute* pAttribute) +{ + m_offSet = 0; + FX_DWORD size = (FX_DWORD)m_pFile->GetSize(); + if(size > FXCODEC_BLOCK_SIZE) { + size = FXCODEC_BLOCK_SIZE; + } + if(m_pSrcBuf != NULL) { + FX_Free(m_pSrcBuf); + m_pSrcBuf = NULL; + } + m_pSrcBuf = FX_Alloc(FX_BYTE, size); + if(m_pSrcBuf == NULL) { + m_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + FXSYS_memset32(m_pSrcBuf, 0, size); + m_SrcSize = size; + switch(imageType) { + case FXCODEC_IMAGE_BMP: { + ICodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule(); + if(pBmpModule == NULL) { + m_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + pBmpModule->InputImagePositionBufCallback = BmpInputImagePositionBufCallback; + pBmpModule->ReadScanlineCallback = BmpReadScanlineCallback; + m_pBmpContext = pBmpModule->Start((void*)this); + if(m_pBmpContext == NULL) { + m_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + FX_BOOL bResult = m_pFile->ReadBlock(m_pSrcBuf, 0, size); + if(!bResult) { + m_status = FXCODEC_STATUS_ERR_READ; + return FALSE; + } + m_offSet += size; + pBmpModule->Input(m_pBmpContext, m_pSrcBuf, size); + FX_DWORD* pPalette = NULL; + FX_INT32 readResult = pBmpModule->ReadHeader(m_pBmpContext, &m_SrcWidth, &m_SrcHeight, &m_BmpIsTopBottom, + &m_SrcComponents, &m_SrcPaletteNumber, &pPalette, pAttribute); + while(readResult == 2) { + FXCODEC_STATUS error_status = FXCODEC_STATUS_ERR_FORMAT; + if(!BmpReadMoreData(pBmpModule, error_status)) { + m_status = error_status; + return FALSE; + } + readResult = pBmpModule->ReadHeader(m_pBmpContext, &m_SrcWidth, &m_SrcHeight, &m_BmpIsTopBottom, + &m_SrcComponents, &m_SrcPaletteNumber, &pPalette, pAttribute); + } + if(readResult == 1) { + m_SrcBPC = 8; + m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight); + if(m_pSrcPalette != NULL) { + FX_Free(m_pSrcPalette); + m_pSrcPalette = NULL; + } + if (m_SrcPaletteNumber) { + m_pSrcPalette = FX_Alloc(FX_ARGB, m_SrcPaletteNumber); + if(m_pSrcPalette == NULL) { + m_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + FXSYS_memcpy32(m_pSrcPalette, pPalette, m_SrcPaletteNumber * sizeof(FX_DWORD)); + } + return TRUE; + } + if(m_pBmpContext != NULL) { + pBmpModule->Finish(m_pBmpContext); + m_pBmpContext = NULL; + } + m_status = FXCODEC_STATUS_ERR_FORMAT; + return FALSE; + } + break; + case FXCODEC_IMAGE_JPG: { + ICodec_JpegModule* pJpegModule = m_pCodecMgr->GetJpegModule(); + if(pJpegModule == NULL) { + m_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + m_pJpegContext = pJpegModule->Start(); + if(m_pJpegContext == NULL) { + m_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + FX_BOOL bResult = m_pFile->ReadBlock(m_pSrcBuf, 0, size); + if(!bResult) { + m_status = FXCODEC_STATUS_ERR_READ; + return FALSE; + } + m_offSet += size; + pJpegModule->Input(m_pJpegContext, m_pSrcBuf, size); + FX_INT32 readResult = pJpegModule->ReadHeader(m_pJpegContext, &m_SrcWidth, &m_SrcHeight, &m_SrcComponents, pAttribute); + while(readResult == 2) { + FXCODEC_STATUS error_status = FXCODEC_STATUS_ERR_FORMAT; + if(!JpegReadMoreData(pJpegModule, error_status)) { + m_status = error_status; + return FALSE; + } + readResult = pJpegModule->ReadHeader(m_pJpegContext, &m_SrcWidth, &m_SrcHeight, &m_SrcComponents, pAttribute); + } + if(!readResult) { + m_SrcBPC = 8; + m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight); + return TRUE; + } + if(m_pJpegContext != NULL) { + pJpegModule->Finish(m_pJpegContext); + m_pJpegContext = NULL; + } + m_status = FXCODEC_STATUS_ERR_FORMAT; + return FALSE; + } + break; + case FXCODEC_IMAGE_PNG: { + ICodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule(); + if(pPngModule == NULL) { + m_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + pPngModule->ReadHeaderCallback = CCodec_ProgressiveDecoder::PngReadHeaderFunc; + pPngModule->AskScanlineBufCallback = CCodec_ProgressiveDecoder::PngAskScanlineBufFunc; + pPngModule->FillScanlineBufCompletedCallback = CCodec_ProgressiveDecoder::PngFillScanlineBufCompletedFunc; + m_pPngContext = pPngModule->Start((void*)this); + if(m_pPngContext == NULL) { + m_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + FX_BOOL bResult = m_pFile->ReadBlock(m_pSrcBuf, 0, size); + if(!bResult) { + m_status = FXCODEC_STATUS_ERR_READ; + return FALSE; + } + m_offSet += size; + bResult = pPngModule->Input(m_pPngContext, m_pSrcBuf, size, pAttribute); + while(bResult) { + FX_DWORD remain_size = (FX_DWORD)m_pFile->GetSize() - m_offSet; + FX_DWORD input_size = remain_size > FXCODEC_BLOCK_SIZE ? FXCODEC_BLOCK_SIZE : remain_size; + if(input_size == 0) { + if(m_pPngContext != NULL) { + pPngModule->Finish(m_pPngContext); + } + m_pPngContext = NULL; + m_status = FXCODEC_STATUS_ERR_FORMAT; + return FALSE; + } + if(m_pSrcBuf != NULL && input_size > m_SrcSize) { + FX_Free(m_pSrcBuf); + m_pSrcBuf = FX_Alloc(FX_BYTE, input_size); + if(m_pSrcBuf == NULL) { + m_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + FXSYS_memset32(m_pSrcBuf, 0, input_size); + m_SrcSize = input_size; + } + bResult = m_pFile->ReadBlock(m_pSrcBuf, m_offSet, input_size); + if(!bResult) { + m_status = FXCODEC_STATUS_ERR_READ; + return FALSE; + } + m_offSet += input_size; + bResult = pPngModule->Input(m_pPngContext, m_pSrcBuf, input_size, pAttribute); + } + ASSERT(!bResult); + if(m_pPngContext != NULL) { + pPngModule->Finish(m_pPngContext); + m_pPngContext = NULL; + } + if(m_SrcPassNumber == 0) { + m_status = FXCODEC_STATUS_ERR_FORMAT; + return FALSE; + } + } + break; + case FXCODEC_IMAGE_GIF: { + ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule(); + if(pGifModule == NULL) { + m_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + pGifModule->RecordCurrentPositionCallback = CCodec_ProgressiveDecoder::GifRecordCurrentPositionCallback; + pGifModule->AskLocalPaletteBufCallback = CCodec_ProgressiveDecoder::GifAskLocalPaletteBufCallback; + pGifModule->InputRecordPositionBufCallback = CCodec_ProgressiveDecoder::GifInputRecordPositionBufCallback; + pGifModule->ReadScanlineCallback = CCodec_ProgressiveDecoder::GifReadScanlineCallback; + m_pGifContext = pGifModule->Start((void*)this); + if(m_pGifContext == NULL) { + m_status = FXCODEC_STATUS_ERR_MEMORY; + return FALSE; + } + FX_BOOL bResult = m_pFile->ReadBlock(m_pSrcBuf, 0, size); + if(!bResult) { + m_status = FXCODEC_STATUS_ERR_READ; + return FALSE; + } + m_offSet += size; + pGifModule->Input(m_pGifContext, m_pSrcBuf, size); + m_SrcComponents = 1; + FX_INT32 readResult = pGifModule->ReadHeader(m_pGifContext, &m_SrcWidth, &m_SrcHeight, + &m_GifPltNumber, (void**)&m_pGifPalette, &m_GifBgIndex); + while(readResult == 2) { + FXCODEC_STATUS error_status = FXCODEC_STATUS_ERR_FORMAT; + if(!GifReadMoreData(pGifModule, error_status)) { + m_status = error_status; + return FALSE; + } + readResult = pGifModule->ReadHeader(m_pGifContext, &m_SrcWidth, &m_SrcHeight, + &m_GifPltNumber, (void**)&m_pGifPalette, &m_GifBgIndex); + } + if(readResult == 1) { + m_SrcBPC = 8; + m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight); + return TRUE; + } + if(m_pGifContext != NULL) { + pGifModule->Finish(m_pGifContext); + m_pGifContext = NULL; + } + m_status = FXCODEC_STATUS_ERR_FORMAT; + return FALSE; + } + break; + case FXCODEC_IMAGE_TIF: { + ICodec_TiffModule* pTiffModule = m_pCodecMgr->GetTiffModule(); + if(pTiffModule == NULL) { + m_status = FXCODEC_STATUS_ERR_FORMAT; + return FALSE; + } + m_pTiffContext = pTiffModule->CreateDecoder(m_pFile); + if(m_pTiffContext == NULL) { + m_status = FXCODEC_STATUS_ERR_FORMAT; + return FALSE; + } + FX_INT32 frames = 0; + pTiffModule->GetFrames(m_pTiffContext, frames); + FX_DWORD bpc; + FX_BOOL ret = pTiffModule->LoadFrameInfo(m_pTiffContext, 0, (FX_DWORD&)m_SrcWidth, (FX_DWORD&)m_SrcHeight, (FX_DWORD&)m_SrcComponents, bpc, pAttribute); + m_SrcComponents = 4; + m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight); + if(!ret) { + pTiffModule->DestroyDecoder(m_pTiffContext); + (m_pTiffContext = NULL); + (m_status = FXCODEC_STATUS_ERR_FORMAT); + return FALSE; + } + } + break; + default: + m_status = FXCODEC_STATUS_ERR_FORMAT; + return FALSE; + } + return TRUE; +} +FXCODEC_STATUS CCodec_ProgressiveDecoder::LoadImageInfo(IFX_FileRead* pFile, FXCODEC_IMAGE_TYPE imageType, CFX_DIBAttribute* pAttribute) +{ + switch(m_status) { + case FXCODEC_STATUS_FRAME_READY: + case FXCODEC_STATUS_FRAME_TOBECONTINUE: + case FXCODEC_STATUS_DECODE_READY: + case FXCODEC_STATUS_DECODE_TOBECONTINUE: + return FXCODEC_STATUS_ERROR; + default: + ; + } + if(pFile == NULL) { + m_status = FXCODEC_STATUS_ERR_PARAMS; + m_pFile = NULL; + return m_status; + } + m_pFile = pFile; + m_offSet = 0; + m_SrcWidth = m_SrcHeight = 0; + m_SrcComponents = m_SrcBPC = 0; + m_clipBox = FX_RECT(0, 0, 0, 0); + m_startX = m_startY = 0; + m_sizeX = m_sizeY = 0; + m_SrcPassNumber = 0; + if(imageType != FXCODEC_IMAGE_UNKNOWN && + DetectImageType(imageType, pAttribute)) { + m_imagType = imageType; + m_status = FXCODEC_STATUS_FRAME_READY; + return m_status; + } + for (int type = FXCODEC_IMAGE_BMP; type < FXCODEC_IMAGE_MAX; type++) { + if(DetectImageType((FXCODEC_IMAGE_TYPE)type, pAttribute)) { + m_imagType = (FXCODEC_IMAGE_TYPE)type; + m_status = FXCODEC_STATUS_FRAME_READY; + return m_status; + } + } + m_status = FXCODEC_STATUS_ERR_FORMAT; + m_pFile = NULL; + return m_status; +} +void CCodec_ProgressiveDecoder::SetClipBox(FX_RECT* clip) +{ + if(m_status != FXCODEC_STATUS_FRAME_READY) { + return; + } + if(clip->IsEmpty()) { + m_clipBox = FX_RECT(0, 0, 0, 0); + return; + } + if(clip->left < 0) { + clip->left = 0; + } + if(clip->right > m_SrcWidth) { + clip->right = m_SrcWidth; + } + if(clip->top < 0) { + clip->top = 0; + } + if(clip->bottom > m_SrcHeight) { + clip->bottom = m_SrcHeight; + } + if(clip->IsEmpty()) { + m_clipBox = FX_RECT(0, 0, 0, 0); + return; + } + m_clipBox = *clip; +} +void CCodec_ProgressiveDecoder::GetDownScale(int& down_scale) +{ + down_scale = 1; + int ratio_w = m_clipBox.Width() / m_sizeX; + int ratio_h = m_clipBox.Height() / m_sizeY; + int ratio = (ratio_w > ratio_h) ? ratio_h : ratio_w; + if (ratio >= 8) { + down_scale = 8; + } else if (ratio >= 4) { + down_scale = 4; + } else if (ratio >= 2) { + down_scale = 2; + } + m_clipBox.left /= down_scale; + m_clipBox.right /= down_scale; + m_clipBox.top /= down_scale; + m_clipBox.bottom /= down_scale; + if(m_clipBox.right == m_clipBox.left) { + m_clipBox.right = m_clipBox.left + 1; + } + if(m_clipBox.bottom == m_clipBox.top) { + m_clipBox.bottom = m_clipBox.top + 1; + } +} +void CCodec_ProgressiveDecoder::GetTransMethod(FXDIB_Format des_format, FXCodec_Format src_format) +{ + switch(des_format) { + case FXDIB_1bppMask: + case FXDIB_1bppRgb: { + switch(src_format) { + case FXCodec_1bppGray: + m_TransMethod = 0; + break; + default: + m_TransMethod = -1; + } + } + break; + case FXDIB_8bppMask: + case FXDIB_8bppRgb: { + switch(src_format) { + case FXCodec_1bppGray: + m_TransMethod = 1; + break; + case FXCodec_8bppGray: + m_TransMethod = 2; + break; + case FXCodec_1bppRgb: + case FXCodec_8bppRgb: + m_TransMethod = 3; + break; + case FXCodec_Rgb: + case FXCodec_Rgb32: + case FXCodec_Argb: + m_TransMethod = 4; + break; + case FXCodec_Cmyk: + m_TransMethod = 5; + break; + default: + m_TransMethod = -1; + } + } + break; + case FXDIB_Rgb: { + switch(src_format) { + case FXCodec_1bppGray: + m_TransMethod = 6; + break; + case FXCodec_8bppGray: + m_TransMethod = 7; + break; + case FXCodec_1bppRgb: + case FXCodec_8bppRgb: + m_TransMethod = 8; + break; + case FXCodec_Rgb: + case FXCodec_Rgb32: + case FXCodec_Argb: + m_TransMethod = 9; + break; + case FXCodec_Cmyk: + m_TransMethod = 10; + break; + default: + m_TransMethod = -1; + } + } + break; + case FXDIB_Rgb32: + case FXDIB_Argb: { + switch(src_format) { + case FXCodec_1bppGray: + m_TransMethod = 6; + break; + case FXCodec_8bppGray: + m_TransMethod = 7; + break; + case FXCodec_1bppRgb: + case FXCodec_8bppRgb: + if(des_format == FXDIB_Argb) { + m_TransMethod = 12; + } else { + m_TransMethod = 8; + } + break; + case FXCodec_Rgb: + case FXCodec_Rgb32: + m_TransMethod = 9; + break; + case FXCodec_Cmyk: + m_TransMethod = 10; + break; + case FXCodec_Argb: + m_TransMethod = 11; + break; + default: + m_TransMethod = -1; + } + } + break; + default: + m_TransMethod = -1; + } +} +void _RGB2BGR(FX_LPBYTE buffer, int width = 1) +{ + if (buffer && width > 0) { + FX_BYTE temp; + int i = 0; + int j = 0; + for (; i < width; i++, j += 3) { + temp = buffer[j]; + buffer[j] = buffer[j + 2]; + buffer[j + 2] = temp; + } + } +} +void CCodec_ProgressiveDecoder::ReSampleScanline(CFX_DIBitmap* pDeviceBitmap, int des_line, FX_LPBYTE src_scan, FXCodec_Format src_format) +{ + int src_left = m_clipBox.left; + int des_left = m_startX; + FX_LPBYTE des_scan = pDeviceBitmap->GetBuffer() + des_line * pDeviceBitmap->GetPitch(); + int src_bpp = src_format & 0xff; + int des_bpp = pDeviceBitmap->GetBPP(); + int src_Bpp = src_bpp >> 3; + int des_Bpp = des_bpp >> 3; + src_scan += src_left * src_Bpp; + des_scan += des_left * des_Bpp; + for (int des_col = 0; des_col < m_sizeX; des_col++) { + PixelWeight* pPixelWeights = m_WeightHorz.GetPixelWeight(des_col); + switch(m_TransMethod) { + case -1: + return; + case 0: + return; + case 1: + return; + case 2: { + FX_DWORD des_g = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) { + int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + des_g += pixel_weight * src_scan[j]; + } + *des_scan++ = (FX_BYTE)(des_g >> 16); + } + break; + case 3: { + int des_r = 0, des_g = 0, des_b = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) { + int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + unsigned long argb = m_pSrcPalette[src_scan[j]]; + des_r += pixel_weight * (FX_BYTE)(argb >> 16); + des_g += pixel_weight * (FX_BYTE)(argb >> 8); + des_b += pixel_weight * (FX_BYTE)argb; + } + *des_scan++ = (FX_BYTE)FXRGB2GRAY((des_r >> 16), (des_g >> 16), (des_b >> 16)); + } + break; + case 4: { + FX_DWORD des_b = 0, des_g = 0, des_r = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) { + int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + FX_LPCBYTE src_pixel = src_scan + j * src_Bpp; + des_b += pixel_weight * (*src_pixel++); + des_g += pixel_weight * (*src_pixel++); + des_r += pixel_weight * (*src_pixel); + } + *des_scan++ = (FX_BYTE)FXRGB2GRAY((des_r >> 16), (des_g >> 16), (des_b >> 16)); + } + break; + case 5: { + FX_DWORD des_b = 0, des_g = 0, des_r = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) { + int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + FX_LPCBYTE src_pixel = src_scan + j * src_Bpp; + FX_BYTE src_b = 0, src_g = 0, src_r = 0; + AdobeCMYK_to_sRGB1(255 - src_pixel[0], 255 - src_pixel[1], 255 - src_pixel[2], 255 - src_pixel[3], + src_r, src_g, src_b); + des_b += pixel_weight * src_b; + des_g += pixel_weight * src_g; + des_r += pixel_weight * src_r; + } + *des_scan++ = (FX_BYTE)FXRGB2GRAY((des_r >> 16), (des_g >> 16), (des_b >> 16)); + } + break; + case 6: + return; + case 7: { + FX_DWORD des_g = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) { + int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + des_g += pixel_weight * src_scan[j]; + } + FXSYS_memset8(des_scan, (FX_BYTE)(des_g >> 16), 3); + des_scan += des_Bpp; + } + break; + case 8: { + int des_r = 0, des_g = 0, des_b = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) { + int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + unsigned long argb = m_pSrcPalette[src_scan[j]]; + des_r += pixel_weight * (FX_BYTE)(argb >> 16); + des_g += pixel_weight * (FX_BYTE)(argb >> 8); + des_b += pixel_weight * (FX_BYTE)argb; + } + *des_scan++ = (FX_BYTE)((des_b) >> 16); + *des_scan++ = (FX_BYTE)((des_g) >> 16); + *des_scan++ = (FX_BYTE)((des_r) >> 16); + des_scan += des_Bpp - 3; + } + break; + case 12: { + if (m_pBmpContext) { + int des_r = 0, des_g = 0, des_b = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) { + int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + unsigned long argb = m_pSrcPalette[src_scan[j]]; + des_r += pixel_weight * (FX_BYTE)(argb >> 16); + des_g += pixel_weight * (FX_BYTE)(argb >> 8); + des_b += pixel_weight * (FX_BYTE)argb; + } + *des_scan++ = (FX_BYTE)((des_b) >> 16); + *des_scan++ = (FX_BYTE)((des_g) >> 16); + *des_scan++ = (FX_BYTE)((des_r) >> 16); + *des_scan++ = 0xFF; + } else { + int des_a = 0, des_r = 0, des_g = 0, des_b = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) { + int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + unsigned long argb = m_pSrcPalette[src_scan[j]]; + des_a += pixel_weight * (FX_BYTE)(argb >> 24); + des_r += pixel_weight * (FX_BYTE)(argb >> 16); + des_g += pixel_weight * (FX_BYTE)(argb >> 8); + des_b += pixel_weight * (FX_BYTE)argb; + } + *des_scan++ = (FX_BYTE)((des_b) >> 16); + *des_scan++ = (FX_BYTE)((des_g) >> 16); + *des_scan++ = (FX_BYTE)((des_r) >> 16); + *des_scan++ = (FX_BYTE)((des_a) >> 16); + } + } + break; + case 9: { + FX_DWORD des_b = 0, des_g = 0, des_r = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) { + int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + FX_LPCBYTE src_pixel = src_scan + j * src_Bpp; + des_b += pixel_weight * (*src_pixel++); + des_g += pixel_weight * (*src_pixel++); + des_r += pixel_weight * (*src_pixel); + } + *des_scan++ = (FX_BYTE)((des_b) >> 16); + *des_scan++ = (FX_BYTE)((des_g) >> 16); + *des_scan++ = (FX_BYTE)((des_r) >> 16); + des_scan += des_Bpp - 3; + } + break; + case 10: { + FX_DWORD des_b = 0, des_g = 0, des_r = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j++) { + int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + FX_LPCBYTE src_pixel = src_scan + j * src_Bpp; + FX_BYTE src_b = 0, src_g = 0, src_r = 0; + AdobeCMYK_to_sRGB1(255 - src_pixel[0], 255 - src_pixel[1], 255 - src_pixel[2], 255 - src_pixel[3], + src_r, src_g, src_b); + des_b += pixel_weight * src_b; + des_g += pixel_weight * src_g; + des_r += pixel_weight * src_r; + } + *des_scan++ = (FX_BYTE)((des_b) >> 16); + *des_scan++ = (FX_BYTE)((des_g) >> 16); + *des_scan++ = (FX_BYTE)((des_r) >> 16); + des_scan += des_Bpp - 3; + } + break; + case 11: { + FX_DWORD des_alpha = 0, des_r = 0, des_g = 0, des_b = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) { + int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + FX_LPCBYTE src_pixel = src_scan + j * src_Bpp; + pixel_weight = pixel_weight * src_pixel[3] / 255; + des_b += pixel_weight * (*src_pixel++); + des_g += pixel_weight * (*src_pixel++); + des_r += pixel_weight * (*src_pixel); + des_alpha += pixel_weight; + } + *des_scan++ = (FX_BYTE)((des_b) >> 16); + *des_scan++ = (FX_BYTE)((des_g) >> 16); + *des_scan++ = (FX_BYTE)((des_r) >> 16); + *des_scan++ = (FX_BYTE)((des_alpha * 255) >> 16); + } + break; + default: + return; + } + } +} +void CCodec_ProgressiveDecoder::ResampleVert(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row) +{ + int des_Bpp = pDeviceBitmap->GetBPP() >> 3; + FX_DWORD des_ScanOffet = m_startX * des_Bpp; + if(m_bInterpol) { + int des_top = m_startY; + int des_row_1 = des_row - int(scale_y); + if(des_row_1 < des_top) { + int des_bottom = des_top + m_sizeY; + if(des_row + (int)scale_y >= des_bottom - 1) { + FX_LPBYTE scan_src = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet; + while (++des_row < des_bottom) { + FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet; + FX_DWORD size = m_sizeX * des_Bpp; + FXSYS_memcpy32(scan_des, scan_src, size); + } + } + return; + } + for (; des_row_1 < des_row; des_row_1++) { + FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row_1) + des_ScanOffet; + PixelWeight* pWeight = m_WeightVert.GetPixelWeight(des_row_1 - des_top); + FX_LPCBYTE scan_src1 = pDeviceBitmap->GetScanline(pWeight->m_SrcStart + des_top) + des_ScanOffet; + FX_LPCBYTE scan_src2 = pDeviceBitmap->GetScanline(pWeight->m_SrcEnd + des_top) + des_ScanOffet; + for (int des_col = 0; des_col < m_sizeX; des_col++) { + switch(pDeviceBitmap->GetFormat()) { + case FXDIB_Invalid: + case FXDIB_1bppMask: + case FXDIB_1bppRgb: + return; + case FXDIB_8bppMask: + case FXDIB_8bppRgb: { + if(pDeviceBitmap->GetPalette() != NULL) { + return; + } + int des_g = 0; + des_g += pWeight->m_Weights[0] * (*scan_src1++); + des_g += pWeight->m_Weights[1] * (*scan_src2++); + *scan_des++ = (FX_BYTE)(des_g >> 16); + } + break; + case FXDIB_Rgb: + case FXDIB_Rgb32: { + FX_DWORD des_b = 0, des_g = 0, des_r = 0; + des_b += pWeight->m_Weights[0] * (*scan_src1++); + des_g += pWeight->m_Weights[0] * (*scan_src1++); + des_r += pWeight->m_Weights[0] * (*scan_src1++); + scan_src1 += des_Bpp - 3; + des_b += pWeight->m_Weights[1] * (*scan_src2++); + des_g += pWeight->m_Weights[1] * (*scan_src2++); + des_r += pWeight->m_Weights[1] * (*scan_src2++); + scan_src2 += des_Bpp - 3; + *scan_des++ = (FX_BYTE)((des_b) >> 16); + *scan_des++ = (FX_BYTE)((des_g) >> 16); + *scan_des++ = (FX_BYTE)((des_r) >> 16); + scan_des += des_Bpp - 3; + } + break; + case FXDIB_Argb: { + FX_DWORD des_a = 0, des_b = 0, des_g = 0, des_r = 0; + des_b += pWeight->m_Weights[0] * (*scan_src1++); + des_g += pWeight->m_Weights[0] * (*scan_src1++); + des_r += pWeight->m_Weights[0] * (*scan_src1++); + des_a += pWeight->m_Weights[0] * (*scan_src1++); + des_b += pWeight->m_Weights[1] * (*scan_src2++); + des_g += pWeight->m_Weights[1] * (*scan_src2++); + des_r += pWeight->m_Weights[1] * (*scan_src2++); + des_a += pWeight->m_Weights[1] * (*scan_src2++); + *scan_des++ = (FX_BYTE)((des_b) >> 16); + *scan_des++ = (FX_BYTE)((des_g) >> 16); + *scan_des++ = (FX_BYTE)((des_r) >> 16); + *scan_des++ = (FX_BYTE)((des_a) >> 16); + } + break; + default: + return; + } + } + } + int des_bottom = des_top + m_sizeY; + if(des_row + (int)scale_y >= des_bottom - 1) { + FX_LPBYTE scan_src = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet; + while (++des_row < des_bottom) { + FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet; + FX_DWORD size = m_sizeX * des_Bpp; + FXSYS_memcpy32(scan_des, scan_src, size); + } + } + return; + } + int multiple = (int)FXSYS_ceil((FX_FLOAT)scale_y - 1); + if(multiple > 0) { + FX_LPBYTE scan_src = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row) + des_ScanOffet; + for (int i = 1; i <= multiple; i++) { + if(des_row + i >= m_startY + m_sizeY) { + return; + } + FX_LPBYTE scan_des = (FX_LPBYTE)pDeviceBitmap->GetScanline(des_row + i) + des_ScanOffet; + FX_DWORD size = m_sizeX * des_Bpp; + FXSYS_memcpy32(scan_des, scan_src, size); + } + } +} +void CCodec_ProgressiveDecoder::Resample(CFX_DIBitmap* pDeviceBitmap, FX_INT32 src_line, FX_LPBYTE src_scan, FXCodec_Format src_format) +{ + int src_top = m_clipBox.top; + int des_top = m_startY; + int src_hei = m_clipBox.Height(); + int des_hei = m_sizeY; + if(src_line >= src_top) { + double scale_y = (double)des_hei / (double)src_hei; + int src_row = src_line - src_top; + int des_row = (int)(src_row * scale_y) + des_top; + if(des_row >= des_top + des_hei) { + return; + } + ReSampleScanline(pDeviceBitmap, des_row, m_pDecodeBuf, src_format); + if(scale_y > 1.0) { + ResampleVert(pDeviceBitmap, scale_y, des_row); + } + } +} +FXCODEC_STATUS CCodec_ProgressiveDecoder::GetFrames(FX_INT32& frames, IFX_Pause* pPause) +{ + if(!(m_status == FXCODEC_STATUS_FRAME_READY || m_status == FXCODEC_STATUS_FRAME_TOBECONTINUE)) { + return FXCODEC_STATUS_ERROR; + } + switch(m_imagType) { + case FXCODEC_IMAGE_BMP: + case FXCODEC_IMAGE_JPG: + case FXCODEC_IMAGE_PNG: + case FXCODEC_IMAGE_TIF: + frames = m_FrameNumber = 1; + return m_status = FXCODEC_STATUS_DECODE_READY; + case FXCODEC_IMAGE_GIF: { + ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule(); + while (TRUE) { + FX_INT32 readResult = pGifModule->LoadFrameInfo(m_pGifContext, &m_FrameNumber); + while(readResult == 2) { + FXCODEC_STATUS error_status = FXCODEC_STATUS_ERR_READ; + if(!GifReadMoreData(pGifModule, error_status)) { + return error_status; + } + if(pPause && pPause->NeedToPauseNow()) { + return m_status = FXCODEC_STATUS_FRAME_TOBECONTINUE; + } + readResult = pGifModule->LoadFrameInfo(m_pGifContext, &m_FrameNumber); + } + if(readResult == 1) { + frames = m_FrameNumber; + return m_status = FXCODEC_STATUS_DECODE_READY; + } + if(m_pGifContext != NULL) { + pGifModule->Finish(m_pGifContext); + m_pGifContext = NULL; + } + return m_status = FXCODEC_STATUS_ERROR; + } + } + break; + default: + ; + } + return FXCODEC_STATUS_ERROR; +} +FXCODEC_STATUS CCodec_ProgressiveDecoder::StartDecode(CFX_DIBitmap* pDIBitmap, + int start_x, int start_y, int size_x, int size_y, + FX_INT32 frames, FX_BOOL bInterpol) +{ + if(m_status != FXCODEC_STATUS_DECODE_READY) { + return FXCODEC_STATUS_ERROR; + } + if(pDIBitmap == NULL || pDIBitmap->GetBPP() < 8 || + frames < 0 || frames >= m_FrameNumber) { + return FXCODEC_STATUS_ERR_PARAMS; + } + m_pDeviceBitmap = pDIBitmap; + if(m_clipBox.IsEmpty()) { + return FXCODEC_STATUS_ERR_PARAMS; + } + if(size_x <= 0 || size_x > 65535 || size_y <= 0 || size_y > 65535) { + return FXCODEC_STATUS_ERR_PARAMS; + } + FX_RECT device_rc = FX_RECT(start_x, start_y, start_x + size_x, start_y + size_y); + FX_INT32 out_range_x = device_rc.right - pDIBitmap->GetWidth(); + FX_INT32 out_range_y = device_rc.bottom - pDIBitmap->GetHeight(); + device_rc.Intersect(FX_RECT(0, 0, pDIBitmap->GetWidth(), pDIBitmap->GetHeight())); + if(device_rc.IsEmpty()) { + return FXCODEC_STATUS_ERR_PARAMS; + } + m_startX = device_rc.left; + m_startY = device_rc.top; + m_sizeX = device_rc.Width(); + m_sizeY = device_rc.Height(); + m_bInterpol = bInterpol; + m_FrameCur = 0; + if(start_x < 0 || out_range_x > 0) { + FX_FLOAT scaleX = (FX_FLOAT)m_clipBox.Width() / (FX_FLOAT)size_x; + if(start_x < 0) { + m_clipBox.left -= (FX_INT32)FXSYS_ceil((FX_FLOAT)start_x * scaleX); + } + if(out_range_x > 0) { + m_clipBox.right -= (FX_INT32)FXSYS_floor((FX_FLOAT)out_range_x * scaleX); + } + } + if(start_y < 0 || out_range_y > 0) { + FX_FLOAT scaleY = (FX_FLOAT)m_clipBox.Height() / (FX_FLOAT)size_y; + if(start_y < 0) { + m_clipBox.top -= (FX_INT32)FXSYS_ceil((FX_FLOAT)start_y * scaleY); + } + if(out_range_y > 0) { + m_clipBox.bottom -= (FX_INT32)FXSYS_floor((FX_FLOAT)out_range_y * scaleY); + } + } + if(m_clipBox.IsEmpty()) { + return FXCODEC_STATUS_ERR_PARAMS; + } + switch(m_imagType) { + case FXCODEC_IMAGE_JPG: { + ICodec_JpegModule* pJpegModule = m_pCodecMgr->GetJpegModule(); + int down_scale = 1; + GetDownScale(down_scale); + FX_BOOL bStart = pJpegModule->StartScanline(m_pJpegContext, down_scale); + while(!bStart) { + FXCODEC_STATUS error_status = FXCODEC_STATUS_ERROR; + if(!JpegReadMoreData(pJpegModule, error_status)) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = error_status; + } + bStart = pJpegModule->StartScanline(m_pJpegContext, down_scale); + } + int scanline_size = ( m_SrcWidth + down_scale - 1) / down_scale; + scanline_size = (scanline_size * m_SrcComponents + 3) / 4 * 4; + if(m_pDecodeBuf != NULL) { + FX_Free(m_pDecodeBuf); + m_pDecodeBuf = NULL; + } + m_pDecodeBuf = FX_Alloc(FX_BYTE, scanline_size); + if(m_pDecodeBuf == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + FXSYS_memset32(m_pDecodeBuf, 0, scanline_size); + m_WeightHorz.Calc(m_sizeX, 0, m_sizeX, m_clipBox.Width(), 0, m_clipBox.Width(), m_bInterpol); + m_WeightVert.Calc(m_sizeY, m_clipBox.Height()); + switch(m_SrcComponents) { + case 1: + m_SrcFormat = FXCodec_8bppGray; + break; + case 3: + m_SrcFormat = FXCodec_Rgb; + break; + case 4: + m_SrcFormat = FXCodec_Cmyk; + break; + } + GetTransMethod(pDIBitmap->GetFormat(), m_SrcFormat); + return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + break; + case FXCODEC_IMAGE_PNG: { + ICodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule(); + if(pPngModule == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + if(m_pPngContext != NULL) { + pPngModule->Finish(m_pPngContext); + m_pPngContext = NULL; + } + m_pPngContext = pPngModule->Start((void*)this); + if(m_pPngContext == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + m_offSet = 0; + switch(m_pDeviceBitmap->GetFormat()) { + case FXDIB_8bppMask: + case FXDIB_8bppRgb: + m_SrcComponents = 1; + m_SrcFormat = FXCodec_8bppGray; + break; + case FXDIB_Rgb: + m_SrcComponents = 3; + m_SrcFormat = FXCodec_Rgb; + break; + case FXDIB_Rgb32: + case FXDIB_Argb: + m_SrcComponents = 4; + m_SrcFormat = FXCodec_Argb; + break; + default: { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_PARAMS; + } + } + GetTransMethod(m_pDeviceBitmap->GetFormat(), m_SrcFormat); + int scanline_size = (m_SrcWidth * m_SrcComponents + 3) / 4 * 4; + if(m_pDecodeBuf != NULL) { + FX_Free(m_pDecodeBuf); + m_pDecodeBuf = NULL; + } + m_pDecodeBuf = FX_Alloc(FX_BYTE, scanline_size); + if(m_pDecodeBuf == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + FXSYS_memset32(m_pDecodeBuf, 0, scanline_size); + m_WeightHorzOO.Calc(m_sizeX, m_clipBox.Width(), m_bInterpol); + m_WeightVert.Calc(m_sizeY, m_clipBox.Height()); + return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + break; + case FXCODEC_IMAGE_GIF: { + ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule(); + if(pGifModule == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + m_SrcFormat = FXCodec_8bppRgb; + GetTransMethod(m_pDeviceBitmap->GetFormat(), m_SrcFormat); + int scanline_size = (m_SrcWidth + 3) / 4 * 4; + if(m_pDecodeBuf != NULL) { + FX_Free(m_pDecodeBuf); + m_pDecodeBuf = NULL; + } + m_pDecodeBuf = FX_Alloc(FX_BYTE, scanline_size); + if(m_pDecodeBuf == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + FXSYS_memset32(m_pDecodeBuf, 0, scanline_size); + m_WeightHorz.Calc(m_sizeX, 0, m_sizeX, m_clipBox.Width(), 0, m_clipBox.Width(), m_bInterpol); + m_WeightVert.Calc(m_sizeY, m_clipBox.Height()); + m_FrameCur = frames; + return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + break; + case FXCODEC_IMAGE_BMP: { + ICodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule(); + if(pBmpModule == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + switch(m_SrcComponents) { + case 1: + m_SrcFormat = FXCodec_8bppRgb; + break; + case 3: + m_SrcFormat = FXCodec_Rgb; + break; + case 4: + m_SrcFormat = FXCodec_Rgb32; + break; + } + GetTransMethod(m_pDeviceBitmap->GetFormat(), m_SrcFormat); + m_ScanlineSize = (m_SrcWidth * m_SrcComponents + 3) / 4 * 4; + if(m_pDecodeBuf != NULL) { + FX_Free(m_pDecodeBuf); + m_pDecodeBuf = NULL; + } + m_pDecodeBuf = FX_Alloc(FX_BYTE, m_ScanlineSize); + if(m_pDecodeBuf == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + FXSYS_memset32(m_pDecodeBuf, 0, m_ScanlineSize); + m_WeightHorz.Calc(m_sizeX, 0, m_sizeX, m_clipBox.Width(), 0, m_clipBox.Width(), m_bInterpol); + m_WeightVert.Calc(m_sizeY, m_clipBox.Height()); + return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + break; + case FXCODEC_IMAGE_TIF: + return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE; + default: + break; + } + return FXCODEC_STATUS_ERROR; +} +FXCODEC_STATUS CCodec_ProgressiveDecoder::ContinueDecode(IFX_Pause* pPause) +{ + if(m_status != FXCODEC_STATUS_DECODE_TOBECONTINUE) { + return FXCODEC_STATUS_ERROR; + } + switch(m_imagType) { + case FXCODEC_IMAGE_JPG: { + ICodec_JpegModule* pJpegModule = m_pCodecMgr->GetJpegModule(); + while(TRUE) { + FX_BOOL readRes = pJpegModule->ReadScanline(m_pJpegContext, m_pDecodeBuf); + while(!readRes) { + FXCODEC_STATUS error_status = FXCODEC_STATUS_DECODE_FINISH; + if(!JpegReadMoreData(pJpegModule, error_status)) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = error_status; + } + readRes = pJpegModule->ReadScanline(m_pJpegContext, m_pDecodeBuf); + } + if(m_SrcFormat == FXCodec_Rgb) { + int src_Bpp = (m_SrcFormat & 0xff) >> 3; + _RGB2BGR(m_pDecodeBuf + m_clipBox.left * src_Bpp, m_clipBox.Width()); + } + if(m_SrcRow >= m_clipBox.bottom) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_DECODE_FINISH; + } + Resample(m_pDeviceBitmap, m_SrcRow, m_pDecodeBuf, m_SrcFormat); + m_SrcRow++; + if(pPause && pPause->NeedToPauseNow()) { + return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + } + } + break; + case FXCODEC_IMAGE_PNG: { + ICodec_PngModule* pPngModule = m_pCodecMgr->GetPngModule(); + while (TRUE) { + FX_DWORD remain_size = (FX_DWORD)m_pFile->GetSize() - m_offSet; + FX_DWORD input_size = remain_size > FXCODEC_BLOCK_SIZE ? FXCODEC_BLOCK_SIZE : remain_size; + if(input_size == 0) { + if(m_pPngContext != NULL) { + pPngModule->Finish(m_pPngContext); + } + m_pPngContext = NULL; + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_DECODE_FINISH; + } + if(m_pSrcBuf != NULL && input_size > m_SrcSize) { + FX_Free(m_pSrcBuf); + m_pSrcBuf = FX_Alloc(FX_BYTE, input_size); + if(m_pSrcBuf == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + FXSYS_memset32(m_pSrcBuf, 0, input_size); + m_SrcSize = input_size; + } + FX_BOOL bResult = m_pFile->ReadBlock(m_pSrcBuf, m_offSet, input_size); + if(!bResult) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_READ; + } + m_offSet += input_size; + bResult = pPngModule->Input(m_pPngContext, m_pSrcBuf, input_size); + if(!bResult) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERROR; + } + if(pPause && pPause->NeedToPauseNow()) { + return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + } + } + break; + case FXCODEC_IMAGE_GIF: { + ICodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule(); + while(TRUE) { + FX_INT32 readRes = pGifModule->LoadFrame(m_pGifContext, m_FrameCur); + while(readRes == 2) { + FXCODEC_STATUS error_status = FXCODEC_STATUS_DECODE_FINISH; + if(!GifReadMoreData(pGifModule, error_status)) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = error_status; + } + if(pPause && pPause->NeedToPauseNow()) { + return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + readRes = pGifModule->LoadFrame(m_pGifContext, m_FrameCur); + } + if(readRes == 1) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_DECODE_FINISH; + } + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERROR; + } + } + break; + case FXCODEC_IMAGE_BMP: { + ICodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule(); + while(TRUE) { + FX_INT32 readRes = pBmpModule->LoadImage(m_pBmpContext); + while(readRes == 2) { + FXCODEC_STATUS error_status = FXCODEC_STATUS_DECODE_FINISH; + if(!BmpReadMoreData(pBmpModule, error_status)) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = error_status; + } + if(pPause && pPause->NeedToPauseNow()) { + return m_status = FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + readRes = pBmpModule->LoadImage(m_pBmpContext); + } + if(readRes == 1) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_DECODE_FINISH; + } + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERROR; + } + } + break; + case FXCODEC_IMAGE_TIF: { + ICodec_TiffModule* pTiffModule = m_pCodecMgr->GetTiffModule(); + FX_BOOL ret = FALSE; + if(m_pDeviceBitmap->GetBPP() == 32 && + m_pDeviceBitmap->GetWidth() == m_SrcWidth && m_SrcWidth == m_sizeX && + m_pDeviceBitmap->GetHeight() == m_SrcHeight && m_SrcHeight == m_sizeY && + m_startX == 0 && m_startY == 0 && m_clipBox.left == 0 && m_clipBox.top == 0 + && m_clipBox.right == m_SrcWidth && m_clipBox.bottom == m_SrcHeight) { + ret = pTiffModule->Decode(m_pTiffContext, m_pDeviceBitmap); + m_pDeviceBitmap = NULL; + m_pFile = NULL; + if(!ret) { + return m_status = FXCODEC_STATUS_ERROR; + } + return m_status = FXCODEC_STATUS_DECODE_FINISH; + } else { + CFX_DIBitmap* pDIBitmap = FX_NEW CFX_DIBitmap; + if(pDIBitmap == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + pDIBitmap->Create(m_SrcWidth, m_SrcHeight, FXDIB_Argb); + if(pDIBitmap->GetBuffer() == NULL) { + delete pDIBitmap; + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + ret = pTiffModule->Decode(m_pTiffContext, pDIBitmap); + if(!ret) { + delete pDIBitmap; + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERROR; + } + CFX_DIBitmap* pClipBitmap = + (m_clipBox.left == 0 && + m_clipBox.top == 0 && + m_clipBox.right == m_SrcWidth && + m_clipBox.bottom == m_SrcHeight) ? pDIBitmap : pDIBitmap->Clone(&m_clipBox); + if(pDIBitmap != pClipBitmap) { + delete pDIBitmap; + } + if(pClipBitmap == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + CFX_DIBitmap* pFormatBitmap = NULL; + switch(m_pDeviceBitmap->GetFormat()) { + case FXDIB_8bppRgb: + pFormatBitmap = FX_NEW CFX_DIBitmap; + if(pFormatBitmap == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(), FXDIB_8bppRgb); + break; + case FXDIB_8bppMask: + pFormatBitmap = FX_NEW CFX_DIBitmap; + if(pFormatBitmap == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(), FXDIB_8bppMask); + break; + case FXDIB_Rgb: + pFormatBitmap = FX_NEW CFX_DIBitmap; + if(pFormatBitmap == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(), FXDIB_Rgb); + break; + case FXDIB_Rgb32: + pFormatBitmap = FX_NEW CFX_DIBitmap; + if(pFormatBitmap == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + pFormatBitmap->Create(pClipBitmap->GetWidth(), pClipBitmap->GetHeight(), FXDIB_Rgb32); + break; + case FXDIB_Argb: + pFormatBitmap = pClipBitmap; + break; + default: + ; + } + switch(m_pDeviceBitmap->GetFormat()) { + case FXDIB_8bppRgb: + case FXDIB_8bppMask: { + for (FX_INT32 row = 0; row < pClipBitmap->GetHeight(); row++) { + FX_LPBYTE src_line = (FX_LPBYTE)pClipBitmap->GetScanline(row); + FX_LPBYTE des_line = (FX_LPBYTE)pFormatBitmap->GetScanline(row); + for (FX_INT32 col = 0; col < pClipBitmap->GetWidth(); col++) { + FX_BYTE _a = 255 - src_line[3]; + FX_BYTE b = (src_line[0] * src_line[3] + 0xFF * _a) / 255; + FX_BYTE g = (src_line[1] * src_line[3] + 0xFF * _a) / 255; + FX_BYTE r = (src_line[2] * src_line[3] + 0xFF * _a) / 255; + *des_line++ = FXRGB2GRAY(r, g, b); + src_line += 4; + } + } + } + break; + case FXDIB_Rgb: + case FXDIB_Rgb32: { + FX_INT32 desBpp = (m_pDeviceBitmap->GetFormat() == FXDIB_Rgb) ? 3 : 4; + for (FX_INT32 row = 0; row < pClipBitmap->GetHeight(); row++) { + FX_LPBYTE src_line = (FX_LPBYTE)pClipBitmap->GetScanline(row); + FX_LPBYTE des_line = (FX_LPBYTE)pFormatBitmap->GetScanline(row); + for (FX_INT32 col = 0; col < pClipBitmap->GetWidth(); col++) { + FX_BYTE _a = 255 - src_line[3]; + FX_BYTE b = (src_line[0] * src_line[3] + 0xFF * _a) / 255; + FX_BYTE g = (src_line[1] * src_line[3] + 0xFF * _a) / 255; + FX_BYTE r = (src_line[2] * src_line[3] + 0xFF * _a) / 255; + *des_line++ = b; + *des_line++ = g; + *des_line++ = r; + des_line += desBpp - 3; + src_line += 4; + } + } + } + break; + default: + ; + } + if(pClipBitmap != pFormatBitmap) { + delete pClipBitmap; + } + if(pFormatBitmap == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + CFX_DIBitmap* pStrechBitmap = pFormatBitmap->StretchTo(m_sizeX, m_sizeY, m_bInterpol ? FXDIB_INTERPOL : FXDIB_DOWNSAMPLE); + delete pFormatBitmap; + pFormatBitmap = NULL; + if(pStrechBitmap == NULL) { + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_ERR_MEMORY; + } + m_pDeviceBitmap->TransferBitmap(m_startX, m_startY, m_sizeX, m_sizeY, pStrechBitmap, 0, 0); + delete pStrechBitmap; + pStrechBitmap = NULL; + m_pDeviceBitmap = NULL; + m_pFile = NULL; + return m_status = FXCODEC_STATUS_DECODE_FINISH; + } + } + break; + default: + break; + } + return FXCODEC_STATUS_ERROR; +} +ICodec_ProgressiveDecoder* CCodec_ModuleMgr::CreateProgressiveDecoder() +{ + return FX_NEW CCodec_ProgressiveDecoder(this); +} diff --git a/core/src/fxcodec/codec/fx_codec_progress.h b/core/src/fxcodec/codec/fx_codec_progress.h new file mode 100644 index 0000000000..6a618e2f51 --- /dev/null +++ b/core/src/fxcodec/codec/fx_codec_progress.h @@ -0,0 +1,206 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef _FX_CODEC_PROGRESS_H_ +#define _FX_CODEC_PROGRESS_H_ +#define FXCODEC_BLOCK_SIZE 4096 +#define FXCODEC_PNG_GAMMA 2.2 +#if _FX_OS_ == _FX_MACOSX_ || _FX_OS_ == _FX_IOS_ +# undef FXCODEC_PNG_GAMMA +# define FXCODEC_PNG_GAMMA 1.7 +#endif +struct PixelWeight { + int m_SrcStart; + int m_SrcEnd; + int m_Weights[1]; +}; +class CFXCODEC_WeightTable : public CFX_Object +{ +public: + CFXCODEC_WeightTable() + { + m_pWeightTables = NULL; + } + ~CFXCODEC_WeightTable() + { + if(m_pWeightTables != NULL) { + FX_Free(m_pWeightTables); + } + } + + void Calc(int dest_len, int dest_min, int dest_max, int src_len, int src_min, int src_max, FX_BOOL bInterpol); + PixelWeight* GetPixelWeight(int pixel) + { + return (PixelWeight*)(m_pWeightTables + (pixel - m_DestMin) * m_ItemSize); + } + + int m_DestMin, m_ItemSize; + FX_LPBYTE m_pWeightTables; +}; +class CFXCODEC_HorzTable : public CFX_Object +{ +public: + CFXCODEC_HorzTable() + { + m_pWeightTables = NULL; + } + ~CFXCODEC_HorzTable() + { + if(m_pWeightTables != NULL) { + FX_Free(m_pWeightTables); + } + } + + void Calc(int dest_len, int src_len, FX_BOOL bInterpol); + PixelWeight* GetPixelWeight(int pixel) + { + return (PixelWeight*)(m_pWeightTables + pixel * m_ItemSize); + } + + int m_ItemSize; + FX_LPBYTE m_pWeightTables; +}; +class CFXCODEC_VertTable : public CFX_Object +{ +public: + CFXCODEC_VertTable() + { + m_pWeightTables = NULL; + } + ~CFXCODEC_VertTable() + { + if(m_pWeightTables != NULL) { + FX_Free(m_pWeightTables); + } + } + void Calc(int dest_len, int src_len); + PixelWeight* GetPixelWeight(int pixel) + { + return (PixelWeight*)(m_pWeightTables + pixel * m_ItemSize); + } + int m_ItemSize; + FX_LPBYTE m_pWeightTables; +}; +enum FXCodec_Format { + FXCodec_Invalid = 0, + FXCodec_1bppGray = 0x101, + FXCodec_1bppRgb = 0x001, + FXCodec_8bppGray = 0x108, + FXCodec_8bppRgb = 0x008, + FXCodec_Rgb = 0x018, + FXCodec_Rgb32 = 0x020, + FXCodec_Argb = 0x220, + FXCodec_Cmyk = 0x120 +}; +class CCodec_ProgressiveDecoder : public ICodec_ProgressiveDecoder +{ +public: + CCodec_ProgressiveDecoder(CCodec_ModuleMgr* pCodecMgr); + virtual ~CCodec_ProgressiveDecoder(); + +public: + virtual FXCODEC_STATUS LoadImageInfo(IFX_FileRead* pFile, FXCODEC_IMAGE_TYPE imageType, CFX_DIBAttribute* pAttribute); + + virtual FXCODEC_IMAGE_TYPE GetType() + { + return m_imagType; + } + virtual FX_INT32 GetWidth() + { + return m_SrcWidth; + } + virtual FX_INT32 GetHeight() + { + return m_SrcHeight; + } + virtual FX_INT32 GetNumComponents() + { + return m_SrcComponents; + } + virtual FX_INT32 GetBPC() + { + return m_SrcBPC; + } + virtual void SetClipBox(FX_RECT* clip); + virtual FXCODEC_STATUS GetFrames(FX_INT32& frames, IFX_Pause* pPause); + + virtual FXCODEC_STATUS StartDecode(CFX_DIBitmap* pDIBitmap, + int start_x, int start_y, int size_x, int size_y, + FX_INT32 frames, FX_BOOL bInterpol); + + virtual FXCODEC_STATUS ContinueDecode(IFX_Pause* pPause); + +protected: + FX_BOOL DetectImageType(FXCODEC_IMAGE_TYPE imageType, CFX_DIBAttribute* pAttribute = NULL); + void GetDownScale(int& down_scale); + void GetTransMethod(FXDIB_Format des_format, FXCodec_Format src_format); + void ReSampleScanline(CFX_DIBitmap* pDeviceBitmap, FX_INT32 des_line, FX_LPBYTE src_scan, FXCodec_Format src_format); + void Resample(CFX_DIBitmap* pDeviceBitmap, FX_INT32 src_line, FX_LPBYTE src_scan, FXCodec_Format src_format); + void ResampleVert(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row); + FX_BOOL JpegReadMoreData(ICodec_JpegModule* pJpegModule, FXCODEC_STATUS& err_status); + static FX_BOOL PngReadHeaderFunc(void* pModule, int width, int height, int bpc, int pass, int* color_type, double* gamma); + static FX_BOOL PngAskScanlineBufFunc(void* pModule, int line, FX_LPBYTE& src_buf); + static void PngFillScanlineBufCompletedFunc(void* pModule, int pass, int line); + void PngOneOneMapResampleHorz(CFX_DIBitmap* pDeviceBitmap, FX_INT32 des_line, FX_LPBYTE src_scan, FXCodec_Format src_format); + + FX_BOOL GifReadMoreData(ICodec_GifModule* pGifModule, FXCODEC_STATUS& err_status); + static void GifRecordCurrentPositionCallback(void* pModule, FX_DWORD& cur_pos); + static FX_LPBYTE GifAskLocalPaletteBufCallback(void* pModule, FX_INT32 frame_num, FX_INT32 pal_size); + static FX_BOOL GifInputRecordPositionBufCallback(void* pModule, FX_DWORD rcd_pos, const FX_RECT& img_rc, + FX_INT32 pal_num, void* pal_ptr, + FX_INT32 delay_time, FX_BOOL user_input, + FX_INT32 trans_index, FX_INT32 disposal_method, FX_BOOL interlace); + static void GifReadScanlineCallback(void* pModule, FX_INT32 row_num, FX_LPBYTE row_buf); + void GifDoubleLineResampleVert(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row); + FX_BOOL BmpReadMoreData(ICodec_BmpModule* pBmpModule, FXCODEC_STATUS& err_status); + static FX_BOOL BmpInputImagePositionBufCallback(void* pModule, FX_DWORD rcd_pos); + static void BmpReadScanlineCallback(void* pModule, FX_INT32 row_num, FX_LPBYTE row_buf); + void ResampleVertBT(CFX_DIBitmap* pDeviceBitmap, double scale_y, int des_row); +public: + IFX_FileRead* m_pFile; + CCodec_ModuleMgr* m_pCodecMgr; + FX_LPVOID m_pJpegContext; + FX_LPVOID m_pPngContext; + FX_LPVOID m_pGifContext; + FX_LPVOID m_pBmpContext; + FX_LPVOID m_pTiffContext; + FXCODEC_IMAGE_TYPE m_imagType; + FX_DWORD m_offSet; + FX_LPBYTE m_pSrcBuf; + FX_DWORD m_SrcSize; + FX_LPBYTE m_pDecodeBuf; + int m_ScanlineSize; + CFX_DIBitmap* m_pDeviceBitmap; + FX_BOOL m_bInterpol; + CFXCODEC_WeightTable m_WeightHorz; + CFXCODEC_VertTable m_WeightVert; + CFXCODEC_HorzTable m_WeightHorzOO; + int m_SrcWidth; + int m_SrcHeight; + int m_SrcComponents; + int m_SrcBPC; + FX_RECT m_clipBox; + int m_startX; + int m_startY; + int m_sizeX; + int m_sizeY; + int m_TransMethod; + FX_ARGB* m_pSrcPalette; + int m_SrcPaletteNumber; + int m_SrcRow; + FXCodec_Format m_SrcFormat; + int m_SrcPassNumber; + int m_FrameNumber; + int m_FrameCur; + int m_GifBgIndex; + FX_LPBYTE m_pGifPalette; + FX_INT32 m_GifPltNumber; + int m_GifTransIndex; + FX_RECT m_GifFrameRect; + FX_BOOL m_BmpIsTopBottom; + FXCODEC_STATUS m_status; +}; +#endif diff --git a/core/src/fxcodec/codec/fx_codec_tiff.cpp b/core/src/fxcodec/codec/fx_codec_tiff.cpp new file mode 100644 index 0000000000..c90de7a74f --- /dev/null +++ b/core/src/fxcodec/codec/fx_codec_tiff.cpp @@ -0,0 +1,532 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../../../include/fxcodec/fx_codec.h" +#include "../../../include/fxge/fx_dib.h" +#include "codec_int.h" +extern "C" { +#include "../fx_tiff/include/fx_tiffiop.h" +} +#if !defined(_FPDFAPI_MINI_) +void* IccLib_CreateTransform_sRGB(const unsigned char* pProfileData, unsigned int dwProfileSize, int nComponents, int intent, FX_DWORD dwSrcFormat = Icc_FORMAT_DEFAULT); +void IccLib_TranslateImage(void* pTransform, unsigned char* pDest, const unsigned char* pSrc, int pixels); +void IccLib_DestroyTransform(void* pTransform); +#endif +class CCodec_TiffContext : public CFX_Object +{ +public: + CCodec_TiffContext(); + ~CCodec_TiffContext(); + + FX_BOOL InitDecoder(IFX_FileRead* file_ptr); + void GetFrames(FX_INT32& frames); + FX_BOOL LoadFrameInfo(FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute); + FX_BOOL Decode(CFX_DIBitmap* pDIBitmap); + + union { + IFX_FileRead* in; + IFX_FileStream* out; + } io; + + FX_DWORD offset; + + TIFF* tif_ctx; + void* icc_ctx; + FX_INT32 frame_num; + FX_INT32 frame_cur; + FX_BOOL isDecoder; +private: + FX_BOOL isSupport(CFX_DIBitmap* pDIBitmap); + void SetPalette(CFX_DIBitmap* pDIBitmap, FX_UINT16 bps); + FX_BOOL Decode1bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp); + FX_BOOL Decode8bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp); + FX_BOOL Decode24bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp); +}; +CCodec_TiffContext::CCodec_TiffContext() +{ + offset = 0; + frame_num = 0; + frame_cur = 0; + io.in = NULL; + tif_ctx = NULL; + icc_ctx = NULL; + isDecoder = TRUE; +} +CCodec_TiffContext::~CCodec_TiffContext() +{ +#if !defined(_FPDFAPI_MINI_) + if(icc_ctx) { + IccLib_DestroyTransform(icc_ctx); + icc_ctx = NULL; + } +#endif + if(tif_ctx) { + TIFFClose(tif_ctx); + } +} +static tsize_t _tiff_read(thandle_t context, tdata_t buf, tsize_t length) +{ + CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context; + FX_BOOL ret = FALSE; + if(pTiffContext->isDecoder) { + ret = pTiffContext->io.in->ReadBlock(buf, pTiffContext->offset, length); + } else { + ret = pTiffContext->io.out->ReadBlock(buf, pTiffContext->offset, length); + } + if(!ret) { + return 0; + } + pTiffContext->offset += (FX_DWORD)length; + return length; +} +static tsize_t _tiff_write(thandle_t context, tdata_t buf, tsize_t length) +{ + CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context; + ASSERT(!pTiffContext->isDecoder); + if(!pTiffContext->io.out->WriteBlock(buf, pTiffContext->offset, length)) { + return 0; + } + pTiffContext->offset += (FX_DWORD)length; + return length; +} +static toff_t _tiff_seek(thandle_t context, toff_t offset, int whence) +{ + CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context; + switch(whence) { + case 0: + pTiffContext->offset = (FX_DWORD)offset; + break; + case 1: + pTiffContext->offset += (FX_DWORD)offset; + break; + case 2: + if(pTiffContext->isDecoder) { + if(pTiffContext->io.in->GetSize() < (FX_FILESIZE)offset) { + return -1; + } + pTiffContext->offset = (FX_DWORD)(pTiffContext->io.in->GetSize() - offset); + } else { + if(pTiffContext->io.out->GetSize() < (FX_FILESIZE)offset) { + return -1; + } + pTiffContext->offset = (FX_DWORD)(pTiffContext->io.out->GetSize() - offset); + } + break; + default: + return -1; + } + ASSERT(pTiffContext->isDecoder ? + (pTiffContext->offset <= (FX_DWORD)pTiffContext->io.in->GetSize()) : + TRUE); + return pTiffContext->offset; +} +static int _tiff_close(thandle_t context) +{ + return 0; +} +static toff_t _tiff_get_size(thandle_t context) +{ + CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context; + return pTiffContext->isDecoder ? + (toff_t)pTiffContext->io.in->GetSize() : + (toff_t)pTiffContext->io.out->GetSize(); +} +static int _tiff_map(thandle_t context, tdata_t*, toff_t*) +{ + return 0; +} +static void _tiff_unmap(thandle_t context, tdata_t, toff_t) {} +TIFF* _tiff_open(void* context, const char* mode) +{ + TIFF* tif = TIFFClientOpen("Tiff Image", mode, + (thandle_t)context, + _tiff_read, _tiff_write, _tiff_seek, _tiff_close, + _tiff_get_size, _tiff_map, _tiff_unmap); + if(tif) { + tif->tif_fd = (int)(FX_INTPTR)context; + } + return tif; +} +void* _TIFFmalloc(tmsize_t size) +{ + return FXMEM_DefaultAlloc(size, 0); +} +void _TIFFfree(void* ptr) +{ + FXMEM_DefaultFree(ptr, 0); +} +void* _TIFFrealloc(void* ptr, tmsize_t size) +{ + return FXMEM_DefaultRealloc(ptr, size, 0); +} +void _TIFFmemset(void* ptr, int val, tmsize_t size) +{ + FXSYS_memset8(ptr, val, (size_t)size); +} +void _TIFFmemcpy(void* des, const void* src, tmsize_t size) +{ + FXSYS_memcpy32(des, src, (size_t)size); +} +int _TIFFmemcmp(const void* ptr1, const void* ptr2, tmsize_t size) +{ + return FXSYS_memcmp32(ptr1, ptr2, (size_t)size); +} +static void _tiff_warning_ext(thandle_t context, const char* module, const char* fmt, va_list ap) +{ + if(module != NULL) { + } +} +TIFFErrorHandlerExt _TIFFwarningHandlerExt = _tiff_warning_ext; +static void _tiff_error_ext(thandle_t context, const char* module, const char* fmt, va_list ap) +{ + if(module != NULL) { + } +} +TIFFErrorHandlerExt _TIFFerrorHandlerExt = _tiff_error_ext; +int TIFFCmyk2Rgb(thandle_t context, uint8 c, uint8 m, uint8 y, uint8 k, uint8* r, uint8* g, uint8* b) +{ + if(context == NULL) { + return 0; + } + CCodec_TiffContext* p = (CCodec_TiffContext*)context; +#if !defined(_FPDFAPI_MINI_) + if(p->icc_ctx) { + unsigned char cmyk[4], bgr[3]; + cmyk[0] = c, cmyk[1] = m, cmyk[2] = y, cmyk[3] = k; + IccLib_TranslateImage(p->icc_ctx, bgr, cmyk, 1); + *r = bgr[2], *g = bgr[1], *b = bgr[0]; + } else { +#endif + AdobeCMYK_to_sRGB1(c, m, y, k, *r, *g, *b); +#if !defined(_FPDFAPI_MINI_) + } +#endif + return 1; +} +FX_BOOL CCodec_TiffContext::InitDecoder(IFX_FileRead* file_ptr) +{ + io.in = file_ptr; + tif_ctx = _tiff_open(this, "r"); + if(tif_ctx == NULL) { + return FALSE; + } + return TRUE; +} +void CCodec_TiffContext::GetFrames(FX_INT32& frames) +{ + frames = frame_num = TIFFNumberOfDirectories(tif_ctx); +} +#define TIFF_EXIF_GETINFO(key, T, tag) {\ + T val = (T)0;\ + TIFFGetField(tif_ctx,tag,&val);\ + if (val) {\ + (key) = FX_Alloc(FX_BYTE,sizeof(T));\ + if ((key)) {\ + T* ptr = (T*)(key);\ + *ptr = val;\ + pExif->m_TagVal.SetAt(tag,(key));}}}\ + (key) = NULL; +#define TIFF_EXIF_GETSTRINGINFO(key, tag) {\ + FX_DWORD size = 0;\ + FX_LPBYTE buf = NULL;\ + TIFFGetField(tif_ctx,tag,&size, &buf);\ + if (size && buf) {\ + (key) = FX_Alloc(FX_BYTE,size);\ + if ((key)) {\ + FXSYS_memcpy32((key),buf,size);\ + pExif->m_TagVal.SetAt(tag,(key));}}}\ + (key) = NULL; +template +static FX_BOOL Tiff_Exif_GetInfo(TIFF* tif_ctx, ttag_t tag, CFX_DIBAttributeExif* pExif) +{ + FX_LPBYTE key = NULL; + T val = (T)0; + TIFFGetField(tif_ctx, tag, &val); + if (val) { + (key) = FX_Alloc(FX_BYTE, sizeof(T)); + if ((key) == NULL) { + return FALSE; + } + T* ptr = (T*)(key); + *ptr = val; + pExif->m_TagVal.SetAt(tag, (key)); + return TRUE; + } + return FALSE; +} +static void Tiff_Exif_GetStringInfo(TIFF* tif_ctx, ttag_t tag, CFX_DIBAttributeExif* pExif) +{ + FX_LPSTR buf = NULL; + FX_LPBYTE key = NULL; + TIFFGetField(tif_ctx, tag, &buf); + if (buf) { + FX_INT32 size = (FX_INT32)FXSYS_strlen(buf); + (key) = FX_Alloc(FX_BYTE, size + 1); + if ((key) == NULL) { + return; + } + FXSYS_memcpy32((key), buf, size); + key[size] = 0; + pExif->m_TagVal.SetAt(tag, (key)); + } +} +FX_BOOL CCodec_TiffContext::LoadFrameInfo(FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute) +{ + if (!TIFFSetDirectory(tif_ctx, (uint16)frame)) { + return FALSE; + } + FX_WORD tif_cs; + FX_DWORD tif_icc_size = 0; + FX_LPBYTE tif_icc_buf = NULL; + FX_WORD tif_bpc = 0; + FX_WORD tif_cps; + FX_DWORD tif_rps; + width = height = comps = 0; + TIFFGetField(tif_ctx, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif_ctx, TIFFTAG_IMAGELENGTH, &height); + TIFFGetField(tif_ctx, TIFFTAG_SAMPLESPERPIXEL, &comps); + TIFFGetField(tif_ctx, TIFFTAG_BITSPERSAMPLE, &tif_bpc); + TIFFGetField(tif_ctx, TIFFTAG_PHOTOMETRIC, &tif_cs); + TIFFGetField(tif_ctx, TIFFTAG_COMPRESSION, &tif_cps); + TIFFGetField(tif_ctx, TIFFTAG_ROWSPERSTRIP, &tif_rps); + TIFFGetField(tif_ctx, TIFFTAG_ICCPROFILE, &tif_icc_size, &tif_icc_buf); + if (pAttribute) { + pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_INCH; + if (TIFFGetField(tif_ctx, TIFFTAG_RESOLUTIONUNIT, &pAttribute->m_wDPIUnit)) { + pAttribute->m_wDPIUnit -= 1; + } + CFX_DIBAttributeExif* pExif = (CFX_DIBAttributeExif*)pAttribute->m_pExif; + pExif->clear(); + Tiff_Exif_GetInfo(tif_ctx, TIFFTAG_ORIENTATION, pExif); + if (Tiff_Exif_GetInfo(tif_ctx, TIFFTAG_XRESOLUTION, pExif)) { + FX_FLOAT fDpi = 0; + pExif->GetInfo(TIFFTAG_XRESOLUTION, &fDpi); + pAttribute->m_nXDPI = (FX_INT32)(fDpi + 0.5f); + } + if (Tiff_Exif_GetInfo(tif_ctx, TIFFTAG_YRESOLUTION, pExif)) { + FX_FLOAT fDpi = 0; + pExif->GetInfo(TIFFTAG_YRESOLUTION, &fDpi); + pAttribute->m_nYDPI = (FX_INT32)(fDpi + 0.5f); + } + Tiff_Exif_GetStringInfo(tif_ctx, TIFFTAG_IMAGEDESCRIPTION, pExif); + Tiff_Exif_GetStringInfo(tif_ctx, TIFFTAG_MAKE, pExif); + Tiff_Exif_GetStringInfo(tif_ctx, TIFFTAG_MODEL, pExif); + } + bpc = tif_bpc; + if(tif_rps > height) { + TIFFSetField(tif_ctx, TIFFTAG_ROWSPERSTRIP, tif_rps = height); + } + return TRUE; +} +void _TiffBGRA2RGBA(FX_LPBYTE pBuf, FX_INT32 pixel, FX_INT32 spp) +{ + register FX_BYTE tmp; + for (FX_INT32 n = 0; n < pixel; n++) { + tmp = pBuf[0]; + pBuf[0] = pBuf[2]; + pBuf[2] = tmp; + pBuf += spp; + } +} +FX_BOOL CCodec_TiffContext::isSupport(CFX_DIBitmap* pDIBitmap) +{ + if (TIFFIsTiled(tif_ctx)) { + return FALSE; + } + FX_UINT16 photometric; + if (!TIFFGetField(tif_ctx, TIFFTAG_PHOTOMETRIC, &photometric)) { + return FALSE; + } + switch (pDIBitmap->GetBPP()) { + case 1: + case 8: + if (photometric != PHOTOMETRIC_PALETTE) { + return FALSE; + } + break; + case 24: + if (photometric != PHOTOMETRIC_RGB) { + return FALSE; + } + break; + default: + return FALSE; + } + FX_UINT16 planarconfig; + if (!TIFFGetFieldDefaulted(tif_ctx, TIFFTAG_PLANARCONFIG, &planarconfig)) { + return FALSE; + } + if (planarconfig == PLANARCONFIG_SEPARATE) { + return FALSE; + } + return TRUE; +} +void CCodec_TiffContext::SetPalette(CFX_DIBitmap* pDIBitmap, FX_UINT16 bps) +{ + FX_UINT16 *red_orig, *green_orig, *blue_orig; + TIFFGetField(tif_ctx, TIFFTAG_COLORMAP, &red_orig, &green_orig, &blue_orig); + for (FX_INT32 i = (1L << bps) - 1; i >= 0; i--) { +#define CVT(x) ((FX_UINT16)((x)>>8)) + red_orig[i] = CVT(red_orig[i]); + green_orig[i] = CVT(green_orig[i]); + blue_orig[i] = CVT(blue_orig[i]); +#undef CVT + } + FX_INT32 len = 1 << bps; + for(FX_INT32 index = 0; index < len; index++) { + FX_DWORD r = red_orig[index] & 0xFF; + FX_DWORD g = green_orig[index] & 0xFF; + FX_DWORD b = blue_orig[index] & 0xFF; + FX_DWORD color = (FX_UINT32)b | ((FX_UINT32)g << 8) | ((FX_UINT32)r << 16) | (((uint32)0xffL) << 24); + pDIBitmap->SetPaletteEntry(index, color); + } +} +FX_BOOL CCodec_TiffContext::Decode1bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp) +{ + if (pDIBitmap->GetBPP() != 1 || spp != 1 || bps != 1 || !isSupport(pDIBitmap)) { + return FALSE; + } + SetPalette(pDIBitmap, bps); + FX_INT32 size = (FX_INT32)TIFFScanlineSize(tif_ctx); + FX_LPBYTE buf = (FX_LPBYTE)_TIFFmalloc(size); + if (buf == NULL) { + TIFFError(TIFFFileName(tif_ctx), "No space for scanline buffer"); + return FALSE; + } + FX_LPBYTE bitMapbuffer = (FX_LPBYTE)pDIBitmap->GetBuffer(); + FX_DWORD pitch = pDIBitmap->GetPitch(); + for(FX_INT32 row = 0; row < height; row++) { + TIFFReadScanline(tif_ctx, buf, row, 0); + for(FX_INT32 j = 0; j < size; j++) { + bitMapbuffer[row * pitch + j] = buf[j]; + } + } + _TIFFfree(buf); + return TRUE; +} +FX_BOOL CCodec_TiffContext::Decode8bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp) +{ + if (pDIBitmap->GetBPP() != 8 || spp != 1 || (bps != 4 && bps != 8) || !isSupport(pDIBitmap)) { + return FALSE; + } + SetPalette(pDIBitmap, bps); + FX_INT32 size = (FX_INT32)TIFFScanlineSize(tif_ctx); + FX_LPBYTE buf = (FX_LPBYTE)_TIFFmalloc(size); + if (buf == NULL) { + TIFFError(TIFFFileName(tif_ctx), "No space for scanline buffer"); + return FALSE; + } + FX_LPBYTE bitMapbuffer = (FX_LPBYTE)pDIBitmap->GetBuffer(); + FX_DWORD pitch = pDIBitmap->GetPitch(); + for(FX_INT32 row = 0; row < height; row++) { + TIFFReadScanline(tif_ctx, buf, row, 0); + for(FX_INT32 j = 0; j < size; j++) { + switch(bps) { + case 4: + bitMapbuffer[row * pitch + 2 * j + 0] = (buf[j] & 0xF0) >> 4; + bitMapbuffer[row * pitch + 2 * j + 1] = (buf[j] & 0x0F) >> 0; + break; + case 8: + bitMapbuffer[row * pitch + j] = buf[j]; + break; + } + } + } + _TIFFfree(buf); + return TRUE; +} +FX_BOOL CCodec_TiffContext::Decode24bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp) +{ + if (pDIBitmap->GetBPP() != 24 || !isSupport(pDIBitmap)) { + return FALSE; + } + FX_INT32 size = (FX_INT32)TIFFScanlineSize(tif_ctx); + FX_LPBYTE buf = (FX_LPBYTE)_TIFFmalloc(size); + if (buf == NULL) { + TIFFError(TIFFFileName(tif_ctx), "No space for scanline buffer"); + return FALSE; + } + FX_LPBYTE bitMapbuffer = (FX_LPBYTE)pDIBitmap->GetBuffer(); + FX_DWORD pitch = pDIBitmap->GetPitch(); + for(FX_INT32 row = 0; row < height; row++) { + TIFFReadScanline(tif_ctx, buf, row, 0); + for(FX_INT32 j = 0; j < size - 2; j += 3) { + bitMapbuffer[row * pitch + j + 0] = buf[j + 2]; + bitMapbuffer[row * pitch + j + 1] = buf[j + 1]; + bitMapbuffer[row * pitch + j + 2] = buf[j + 0]; + } + } + _TIFFfree(buf); + return TRUE; +} +FX_BOOL CCodec_TiffContext::Decode(CFX_DIBitmap* pDIBitmap) +{ + FX_DWORD img_wid = pDIBitmap->GetWidth(); + FX_DWORD img_hei = pDIBitmap->GetHeight(); + FX_DWORD width = 0; + FX_DWORD height = 0; + TIFFGetField(tif_ctx, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif_ctx, TIFFTAG_IMAGELENGTH, &height); + if (img_wid != width || img_hei != height) { + return FALSE; + } + if (pDIBitmap->GetBPP() == 32) { + FX_WORD rotation = ORIENTATION_TOPLEFT; + TIFFGetField(tif_ctx, TIFFTAG_ORIENTATION, &rotation); + if(TIFFReadRGBAImageOriented(tif_ctx, img_wid, img_hei, + (uint32*)pDIBitmap->GetBuffer(), rotation, 1)) { + for (FX_DWORD row = 0; row < img_hei; row++) { + FX_LPBYTE row_buf = (FX_LPBYTE)pDIBitmap->GetScanline(row); + _TiffBGRA2RGBA(row_buf, img_wid, 4); + } + return TRUE; + } + } + FX_UINT16 spp, bps; + TIFFGetField(tif_ctx, TIFFTAG_SAMPLESPERPIXEL, &spp); + TIFFGetField(tif_ctx, TIFFTAG_BITSPERSAMPLE, &bps); + FX_DWORD bpp = bps * spp; + if (bpp == 1) { + return Decode1bppRGB(pDIBitmap, height, width, bps, spp); + } else if (bpp <= 8) { + return Decode8bppRGB(pDIBitmap, height, width, bps, spp); + } else if (bpp <= 24) { + return Decode24bppRGB(pDIBitmap, height, width, bps, spp); + } + return FALSE; +} +FX_LPVOID CCodec_TiffModule::CreateDecoder(IFX_FileRead* file_ptr) +{ + CCodec_TiffContext* pDecoder = FX_NEW CCodec_TiffContext; + if (pDecoder == NULL) { + return NULL; + } + if (!pDecoder->InitDecoder(file_ptr)) { + delete pDecoder; + return NULL; + } + return pDecoder; +} +void CCodec_TiffModule::GetFrames(FX_LPVOID ctx, FX_INT32& frames) +{ + CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx; + pDecoder->GetFrames(frames); +} +FX_BOOL CCodec_TiffModule::LoadFrameInfo(FX_LPVOID ctx, FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute) +{ + CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx; + return pDecoder->LoadFrameInfo(frame, width, height, comps, bpc, pAttribute); +} +FX_BOOL CCodec_TiffModule::Decode(void* ctx, class CFX_DIBitmap* pDIBitmap) +{ + CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx; + return pDecoder->Decode(pDIBitmap); +} +void CCodec_TiffModule::DestroyDecoder(void* ctx) +{ + CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx; + delete pDecoder; +} diff --git a/core/src/fxcodec/fx_lpng/include/fx_png.h b/core/src/fxcodec/fx_lpng/include/fx_png.h new file mode 100644 index 0000000000..4ef53d0298 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/include/fx_png.h @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/png.h" diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_png.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_png.c new file mode 100644 index 0000000000..5329a6409d --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_png.c @@ -0,0 +1,4299 @@ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +/* png.c - location for general purpose libpng functions + * + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef png_libpng_version_1_6_3 Your_png_h_is_not_version_1_6_3; + +/* Tells libpng that we have already handled the first "num_bytes" bytes + * of the PNG file signature. If the PNG data is embedded into another + * stream we can set num_bytes = 8 so that libpng will not attempt to read + * or write any of the magic bytes before it starts on the IHDR. + */ + +#ifdef PNG_READ_SUPPORTED +void PNGAPI +png_set_sig_bytes(png_structrp png_ptr, int num_bytes) +{ + png_debug(1, "in png_set_sig_bytes"); + + if (png_ptr == NULL) + return; + + if (num_bytes > 8) + png_error(png_ptr, "Too many bytes for PNG signature"); + + png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); +} + +/* Checks whether the supplied bytes match the PNG signature. We allow + * checking less than the full 8-byte signature so that those apps that + * already read the first few bytes of a file to determine the file type + * can simply check the remaining bytes for extra assurance. Returns + * an integer less than, equal to, or greater than zero if sig is found, + * respectively, to be less than, to match, or be greater than the correct + * PNG signature (this is the same behavior as strcmp, memcmp, etc). + */ +int PNGAPI +png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + + if (num_to_check > 8) + num_to_check = 8; + + else if (num_to_check < 1) + return (-1); + + if (start > 7) + return (-1); + + if (start + num_to_check > 8) + num_to_check = 8 - start; + + return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check))); +} + +#endif /* PNG_READ_SUPPORTED */ + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Function to allocate memory for zlib */ +PNG_FUNCTION(voidpf /* PRIVATE */, +png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED) +{ + png_alloc_size_t num_bytes = size; + + if (png_ptr == NULL) + return NULL; + + if (items >= (~(png_alloc_size_t)0)/size) + { + png_warning (png_voidcast(png_structrp, png_ptr), + "Potential overflow in png_zalloc()"); + return NULL; + } + + num_bytes *= items; + return png_malloc_warn(png_voidcast(png_structrp, png_ptr), num_bytes); +} + +/* Function to free memory for zlib */ +void /* PRIVATE */ +png_zfree(voidpf png_ptr, voidpf ptr) +{ + png_free(png_voidcast(png_const_structrp,png_ptr), ptr); +} + +/* Reset the CRC variable to 32 bits of 1's. Care must be taken + * in case CRC is > 32 bits to leave the top bits 0. + */ +void /* PRIVATE */ +png_reset_crc(png_structrp png_ptr) +{ + /* The cast is safe because the crc is a 32 bit value. */ + png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0); +} + +/* Calculate the CRC over a section of data. We can only pass as + * much data to this routine as the largest single buffer size. We + * also check that this data will actually be used before going to the + * trouble of calculating it. + */ +void /* PRIVATE */ +png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, png_size_t length) +{ + int need_crc = 1; + + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)) + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + + /* 'uLong' is defined in zlib.h as unsigned long; this means that on some + * systems it is a 64 bit value. crc32, however, returns 32 bits so the + * following cast is safe. 'uInt' may be no more than 16 bits, so it is + * necessary to perform a loop here. + */ + if (need_crc && length > 0) + { + uLong crc = png_ptr->crc; /* Should never issue a warning */ + + do + { + uInt safe_length = (uInt)length; + if (safe_length == 0) + safe_length = (uInt)-1; /* evil, but safe */ + + crc = crc32(crc, ptr, safe_length); + + /* The following should never issue compiler warnings; if they do the + * target system has characteristics that will probably violate other + * assumptions within the libpng code. + */ + ptr += safe_length; + length -= safe_length; + } + while (length > 0); + + /* And the following is always safe because the crc is only 32 bits. */ + png_ptr->crc = (png_uint_32)crc; + } +} + +/* Check a user supplied version number, called from both read and write + * functions that create a png_struct. + */ +int +png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver) +{ + if (user_png_ver) + { + int i = 0; + + do + { + if (user_png_ver[i] != png_libpng_ver[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + } while (png_libpng_ver[i++]); + } + + else + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + + if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) + { + /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so + * we must recompile any applications that use any older library version. + * For versions after libpng 1.0, we will be compatible, so we need + * only check the first and third digits (note that when we reach version + * 1.10 we will need to check the fourth symbol, namely user_png_ver[3]). + */ + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || + (user_png_ver[0] == '1' && (user_png_ver[2] != png_libpng_ver[2] || + user_png_ver[3] != png_libpng_ver[3])) || + (user_png_ver[0] == '0' && user_png_ver[2] < '9')) + { +#ifdef PNG_WARNINGS_SUPPORTED + size_t pos = 0; + char m[128]; + + pos = png_safecat(m, (sizeof m), pos, + "Application built with libpng-"); + pos = png_safecat(m, (sizeof m), pos, user_png_ver); + pos = png_safecat(m, (sizeof m), pos, " but running with "); + pos = png_safecat(m, (sizeof m), pos, png_libpng_ver); + + png_warning(png_ptr, m); +#endif + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + + return 0; + } + } + + /* Success return. */ + return 1; +} + +/* Generic function to create a png_struct for either read or write - this + * contains the common initialization. + */ +PNG_FUNCTION(png_structp /* PRIVATE */, +png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) +{ + png_struct create_struct; +# ifdef PNG_SETJMP_SUPPORTED + jmp_buf create_jmp_buf; +# endif + + /* This temporary stack-allocated structure is used to provide a place to + * build enough context to allow the user provided memory allocator (if any) + * to be called. + */ + memset(&create_struct, 0, (sizeof create_struct)); + + /* Added at libpng-1.2.6 */ +# ifdef PNG_USER_LIMITS_SUPPORTED + create_struct.user_width_max = PNG_USER_WIDTH_MAX; + create_struct.user_height_max = PNG_USER_HEIGHT_MAX; + +# ifdef PNG_USER_CHUNK_CACHE_MAX + /* Added at libpng-1.2.43 and 1.4.0 */ + create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; +# endif + +# ifdef PNG_USER_CHUNK_MALLOC_MAX + /* Added at libpng-1.2.43 and 1.4.1, required only for read but exists + * in png_struct regardless. + */ + create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; +# endif +# endif + + /* The following two API calls simply set fields in png_struct, so it is safe + * to do them now even though error handling is not yet set up. + */ +# ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn); +# endif + + /* (*error_fn) can return control to the caller after the error_ptr is set, + * this will result in a memory leak unless the error_fn does something + * extremely sophisticated. The design lacks merit but is implicit in the + * API. + */ + png_set_error_fn(&create_struct, error_ptr, error_fn, warn_fn); + +# ifdef PNG_SETJMP_SUPPORTED + if (!setjmp(create_jmp_buf)) + { + /* Temporarily fake out the longjmp information until we have + * successfully completed this function. This only works if we have + * setjmp() support compiled in, but it is safe - this stuff should + * never happen. + */ + create_struct.jmp_buf_ptr = &create_jmp_buf; + create_struct.jmp_buf_size = 0; /*stack allocation*/ + create_struct.longjmp_fn = longjmp; +# else + { +# endif + /* Call the general version checker (shared with read and write code): + */ + if (png_user_version_check(&create_struct, user_png_ver)) + { + png_structrp png_ptr = png_voidcast(png_structrp, + png_malloc_warn(&create_struct, (sizeof *png_ptr))); + + if (png_ptr != NULL) + { + /* png_ptr->zstream holds a back-pointer to the png_struct, so + * this can only be done now: + */ + create_struct.zstream.zalloc = png_zalloc; + create_struct.zstream.zfree = png_zfree; + create_struct.zstream.opaque = png_ptr; + +# ifdef PNG_SETJMP_SUPPORTED + /* Eliminate the local error handling: */ + create_struct.jmp_buf_ptr = NULL; + create_struct.jmp_buf_size = 0; + create_struct.longjmp_fn = 0; +# endif + + *png_ptr = create_struct; + + /* This is the successful return point */ + return png_ptr; + } + } + } + + /* A longjmp because of a bug in the application storage allocator or a + * simple failure to allocate the png_struct. + */ + return NULL; +} + +/* Allocate the memory for an info_struct for the application. */ +PNG_FUNCTION(png_infop,PNGAPI +png_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED) +{ + png_inforp info_ptr; + + png_debug(1, "in png_create_info_struct"); + + if (png_ptr == NULL) + return NULL; + + /* Use the internal API that does not (or at least should not) error out, so + * that this call always returns ok. The application typically sets up the + * error handling *after* creating the info_struct because this is the way it + * has always been done in 'example.c'. + */ + info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr, + (sizeof *info_ptr))); + + if (info_ptr != NULL) + memset(info_ptr, 0, (sizeof *info_ptr)); + + return info_ptr; +} + +/* This function frees the memory associated with a single info struct. + * Normally, one would use either png_destroy_read_struct() or + * png_destroy_write_struct() to free an info struct, but this may be + * useful for some applications. From libpng 1.6.0 this function is also used + * internally to implement the png_info release part of the 'struct' destroy + * APIs. This ensures that all possible approaches free the same data (all of + * it). + */ +void PNGAPI +png_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr) +{ + png_inforp info_ptr = NULL; + + png_debug(1, "in png_destroy_info_struct"); + + if (png_ptr == NULL) + return; + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (info_ptr != NULL) + { + /* Do this first in case of an error below; if the app implements its own + * memory management this can lead to png_free calling png_error, which + * will abort this routine and return control to the app error handler. + * An infinite loop may result if it then tries to free the same info + * ptr. + */ + *info_ptr_ptr = NULL; + + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + memset(info_ptr, 0, (sizeof *info_ptr)); + png_free(png_ptr, info_ptr); + } +} + +/* Initialize the info structure. This is now an internal function (0.89) + * and applications using it are urged to use png_create_info_struct() + * instead. Use deprecated in 1.6.0, internal use removed (used internally it + * is just a memset). + * + * NOTE: it is almost inconceivable that this API is used because it bypasses + * the user-memory mechanism and the user error handling/warning mechanisms in + * those cases where it does anything other than a memset. + */ +PNG_FUNCTION(void,PNGAPI +png_info_init_3,(png_infopp ptr_ptr, png_size_t png_info_struct_size), + PNG_DEPRECATED) +{ + png_inforp info_ptr = *ptr_ptr; + + png_debug(1, "in png_info_init_3"); + + if (info_ptr == NULL) + return; + + if ((sizeof (png_info)) > png_info_struct_size) + { + *ptr_ptr = NULL; + /* The following line is why this API should not be used: */ + free(info_ptr); + info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL, + (sizeof *info_ptr))); + *ptr_ptr = info_ptr; + } + + /* Set everything to 0 */ + memset(info_ptr, 0, (sizeof *info_ptr)); +} + +/* The following API is not called internally */ +void PNGAPI +png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr, + int freer, png_uint_32 mask) +{ + png_debug(1, "in png_data_freer"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (freer == PNG_DESTROY_WILL_FREE_DATA) + info_ptr->free_me |= mask; + + else if (freer == PNG_USER_WILL_FREE_DATA) + info_ptr->free_me &= ~mask; + + else + png_error(png_ptr, "Unknown freer parameter in png_data_freer"); +} + +void PNGAPI +png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, + int num) +{ + png_debug(1, "in png_free_data"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + +#ifdef PNG_TEXT_SUPPORTED + /* Free text item num or (if num == -1) all text items */ + if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) + { + if (num != -1) + { + if (info_ptr->text && info_ptr->text[num].key) + { + png_free(png_ptr, info_ptr->text[num].key); + info_ptr->text[num].key = NULL; + } + } + + else + { + int i; + for (i = 0; i < info_ptr->num_text; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); + png_free(png_ptr, info_ptr->text); + info_ptr->text = NULL; + info_ptr->num_text=0; + } + } +#endif + +#ifdef PNG_tRNS_SUPPORTED + /* Free any tRNS entry */ + if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) + { + png_free(png_ptr, info_ptr->trans_alpha); + info_ptr->trans_alpha = NULL; + info_ptr->valid &= ~PNG_INFO_tRNS; + } +#endif + +#ifdef PNG_sCAL_SUPPORTED + /* Free any sCAL entry */ + if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) + { + png_free(png_ptr, info_ptr->scal_s_width); + png_free(png_ptr, info_ptr->scal_s_height); + info_ptr->scal_s_width = NULL; + info_ptr->scal_s_height = NULL; + info_ptr->valid &= ~PNG_INFO_sCAL; + } +#endif + +#ifdef PNG_pCAL_SUPPORTED + /* Free any pCAL entry */ + if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) + { + png_free(png_ptr, info_ptr->pcal_purpose); + png_free(png_ptr, info_ptr->pcal_units); + info_ptr->pcal_purpose = NULL; + info_ptr->pcal_units = NULL; + if (info_ptr->pcal_params != NULL) + { + unsigned int i; + for (i = 0; i < info_ptr->pcal_nparams; i++) + { + png_free(png_ptr, info_ptr->pcal_params[i]); + info_ptr->pcal_params[i] = NULL; + } + png_free(png_ptr, info_ptr->pcal_params); + info_ptr->pcal_params = NULL; + } + info_ptr->valid &= ~PNG_INFO_pCAL; + } +#endif + +#ifdef PNG_iCCP_SUPPORTED + /* Free any profile entry */ + if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) + { + png_free(png_ptr, info_ptr->iccp_name); + png_free(png_ptr, info_ptr->iccp_profile); + info_ptr->iccp_name = NULL; + info_ptr->iccp_profile = NULL; + info_ptr->valid &= ~PNG_INFO_iCCP; + } +#endif + +#ifdef PNG_sPLT_SUPPORTED + /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ + if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) + { + if (num != -1) + { + if (info_ptr->splt_palettes) + { + png_free(png_ptr, info_ptr->splt_palettes[num].name); + png_free(png_ptr, info_ptr->splt_palettes[num].entries); + info_ptr->splt_palettes[num].name = NULL; + info_ptr->splt_palettes[num].entries = NULL; + } + } + + else + { + if (info_ptr->splt_palettes_num) + { + int i; + for (i = 0; i < info_ptr->splt_palettes_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, (int)i); + + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = NULL; + info_ptr->splt_palettes_num = 0; + } + info_ptr->valid &= ~PNG_INFO_sPLT; + } + } +#endif + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) + { + if (num != -1) + { + if (info_ptr->unknown_chunks) + { + png_free(png_ptr, info_ptr->unknown_chunks[num].data); + info_ptr->unknown_chunks[num].data = NULL; + } + } + + else + { + int i; + + if (info_ptr->unknown_chunks_num) + { + for (i = 0; i < info_ptr->unknown_chunks_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, (int)i); + + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks_num = 0; + } + } + } +#endif + +#ifdef PNG_hIST_SUPPORTED + /* Free any hIST entry */ + if ((mask & PNG_FREE_HIST) & info_ptr->free_me) + { + png_free(png_ptr, info_ptr->hist); + info_ptr->hist = NULL; + info_ptr->valid &= ~PNG_INFO_hIST; + } +#endif + + /* Free any PLTE entry that was internally allocated */ + if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) + { + png_free(png_ptr, info_ptr->palette); + info_ptr->palette = NULL; + info_ptr->valid &= ~PNG_INFO_PLTE; + info_ptr->num_palette = 0; + } + +#ifdef PNG_INFO_IMAGE_SUPPORTED + /* Free any image bits attached to the info structure */ + if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) + { + if (info_ptr->row_pointers) + { + png_uint_32 row; + for (row = 0; row < info_ptr->height; row++) + { + png_free(png_ptr, info_ptr->row_pointers[row]); + info_ptr->row_pointers[row] = NULL; + } + png_free(png_ptr, info_ptr->row_pointers); + info_ptr->row_pointers = NULL; + } + info_ptr->valid &= ~PNG_INFO_IDAT; + } +#endif + + if (num != -1) + mask &= ~PNG_FREE_MUL; + + info_ptr->free_me &= ~mask; +} +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +/* This function returns a pointer to the io_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy() or png_read_destroy() are called. + */ +png_voidp PNGAPI +png_get_io_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + + return (png_ptr->io_ptr); +} + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +# ifdef PNG_STDIO_SUPPORTED +/* Initialize the default input/output functions for the PNG file. If you + * use your own read or write routines, you can call either png_set_read_fn() + * or png_set_write_fn() instead of png_init_io(). If you have defined + * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a + * function of your own because "FILE *" isn't necessarily available. + */ +void PNGAPI +png_init_io(png_structrp png_ptr, png_FILE_p fp) +{ + png_debug(1, "in png_init_io"); + + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = (png_voidp)fp; +} +# endif + +#ifdef PNG_SAVE_INT_32_SUPPORTED +/* The png_save_int_32 function assumes integers are stored in two's + * complement format. If this isn't the case, then this routine needs to + * be modified to write data in two's complement format. Note that, + * the following works correctly even if png_int_32 has more than 32 bits + * (compare the more complex code required on read for sign extension.) + */ +void PNGAPI +png_save_int_32(png_bytep buf, png_int_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); +} +#endif + +# ifdef PNG_TIME_RFC1123_SUPPORTED +/* Convert the supplied time into an RFC 1123 string suitable for use in + * a "Creation Time" or other text-based time string. + */ +int PNGAPI +png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime) +{ + static PNG_CONST char short_months[12][4] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + if (out == NULL) + return 0; + + if (ptime->year > 9999 /* RFC1123 limitation */ || + ptime->month == 0 || ptime->month > 12 || + ptime->day == 0 || ptime->day > 31 || + ptime->hour > 23 || ptime->minute > 59 || + ptime->second > 60) + return 0; + + { + size_t pos = 0; + char number_buf[5]; /* enough for a four-digit year */ + +# define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string)) +# define APPEND_NUMBER(format, value)\ + APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value))) +# define APPEND(ch) if (pos < 28) out[pos++] = (ch) + + APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day); + APPEND(' '); + APPEND_STRING(short_months[(ptime->month - 1)]); + APPEND(' '); + APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year); + APPEND(' '); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour); + APPEND(':'); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute); + APPEND(':'); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second); + APPEND_STRING(" +0000"); /* This reliably terminates the buffer */ + +# undef APPEND +# undef APPEND_NUMBER +# undef APPEND_STRING + } + + return 1; +} + +# if PNG_LIBPNG_VER < 10700 +/* To do: remove the following from libpng-1.7 */ +/* Original API that uses a private buffer in png_struct. + * Deprecated because it causes png_struct to carry a spurious temporary + * buffer (png_struct::time_buffer), better to have the caller pass this in. + */ +png_const_charp PNGAPI +png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime) +{ + if (png_ptr != NULL) + { + /* The only failure above if png_ptr != NULL is from an invalid ptime */ + if (!png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime)) + png_warning(png_ptr, "Ignoring invalid time value"); + + else + return png_ptr->time_buffer; + } + + return NULL; +} +# endif +# endif /* PNG_TIME_RFC1123_SUPPORTED */ + +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +png_const_charp PNGAPI +png_get_copyright(png_const_structrp png_ptr) +{ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ +#ifdef PNG_STRING_COPYRIGHT + return PNG_STRING_COPYRIGHT +#else +# ifdef __STDC__ + return PNG_STRING_NEWLINE \ + "libpng version 1.6.3 - July 18, 2013" PNG_STRING_NEWLINE \ + "Copyright (c) 1998-2013 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ + "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ + "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ + PNG_STRING_NEWLINE; +# else + return "libpng version 1.6.3 - July 18, 2013\ + Copyright (c) 1998-2013 Glenn Randers-Pehrson\ + Copyright (c) 1996-1997 Andreas Dilger\ + Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."; +# endif +#endif +} + +/* The following return the library version as a short string in the + * format 1.0.0 through 99.99.99zz. To get the version of *.h files + * used with your application, print out PNG_LIBPNG_VER_STRING, which + * is defined in png.h. + * Note: now there is no difference between png_get_libpng_ver() and + * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, + * it is guaranteed that png.c uses the correct version of png.h. + */ +png_const_charp PNGAPI +png_get_libpng_ver(png_const_structrp png_ptr) +{ + /* Version of *.c files used when building libpng */ + return png_get_header_ver(png_ptr); +} + +png_const_charp PNGAPI +png_get_header_ver(png_const_structrp png_ptr) +{ + /* Version of *.h files used when building libpng */ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ + return PNG_LIBPNG_VER_STRING; +} + +png_const_charp PNGAPI +png_get_header_version(png_const_structrp png_ptr) +{ + /* Returns longer string containing both version and date */ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ +#ifdef __STDC__ + return PNG_HEADER_VERSION_STRING +# ifndef PNG_READ_SUPPORTED + " (NO READ SUPPORT)" +# endif + PNG_STRING_NEWLINE; +#else + return PNG_HEADER_VERSION_STRING; +#endif +} + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +int PNGAPI +png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name) +{ + /* Check chunk_name and return "keep" value if it's on the list, else 0 */ + png_const_bytep p, p_end; + + if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list == 0) + return PNG_HANDLE_CHUNK_AS_DEFAULT; + + p_end = png_ptr->chunk_list; + p = p_end + png_ptr->num_chunk_list*5; /* beyond end */ + + /* The code is the fifth byte after each four byte string. Historically this + * code was always searched from the end of the list, this is no longer + * necessary because the 'set' routine handles duplicate entries correcty. + */ + do /* num_chunk_list > 0, so at least one */ + { + p -= 5; + + if (!memcmp(chunk_name, p, 4)) + return p[4]; + } + while (p > p_end); + + /* This means that known chunks should be processed and unknown chunks should + * be handled according to the value of png_ptr->unknown_default; this can be + * confusing because, as a result, there are two levels of defaulting for + * unknown chunks. + */ + return PNG_HANDLE_CHUNK_AS_DEFAULT; +} + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +int /* PRIVATE */ +png_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name) +{ + png_byte chunk_string[5]; + + PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name); + return png_handle_as_unknown(png_ptr, chunk_string); +} +#endif /* READ_UNKNOWN_CHUNKS */ +#endif /* SET_UNKNOWN_CHUNKS */ + +#ifdef PNG_READ_SUPPORTED +/* This function, added to libpng-1.0.6g, is untested. */ +int PNGAPI +png_reset_zstream(png_structrp png_ptr) +{ + if (png_ptr == NULL) + return Z_STREAM_ERROR; + + /* WARNING: this resets the window bits to the maximum! */ + return (inflateReset(&png_ptr->zstream)); +} +#endif /* PNG_READ_SUPPORTED */ + +/* This function was added to libpng-1.0.7 */ +png_uint_32 PNGAPI +png_access_version_number(void) +{ + /* Version of *.c files used when building libpng */ + return((png_uint_32)PNG_LIBPNG_VER); +} + + + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Ensure that png_ptr->zstream.msg holds some appropriate error message string. + * If it doesn't 'ret' is used to set it to something appropriate, even in cases + * like Z_OK or Z_STREAM_END where the error code is apparently a success code. + */ +void /* PRIVATE */ +png_zstream_error(png_structrp png_ptr, int ret) +{ + /* Translate 'ret' into an appropriate error string, priority is given to the + * one in zstream if set. This always returns a string, even in cases like + * Z_OK or Z_STREAM_END where the error code is a success code. + */ + if (png_ptr->zstream.msg == NULL) switch (ret) + { + default: + case Z_OK: + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code"); + break; + + case Z_STREAM_END: + /* Normal exit */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected end of LZ stream"); + break; + + case Z_NEED_DICT: + /* This means the deflate stream did not have a dictionary; this + * indicates a bogus PNG. + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary"); + break; + + case Z_ERRNO: + /* gz APIs only: should not happen */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("zlib IO error"); + break; + + case Z_STREAM_ERROR: + /* internal libpng error */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("bad parameters to zlib"); + break; + + case Z_DATA_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream"); + break; + + case Z_MEM_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory"); + break; + + case Z_BUF_ERROR: + /* End of input or output; not a problem if the caller is doing + * incremental read or write. + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated"); + break; + + case Z_VERSION_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version"); + break; + + case PNG_UNEXPECTED_ZLIB_RETURN: + /* Compile errors here mean that zlib now uses the value co-opted in + * pngpriv.h for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above + * and change pngpriv.h. Note that this message is "... return", + * whereas the default/Z_OK one is "... return code". + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return"); + break; + } +} + +/* png_convert_size: a PNGAPI but no longer in png.h, so deleted + * at libpng 1.5.5! + */ + +/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ +#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */ +static int +png_colorspace_check_gamma(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA, int from) + /* This is called to check a new gamma value against an existing one. The + * routine returns false if the new gamma value should not be written. + * + * 'from' says where the new gamma value comes from: + * + * 0: the new gamma value is the libpng estimate for an ICC profile + * 1: the new gamma value comes from a gAMA chunk + * 2: the new gamma value comes from an sRGB chunk + */ +{ + png_fixed_point gtest; + + if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && + (!png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) || + png_gamma_significant(gtest))) + { + /* Either this is an sRGB image, in which case the calculated gamma + * approximation should match, or this is an image with a profile and the + * value libpng calculates for the gamma of the profile does not match the + * value recorded in the file. The former, sRGB, case is an error, the + * latter is just a warning. + */ + if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2) + { + png_chunk_report(png_ptr, "gamma value does not match sRGB", + PNG_CHUNK_ERROR); + /* Do not overwrite an sRGB value */ + return from == 2; + } + + else /* sRGB tag not involved */ + { + png_chunk_report(png_ptr, "gamma value does not match libpng estimate", + PNG_CHUNK_WARNING); + return from == 1; + } + } + + return 1; +} + +void /* PRIVATE */ +png_colorspace_set_gamma(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA) +{ + /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't + * occur. Since the fixed point representation is assymetrical it is + * possible for 1/gamma to overflow the limit of 21474 and this means the + * gamma value must be at least 5/100000 and hence at most 20000.0. For + * safety the limits here are a little narrower. The values are 0.00016 to + * 6250.0, which are truly ridiculous gamma values (and will produce + * displays that are all black or all white.) + * + * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk + * handling code, which only required the value to be >0. + */ + png_const_charp errmsg; + + if (gAMA < 16 || gAMA > 625000000) + errmsg = "gamma value out of range"; + +# ifdef PNG_READ_gAMA_SUPPORTED + /* Allow the application to set the gamma value more than once */ + else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0) + errmsg = "duplicate"; +# endif + + /* Do nothing if the colorspace is already invalid */ + else if (colorspace->flags & PNG_COLORSPACE_INVALID) + return; + + else + { + if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA, 1/*from gAMA*/)) + { + /* Store this gamma value. */ + colorspace->gamma = gAMA; + colorspace->flags |= + (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA); + } + + /* At present if the check_gamma test fails the gamma of the colorspace is + * not updated however the colorspace is not invalidated. This + * corresponds to the case where the existing gamma comes from an sRGB + * chunk or profile. An error message has already been output. + */ + return; + } + + /* Error exit - errmsg has been set. */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR); +} + +void /* PRIVATE */ +png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr) +{ + if (info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) + { + /* Everything is invalid */ + info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB| + PNG_INFO_iCCP); + +# ifdef PNG_COLORSPACE_SUPPORTED + /* Clean up the iCCP profile now if it won't be used. */ + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/); +# else + PNG_UNUSED(png_ptr) +# endif + } + + else + { +# ifdef PNG_COLORSPACE_SUPPORTED + /* Leave the INFO_iCCP flag set if the pngset.c code has already set + * it; this allows a PNG to contain a profile which matches sRGB and + * yet still have that profile retrievable by the application. + */ + if (info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) + info_ptr->valid |= PNG_INFO_sRGB; + + else + info_ptr->valid &= ~PNG_INFO_sRGB; + + if (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) + info_ptr->valid |= PNG_INFO_cHRM; + + else + info_ptr->valid &= ~PNG_INFO_cHRM; +# endif + + if (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) + info_ptr->valid |= PNG_INFO_gAMA; + + else + info_ptr->valid &= ~PNG_INFO_gAMA; + } +} + +#ifdef PNG_READ_SUPPORTED +void /* PRIVATE */ +png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr) +{ + if (info_ptr == NULL) /* reduce code size; check here not in the caller */ + return; + + info_ptr->colorspace = png_ptr->colorspace; + png_colorspace_sync_info(png_ptr, info_ptr); +} +#endif +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED +/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for + * cHRM, as opposed to using chromaticities. These internal APIs return + * non-zero on a parameter error. The X, Y and Z values are required to be + * positive and less than 1.0. + */ +static int +png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ) +{ + png_int_32 d, dwhite, whiteX, whiteY; + + d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z; + if (!png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d)) return 1; + if (!png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d)) return 1; + dwhite = d; + whiteX = XYZ->red_X; + whiteY = XYZ->red_Y; + + d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z; + if (!png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d)) return 1; + if (!png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d)) return 1; + dwhite += d; + whiteX += XYZ->green_X; + whiteY += XYZ->green_Y; + + d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z; + if (!png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d)) return 1; + if (!png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d)) return 1; + dwhite += d; + whiteX += XYZ->blue_X; + whiteY += XYZ->blue_Y; + + /* The reference white is simply the sum of the end-point (X,Y,Z) vectors, + * thus: + */ + if (!png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite)) return 1; + if (!png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite)) return 1; + + return 0; +} + +static int +png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) +{ + png_fixed_point red_inverse, green_inverse, blue_scale; + png_fixed_point left, right, denominator; + + /* Check xy and, implicitly, z. Note that wide gamut color spaces typically + * have end points with 0 tristimulus values (these are impossible end + * points, but they are used to cover the possible colors.) + */ + if (xy->redx < 0 || xy->redx > PNG_FP_1) return 1; + if (xy->redy < 0 || xy->redy > PNG_FP_1-xy->redx) return 1; + if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1; + if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1; + if (xy->bluex < 0 || xy->bluex > PNG_FP_1) return 1; + if (xy->bluey < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1; + if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1; + if (xy->whitey < 0 || xy->whitey > PNG_FP_1-xy->whitex) return 1; + + /* The reverse calculation is more difficult because the original tristimulus + * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8 + * derived values were recorded in the cHRM chunk; + * (red,green,blue,white)x(x,y). This loses one degree of freedom and + * therefore an arbitrary ninth value has to be introduced to undo the + * original transformations. + * + * Think of the original end-points as points in (X,Y,Z) space. The + * chromaticity values (c) have the property: + * + * C + * c = --------- + * X + Y + Z + * + * For each c (x,y,z) from the corresponding original C (X,Y,Z). Thus the + * three chromaticity values (x,y,z) for each end-point obey the + * relationship: + * + * x + y + z = 1 + * + * This describes the plane in (X,Y,Z) space that intersects each axis at the + * value 1.0; call this the chromaticity plane. Thus the chromaticity + * calculation has scaled each end-point so that it is on the x+y+z=1 plane + * and chromaticity is the intersection of the vector from the origin to the + * (X,Y,Z) value with the chromaticity plane. + * + * To fully invert the chromaticity calculation we would need the three + * end-point scale factors, (red-scale, green-scale, blue-scale), but these + * were not recorded. Instead we calculated the reference white (X,Y,Z) and + * recorded the chromaticity of this. The reference white (X,Y,Z) would have + * given all three of the scale factors since: + * + * color-C = color-c * color-scale + * white-C = red-C + green-C + blue-C + * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale + * + * But cHRM records only white-x and white-y, so we have lost the white scale + * factor: + * + * white-C = white-c*white-scale + * + * To handle this the inverse transformation makes an arbitrary assumption + * about white-scale: + * + * Assume: white-Y = 1.0 + * Hence: white-scale = 1/white-y + * Or: red-Y + green-Y + blue-Y = 1.0 + * + * Notice the last statement of the assumption gives an equation in three of + * the nine values we want to calculate. 8 more equations come from the + * above routine as summarised at the top above (the chromaticity + * calculation): + * + * Given: color-x = color-X / (color-X + color-Y + color-Z) + * Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0 + * + * This is 9 simultaneous equations in the 9 variables "color-C" and can be + * solved by Cramer's rule. Cramer's rule requires calculating 10 9x9 matrix + * determinants, however this is not as bad as it seems because only 28 of + * the total of 90 terms in the various matrices are non-zero. Nevertheless + * Cramer's rule is notoriously numerically unstable because the determinant + * calculation involves the difference of large, but similar, numbers. It is + * difficult to be sure that the calculation is stable for real world values + * and it is certain that it becomes unstable where the end points are close + * together. + * + * So this code uses the perhaps slightly less optimal but more + * understandable and totally obvious approach of calculating color-scale. + * + * This algorithm depends on the precision in white-scale and that is + * (1/white-y), so we can immediately see that as white-y approaches 0 the + * accuracy inherent in the cHRM chunk drops off substantially. + * + * libpng arithmetic: a simple invertion of the above equations + * ------------------------------------------------------------ + * + * white_scale = 1/white-y + * white-X = white-x * white-scale + * white-Y = 1.0 + * white-Z = (1 - white-x - white-y) * white_scale + * + * white-C = red-C + green-C + blue-C + * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale + * + * This gives us three equations in (red-scale,green-scale,blue-scale) where + * all the coefficients are now known: + * + * red-x*red-scale + green-x*green-scale + blue-x*blue-scale + * = white-x/white-y + * red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1 + * red-z*red-scale + green-z*green-scale + blue-z*blue-scale + * = (1 - white-x - white-y)/white-y + * + * In the last equation color-z is (1 - color-x - color-y) so we can add all + * three equations together to get an alternative third: + * + * red-scale + green-scale + blue-scale = 1/white-y = white-scale + * + * So now we have a Cramer's rule solution where the determinants are just + * 3x3 - far more tractible. Unfortunately 3x3 determinants still involve + * multiplication of three coefficients so we can't guarantee to avoid + * overflow in the libpng fixed point representation. Using Cramer's rule in + * floating point is probably a good choice here, but it's not an option for + * fixed point. Instead proceed to simplify the first two equations by + * eliminating what is likely to be the largest value, blue-scale: + * + * blue-scale = white-scale - red-scale - green-scale + * + * Hence: + * + * (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale = + * (white-x - blue-x)*white-scale + * + * (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale = + * 1 - blue-y*white-scale + * + * And now we can trivially solve for (red-scale,green-scale): + * + * green-scale = + * (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale + * ----------------------------------------------------------- + * green-x - blue-x + * + * red-scale = + * 1 - blue-y*white-scale - (green-y - blue-y) * green-scale + * --------------------------------------------------------- + * red-y - blue-y + * + * Hence: + * + * red-scale = + * ( (green-x - blue-x) * (white-y - blue-y) - + * (green-y - blue-y) * (white-x - blue-x) ) / white-y + * ------------------------------------------------------------------------- + * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) + * + * green-scale = + * ( (red-y - blue-y) * (white-x - blue-x) - + * (red-x - blue-x) * (white-y - blue-y) ) / white-y + * ------------------------------------------------------------------------- + * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) + * + * Accuracy: + * The input values have 5 decimal digits of accuracy. The values are all in + * the range 0 < value < 1, so simple products are in the same range but may + * need up to 10 decimal digits to preserve the original precision and avoid + * underflow. Because we are using a 32-bit signed representation we cannot + * match this; the best is a little over 9 decimal digits, less than 10. + * + * The approach used here is to preserve the maximum precision within the + * signed representation. Because the red-scale calculation above uses the + * difference between two products of values that must be in the range -1..+1 + * it is sufficient to divide the product by 7; ceil(100,000/32767*2). The + * factor is irrelevant in the calculation because it is applied to both + * numerator and denominator. + * + * Note that the values of the differences of the products of the + * chromaticities in the above equations tend to be small, for example for + * the sRGB chromaticities they are: + * + * red numerator: -0.04751 + * green numerator: -0.08788 + * denominator: -0.2241 (without white-y multiplication) + * + * The resultant Y coefficients from the chromaticities of some widely used + * color space definitions are (to 15 decimal places): + * + * sRGB + * 0.212639005871510 0.715168678767756 0.072192315360734 + * Kodak ProPhoto + * 0.288071128229293 0.711843217810102 0.000085653960605 + * Adobe RGB + * 0.297344975250536 0.627363566255466 0.075291458493998 + * Adobe Wide Gamut RGB + * 0.258728243040113 0.724682314948566 0.016589442011321 + */ + /* By the argument, above overflow should be impossible here. The return + * value of 2 indicates an internal error to the caller. + */ + if (!png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7)) + return 2; + if (!png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7)) + return 2; + denominator = left - right; + + /* Now find the red numerator. */ + if (!png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7)) + return 2; + if (!png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7)) + return 2; + + /* Overflow is possible here and it indicates an extreme set of PNG cHRM + * chunk values. This calculation actually returns the reciprocal of the + * scale value because this allows us to delay the multiplication of white-y + * into the denominator, which tends to produce a small number. + */ + if (!png_muldiv(&red_inverse, xy->whitey, denominator, left-right) || + red_inverse <= xy->whitey /* r+g+b scales = white scale */) + return 1; + + /* Similarly for green_inverse: */ + if (!png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7)) + return 2; + if (!png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7)) + return 2; + if (!png_muldiv(&green_inverse, xy->whitey, denominator, left-right) || + green_inverse <= xy->whitey) + return 1; + + /* And the blue scale, the checks above guarantee this can't overflow but it + * can still produce 0 for extreme cHRM values. + */ + blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) - + png_reciprocal(green_inverse); + if (blue_scale <= 0) return 1; + + + /* And fill in the png_XYZ: */ + if (!png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse)) return 1; + if (!png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse)) return 1; + if (!png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1, + red_inverse)) + return 1; + + if (!png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse)) + return 1; + if (!png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse)) + return 1; + if (!png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1, + green_inverse)) + return 1; + + if (!png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1)) return 1; + if (!png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1)) return 1; + if (!png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale, + PNG_FP_1)) + return 1; + + return 0; /*success*/ +} + +static int +png_XYZ_normalize(png_XYZ *XYZ) +{ + png_int_32 Y; + + if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 || + XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 || + XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0) + return 1; + + /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. + * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore + * relying on addition of two positive values producing a negative one is not + * safe. + */ + Y = XYZ->red_Y; + if (0x7fffffff - Y < XYZ->green_X) return 1; + Y += XYZ->green_Y; + if (0x7fffffff - Y < XYZ->blue_X) return 1; + Y += XYZ->blue_Y; + + if (Y != PNG_FP_1) + { + if (!png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y)) return 1; + + if (!png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y)) return 1; + + if (!png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y)) return 1; + } + + return 0; +} + +static int +png_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta) +{ + /* Allow an error of +/-0.01 (absolute value) on each chromaticity */ + return !(PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) || + PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) || + PNG_OUT_OF_RANGE(xy1->redx, xy2->redx, delta) || + PNG_OUT_OF_RANGE(xy1->redy, xy2->redy, delta) || + PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) || + PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) || + PNG_OUT_OF_RANGE(xy1->bluex, xy2->bluex, delta) || + PNG_OUT_OF_RANGE(xy1->bluey, xy2->bluey, delta)); +} + +/* Added in libpng-1.6.0, a different check for the validity of a set of cHRM + * chunk chromaticities. Earlier checks used to simply look for the overflow + * condition (where the determinant of the matrix to solve for XYZ ends up zero + * because the chromaticity values are not all distinct.) Despite this it is + * theoretically possible to produce chromaticities that are apparently valid + * but that rapidly degrade to invalid, potentially crashing, sets because of + * arithmetic inaccuracies when calculations are performed on them. The new + * check is to round-trip xy -> XYZ -> xy and then check that the result is + * within a small percentage of the original. + */ +static int +png_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy) +{ + int result; + png_xy xy_test; + + /* As a side-effect this routine also returns the XYZ endpoints. */ + result = png_XYZ_from_xy(XYZ, xy); + if (result) return result; + + result = png_xy_from_XYZ(&xy_test, XYZ); + if (result) return result; + + if (png_colorspace_endpoints_match(xy, &xy_test, + 5/*actually, the math is pretty accurate*/)) + return 0; + + /* Too much slip */ + return 1; +} + +/* This is the check going the other way. The XYZ is modified to normalize it + * (another side-effect) and the xy chromaticities are returned. + */ +static int +png_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ) +{ + int result; + png_XYZ XYZtemp; + + result = png_XYZ_normalize(XYZ); + if (result) return result; + + result = png_xy_from_XYZ(xy, XYZ); + if (result) return result; + + XYZtemp = *XYZ; + return png_colorspace_check_xy(&XYZtemp, xy); +} + +/* Used to check for an endpoint match against sRGB */ +static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */ +{ + /* color x y */ + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000, + /* white */ 31270, 32900 +}; + +static int +png_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ, + int preferred) +{ + if (colorspace->flags & PNG_COLORSPACE_INVALID) + return 0; + + /* The consistency check is performed on the chromaticities; this factors out + * variations because of the normalization (or not) of the end point Y + * values. + */ + if (preferred < 2 && (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) + { + /* The end points must be reasonably close to any we already have. The + * following allows an error of up to +/-.001 + */ + if (!png_colorspace_endpoints_match(xy, &colorspace->end_points_xy, 100)) + { + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "inconsistent chromaticities"); + return 0; /* failed */ + } + + /* Only overwrite with preferred values */ + if (!preferred) + return 1; /* ok, but no change */ + } + + colorspace->end_points_xy = *xy; + colorspace->end_points_XYZ = *XYZ; + colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS; + + /* The end points are normally quoted to two decimal digits, so allow +/-0.01 + * on this test. + */ + if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000)) + colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB; + + else + colorspace->flags &= PNG_COLORSPACE_CANCEL( + PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); + + return 2; /* ok and changed */ +} + +int /* PRIVATE */ +png_colorspace_set_chromaticities(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_xy *xy, int preferred) +{ + /* We must check the end points to ensure they are reasonable - in the past + * color management systems have crashed as a result of getting bogus + * colorant values, while this isn't the fault of libpng it is the + * responsibility of libpng because PNG carries the bomb and libpng is in a + * position to protect against it. + */ + png_XYZ XYZ; + + switch (png_colorspace_check_xy(&XYZ, xy)) + { + case 0: /* success */ + return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ, + preferred); + + case 1: + /* We can't invert the chromaticities so we can't produce value XYZ + * values. Likely as not a color management system will fail too. + */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "invalid chromaticities"); + break; + + default: + /* libpng is broken; this should be a warning but if it happens we + * want error reports so for the moment it is an error. + */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_error(png_ptr, "internal error checking chromaticities"); + break; + } + + return 0; /* failed */ +} + +int /* PRIVATE */ +png_colorspace_set_endpoints(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred) +{ + png_XYZ XYZ = *XYZ_in; + png_xy xy; + + switch (png_colorspace_check_XYZ(&xy, &XYZ)) + { + case 0: + return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ, + preferred); + + case 1: + /* End points are invalid. */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "invalid end points"); + break; + + default: + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_error(png_ptr, "internal error checking chromaticities"); + break; + } + + return 0; /* failed */ +} + +#if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED) +/* Error message generation */ +static char +png_icc_tag_char(png_uint_32 byte) +{ + byte &= 0xff; + if (byte >= 32 && byte <= 126) + return (char)byte; + else + return '?'; +} + +static void +png_icc_tag_name(char *name, png_uint_32 tag) +{ + name[0] = '\''; + name[1] = png_icc_tag_char(tag >> 24); + name[2] = png_icc_tag_char(tag >> 16); + name[3] = png_icc_tag_char(tag >> 8); + name[4] = png_icc_tag_char(tag ); + name[5] = '\''; +} + +static int +is_ICC_signature_char(png_alloc_size_t it) +{ + return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) || + (it >= 97 && it <= 122); +} + +static int is_ICC_signature(png_alloc_size_t it) +{ + return is_ICC_signature_char(it >> 24) /* checks all the top bits */ && + is_ICC_signature_char((it >> 16) & 0xff) && + is_ICC_signature_char((it >> 8) & 0xff) && + is_ICC_signature_char(it & 0xff); +} + +static int +png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_alloc_size_t value, png_const_charp reason) +{ + size_t pos; + char message[196]; /* see below for calculation */ + + if (colorspace != NULL) + colorspace->flags |= PNG_COLORSPACE_INVALID; + + pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */ + pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */ + pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */ + if (is_ICC_signature(value)) + { + /* So 'value' is at most 4 bytes and the following cast is safe */ + png_icc_tag_name(message+pos, (png_uint_32)value); + pos += 6; /* total +8; less than the else clause */ + message[pos++] = ':'; + message[pos++] = ' '; + } +# ifdef PNG_WARNINGS_SUPPORTED + else + { + char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/ + + pos = png_safecat(message, (sizeof message), pos, + png_format_number(number, number+(sizeof number), + PNG_NUMBER_FORMAT_x, value)); + pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/ + } +# endif + /* The 'reason' is an arbitrary message, allow +79 maximum 195 */ + pos = png_safecat(message, (sizeof message), pos, reason); + + /* This is recoverable, but make it unconditionally an app_error on write to + * avoid writing invalid ICC profiles into PNG files. (I.e. we handle them + * on read, with a warning, but on write unless the app turns off + * application errors the PNG won't be written.) + */ + png_chunk_report(png_ptr, message, + (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR); + + return 0; +} +#endif /* sRGB || iCCP */ + +#ifdef PNG_sRGB_SUPPORTED +int /* PRIVATE */ +png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace, + int intent) +{ + /* sRGB sets known gamma, end points and (from the chunk) intent. */ + /* IMPORTANT: these are not necessarily the values found in an ICC profile + * because ICC profiles store values adapted to a D50 environment; it is + * expected that the ICC profile mediaWhitePointTag will be D50, see the + * checks and code elsewhere to understand this better. + * + * These XYZ values, which are accurate to 5dp, produce rgb to gray + * coefficients of (6968,23435,2366), which are reduced (because they add up + * to 32769 not 32768) to (6968,23434,2366). These are the values that + * libpng has traditionally used (and are the best values given the 15bit + * algorithm used by the rgb to gray code.) + */ + static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */ + { + /* color X Y Z */ + /* red */ 41239, 21264, 1933, + /* green */ 35758, 71517, 11919, + /* blue */ 18048, 7219, 95053 + }; + + /* Do nothing if the colorspace is already invalidated. */ + if (colorspace->flags & PNG_COLORSPACE_INVALID) + return 0; + + /* Check the intent, then check for existing settings. It is valid for the + * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must + * be consistent with the correct values. If, however, this function is + * called below because an iCCP chunk matches sRGB then it is quite + * conceivable that an older app recorded incorrect gAMA and cHRM because of + * an incorrect calculation based on the values in the profile - this does + * *not* invalidate the profile (though it still produces an error, which can + * be ignored.) + */ + if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST) + return png_icc_profile_error(png_ptr, colorspace, "sRGB", + (unsigned)intent, "invalid sRGB rendering intent"); + + if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 && + colorspace->rendering_intent != intent) + return png_icc_profile_error(png_ptr, colorspace, "sRGB", + (unsigned)intent, "inconsistent rendering intents"); + + if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0) + { + png_benign_error(png_ptr, "duplicate sRGB information ignored"); + return 0; + } + + /* If the standard sRGB cHRM chunk does not match the one from the PNG file + * warn but overwrite the value with the correct one. + */ + if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 && + !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy, + 100)) + png_chunk_report(png_ptr, "cHRM chunk does not match sRGB", + PNG_CHUNK_ERROR); + + /* This check is just done for the error reporting - the routine always + * returns true when the 'from' argument corresponds to sRGB (2). + */ + (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE, + 2/*from sRGB*/); + + /* intent: bugs in GCC force 'int' to be used as the parameter type. */ + colorspace->rendering_intent = (png_uint_16)intent; + colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT; + + /* endpoints */ + colorspace->end_points_xy = sRGB_xy; + colorspace->end_points_XYZ = sRGB_XYZ; + colorspace->flags |= + (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); + + /* gamma */ + colorspace->gamma = PNG_GAMMA_sRGB_INVERSE; + colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA; + + /* Finally record that we have an sRGB profile */ + colorspace->flags |= + (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB); + + return 1; /* set */ +} +#endif /* sRGB */ + +#ifdef PNG_iCCP_SUPPORTED +/* Encoded value of D50 as an ICC XYZNumber. From the ICC 2010 spec the value + * is XYZ(0.9642,1.0,0.8249), which scales to: + * + * (63189.8112, 65536, 54060.6464) + */ +static const png_byte D50_nCIEXYZ[12] = + { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d }; + +int /* PRIVATE */ +png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length) +{ + if (profile_length < 132) + return png_icc_profile_error(png_ptr, colorspace, name, profile_length, + "too short"); + + if (profile_length & 3) + return png_icc_profile_error(png_ptr, colorspace, name, profile_length, + "invalid length"); + + return 1; +} + +int /* PRIVATE */ +png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, + png_const_bytep profile/* first 132 bytes only */, int color_type) +{ + png_uint_32 temp; + + /* Length check; this cannot be ignored in this code because profile_length + * is used later to check the tag table, so even if the profile seems over + * long profile_length from the caller must be correct. The caller can fix + * this up on read or write by just passing in the profile header length. + */ + temp = png_get_uint_32(profile); + if (temp != profile_length) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "length does not match profile"); + + temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */ + if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */ + profile_length < 132+12*temp) /* truncated tag table */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "tag count too large"); + + /* The 'intent' must be valid or we can't store it, ICC limits the intent to + * 16 bits. + */ + temp = png_get_uint_32(profile+64); + if (temp >= 0xffff) /* The ICC limit */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid rendering intent"); + + /* This is just a warning because the profile may be valid in future + * versions. + */ + if (temp >= PNG_sRGB_INTENT_LAST) + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "intent outside defined range"); + + /* At this point the tag table can't be checked because it hasn't necessarily + * been loaded; however, various header fields can be checked. These checks + * are for values permitted by the PNG spec in an ICC profile; the PNG spec + * restricts the profiles that can be passed in an iCCP chunk (they must be + * appropriate to processing PNG data!) + */ + + /* Data checks (could be skipped). These checks must be independent of the + * version number; however, the version number doesn't accomodate changes in + * the header fields (just the known tags and the interpretation of the + * data.) + */ + temp = png_get_uint_32(profile+36); /* signature 'ascp' */ + if (temp != 0x61637370) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid signature"); + + /* Currently the PCS illuminant/adopted white point (the computational + * white point) are required to be D50, + * however the profile contains a record of the illuminant so perhaps ICC + * expects to be able to change this in the future (despite the rationale in + * the introduction for using a fixed PCS adopted white.) Consequently the + * following is just a warning. + */ + if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0) + (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/, + "PCS illuminant is not D50"); + + /* The PNG spec requires this: + * "If the iCCP chunk is present, the image samples conform to the colour + * space represented by the embedded ICC profile as defined by the + * International Color Consortium [ICC]. The colour space of the ICC profile + * shall be an RGB colour space for colour images (PNG colour types 2, 3, and + * 6), or a greyscale colour space for greyscale images (PNG colour types 0 + * and 4)." + * + * This checking code ensures the embedded profile (on either read or write) + * conforms to the specification requirements. Notice that an ICC 'gray' + * color-space profile contains the information to transform the monochrome + * data to XYZ or L*a*b (according to which PCS the profile uses) and this + * should be used in preference to the standard libpng K channel replication + * into R, G and B channels. + * + * Previously it was suggested that an RGB profile on grayscale data could be + * handled. However it it is clear that using an RGB profile in this context + * must be an error - there is no specification of what it means. Thus it is + * almost certainly more correct to ignore the profile. + */ + temp = png_get_uint_32(profile+16); /* data colour space field */ + switch (temp) + { + case 0x52474220: /* 'RGB ' */ + if (!(color_type & PNG_COLOR_MASK_COLOR)) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "RGB color space not permitted on grayscale PNG"); + break; + + case 0x47524159: /* 'GRAY' */ + if (color_type & PNG_COLOR_MASK_COLOR) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "Gray color space not permitted on RGB PNG"); + break; + + default: + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid ICC profile color space"); + } + + /* It is up to the application to check that the profile class matches the + * application requirements; the spec provides no guidance, but it's pretty + * weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer + * ('prtr') or 'spac' (for generic color spaces). Issue a warning in these + * cases. Issue an error for device link or abstract profiles - these don't + * contain the records necessary to transform the color-space to anything + * other than the target device (and not even that for an abstract profile). + * Profiles of these classes may not be embedded in images. + */ + temp = png_get_uint_32(profile+12); /* profile/device class */ + switch (temp) + { + case 0x73636E72: /* 'scnr' */ + case 0x6D6E7472: /* 'mntr' */ + case 0x70727472: /* 'prtr' */ + case 0x73706163: /* 'spac' */ + /* All supported */ + break; + + case 0x61627374: /* 'abst' */ + /* May not be embedded in an image */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid embedded Abstract ICC profile"); + + case 0x6C696E6B: /* 'link' */ + /* DeviceLink profiles cannnot be interpreted in a non-device specific + * fashion, if an app uses the AToB0Tag in the profile the results are + * undefined unless the result is sent to the intended device, + * therefore a DeviceLink profile should not be found embedded in a + * PNG. + */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "unexpected DeviceLink ICC profile class"); + + case 0x6E6D636C: /* 'nmcl' */ + /* A NamedColor profile is also device specific, however it doesn't + * contain an AToB0 tag that is open to misintrepretation. Almost + * certainly it will fail the tests below. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "unexpected NamedColor ICC profile class"); + break; + + default: + /* To allow for future enhancements to the profile accept unrecognized + * profile classes with a warning, these then hit the test below on the + * tag content to ensure they are backward compatible with one of the + * understood profiles. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "unrecognized ICC profile class"); + break; + } + + /* For any profile other than a device link one the PCS must be encoded + * either in XYZ or Lab. + */ + temp = png_get_uint_32(profile+20); + switch (temp) + { + case 0x58595A20: /* 'XYZ ' */ + case 0x4C616220: /* 'Lab ' */ + break; + + default: + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "unexpected ICC PCS encoding"); + } + + return 1; +} + +int /* PRIVATE */ +png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */) +{ + png_uint_32 tag_count = png_get_uint_32(profile+128); + png_uint_32 itag; + png_const_bytep tag = profile+132; /* The first tag */ + + /* First scan all the tags in the table and add bits to the icc_info value + * (temporarily in 'tags'). + */ + for (itag=0; itag < tag_count; ++itag, tag += 12) + { + png_uint_32 tag_id = png_get_uint_32(tag+0); + png_uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */ + png_uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */ + + /* The ICC specification does not exclude zero length tags, therefore the + * start might actually be anywhere if there is no data, but this would be + * a clear abuse of the intent of the standard so the start is checked for + * being in range. All defined tag types have an 8 byte header - a 4 byte + * type signature then 0. + */ + if ((tag_start & 3) != 0) + { + /* CNHP730S.icc shipped with Microsoft Windows 64 violates this, it is + * only a warning here because libpng does not care about the + * alignment. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, tag_id, + "ICC profile tag start not a multiple of 4"); + } + + /* This is a hard error; potentially it can cause read outside the + * profile. + */ + if (tag_start > profile_length || tag_length > profile_length - tag_start) + return png_icc_profile_error(png_ptr, colorspace, name, tag_id, + "ICC profile tag outside profile"); + } + + return 1; /* success, maybe with warnings */ +} + +#ifdef PNG_sRGB_SUPPORTED +/* Information about the known ICC sRGB profiles */ +static const struct +{ + png_uint_32 adler, crc, length; + png_uint_32 md5[4]; + png_byte have_md5; + png_byte is_broken; + png_uint_16 intent; + +# define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0) +# define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\ + { adler, crc, length, md5, broke, intent }, + +} png_sRGB_checks[] = +{ + /* This data comes from contrib/tools/checksum-icc run on downloads of + * all four ICC sRGB profiles from www.color.org. + */ + /* adler32, crc32, MD5[4], intent, date, length, file-name */ + PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9, + PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0, + "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc") + + /* ICC sRGB v2 perceptual no black-compensation: */ + PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21, + PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0, + "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc") + + PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae, + PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0, + "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc") + + /* ICC sRGB v4 perceptual */ + PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812, + PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0, + "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc") + + /* The following profiles have no known MD5 checksum. If there is a match + * on the (empty) MD5 the other fields are used to attempt a match and + * a warning is produced. The first two of these profiles have a 'cprt' tag + * which suggests that they were also made by Hewlett Packard. + */ + PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0, + "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc") + + /* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not + * match the D50 PCS illuminant in the header (it is in fact the D65 values, + * so the white point is recorded as the un-adapted value.) The profiles + * below only differ in one byte - the intent - and are basically the same as + * the previous profile except for the mediaWhitePointTag error and a missing + * chromaticAdaptationTag. + */ + PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/, + "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual") + + PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/, + "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative") +}; + +static int +png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr, + png_const_bytep profile, uLong adler) +{ + /* The quick check is to verify just the MD5 signature and trust the + * rest of the data. Because the profile has already been verified for + * correctness this is safe. png_colorspace_set_sRGB will check the 'intent' + * field too, so if the profile has been edited with an intent not defined + * by sRGB (but maybe defined by a later ICC specification) the read of + * the profile will fail at that point. + */ + png_uint_32 length = 0; + png_uint_32 intent = 0x10000; /* invalid */ +#if PNG_sRGB_PROFILE_CHECKS > 1 + uLong crc = 0; /* the value for 0 length data */ +#endif + unsigned int i; + + for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i) + { + if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] && + png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] && + png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] && + png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3]) + { + /* This may be one of the old HP profiles without an MD5, in that + * case we can only use the length and Adler32 (note that these + * are not used by default if there is an MD5!) + */ +# if PNG_sRGB_PROFILE_CHECKS == 0 + if (png_sRGB_checks[i].have_md5) + return 1+png_sRGB_checks[i].is_broken; +# endif + + /* Profile is unsigned or more checks have been configured in. */ + if (length == 0) + { + length = png_get_uint_32(profile); + intent = png_get_uint_32(profile+64); + } + + /* Length *and* intent must match */ + if (length == png_sRGB_checks[i].length && + intent == png_sRGB_checks[i].intent) + { + /* Now calculate the adler32 if not done already. */ + if (adler == 0) + { + adler = adler32(0, NULL, 0); + adler = adler32(adler, profile, length); + } + + if (adler == png_sRGB_checks[i].adler) + { + /* These basic checks suggest that the data has not been + * modified, but if the check level is more than 1 perform + * our own crc32 checksum on the data. + */ +# if PNG_sRGB_PROFILE_CHECKS > 1 + if (crc == 0) + { + crc = crc32(0, NULL, 0); + crc = crc32(crc, profile, length); + } + + /* So this check must pass for the 'return' below to happen. + */ + if (crc == png_sRGB_checks[i].crc) +# endif + { + if (png_sRGB_checks[i].is_broken) + { + /* These profiles are known to have bad data that may cause + * problems if they are used, therefore attempt to + * discourage their use, skip the 'have_md5' warning below, + * which is made irrelevant by this error. + */ + png_chunk_report(png_ptr, "known incorrect sRGB profile", + PNG_CHUNK_ERROR); + } + + /* Warn that this being done; this isn't even an error since + * the profile is perfectly valid, but it would be nice if + * people used the up-to-date ones. + */ + else if (!png_sRGB_checks[i].have_md5) + { + png_chunk_report(png_ptr, + "out-of-date sRGB profile with no signature", + PNG_CHUNK_WARNING); + } + + return 1+png_sRGB_checks[i].is_broken; + } + } + } + +# if PNG_sRGB_PROFILE_CHECKS > 0 + /* The signature matched, but the profile had been changed in some + * way. This is an apparent violation of the ICC terms of use and, + * anyway, probably indicates a data error or uninformed hacking. + */ + if (png_sRGB_checks[i].have_md5) + png_benign_error(png_ptr, + "copyright violation: edited ICC profile ignored"); +# endif + } + } + + return 0; /* no match */ +} +#endif + +#ifdef PNG_sRGB_SUPPORTED +void /* PRIVATE */ +png_icc_set_sRGB(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_bytep profile, uLong adler) +{ + /* Is this profile one of the known ICC sRGB profiles? If it is, just set + * the sRGB information. + */ + if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler)) + (void)png_colorspace_set_sRGB(png_ptr, colorspace, + (int)/*already checked*/png_get_uint_32(profile+64)); +} +#endif /* PNG_READ_sRGB_SUPPORTED */ + +int /* PRIVATE */ +png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, png_const_bytep profile, + int color_type) +{ + if (colorspace->flags & PNG_COLORSPACE_INVALID) + return 0; + + if (png_icc_check_length(png_ptr, colorspace, name, profile_length) && + png_icc_check_header(png_ptr, colorspace, name, profile_length, profile, + color_type) && + png_icc_check_tag_table(png_ptr, colorspace, name, profile_length, + profile)) + { +# ifdef PNG_sRGB_SUPPORTED + /* If no sRGB support, don't try storing sRGB information */ + png_icc_set_sRGB(png_ptr, colorspace, profile, 0); +# endif + return 1; + } + + /* Failure case */ + return 0; +} +#endif /* iCCP */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +void /* PRIVATE */ +png_colorspace_set_rgb_coefficients(png_structrp png_ptr) +{ + /* Set the rgb_to_gray coefficients from the colorspace. */ + if (!png_ptr->rgb_to_gray_coefficients_set && + (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + /* png_set_background has not been called, get the coefficients from the Y + * values of the colorspace colorants. + */ + png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y; + png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y; + png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y; + png_fixed_point total = r+g+b; + + if (total > 0 && + r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 && + g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 && + b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 && + r+g+b <= 32769) + { + /* We allow 0 coefficients here. r+g+b may be 32769 if two or + * all of the coefficients were rounded up. Handle this by + * reducing the *largest* coefficient by 1; this matches the + * approach used for the default coefficients in pngrtran.c + */ + int add = 0; + + if (r+g+b > 32768) + add = -1; + else if (r+g+b < 32768) + add = 1; + + if (add != 0) + { + if (g >= r && g >= b) + g += add; + else if (r >= g && r >= b) + r += add; + else + b += add; + } + + /* Check for an internal error. */ + if (r+g+b != 32768) + png_error(png_ptr, + "internal error handling cHRM coefficients"); + + else + { + png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r; + png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g; + } + } + + /* This is a png_error at present even though it could be ignored - + * it should never happen, but it is important that if it does, the + * bug is fixed. + */ + else + png_error(png_ptr, "internal error handling cHRM->XYZ"); + } +} +#endif + +#endif /* COLORSPACE */ + +void /* PRIVATE */ +png_check_IHDR(png_const_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + int error = 0; + + /* Check for width and height valid values */ + if (width == 0) + { + png_warning(png_ptr, "Image width is zero in IHDR"); + error = 1; + } + + if (height == 0) + { + png_warning(png_ptr, "Image height is zero in IHDR"); + error = 1; + } + +# ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (width > png_ptr->user_width_max) + +# else + if (width > PNG_USER_WIDTH_MAX) +# endif + { + png_warning(png_ptr, "Image width exceeds user limit in IHDR"); + error = 1; + } + +# ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (height > png_ptr->user_height_max) +# else + if (height > PNG_USER_HEIGHT_MAX) +# endif + { + png_warning(png_ptr, "Image height exceeds user limit in IHDR"); + error = 1; + } + + if (width > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image width in IHDR"); + error = 1; + } + + if (height > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image height in IHDR"); + error = 1; + } + + if (width > (PNG_UINT_32_MAX + >> 3) /* 8-byte RGBA pixels */ + - 48 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ + png_warning(png_ptr, "Width is too large for libpng to process pixels"); + + /* Check other values */ + if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && + bit_depth != 8 && bit_depth != 16) + { + png_warning(png_ptr, "Invalid bit depth in IHDR"); + error = 1; + } + + if (color_type < 0 || color_type == 1 || + color_type == 5 || color_type > 6) + { + png_warning(png_ptr, "Invalid color type in IHDR"); + error = 1; + } + + if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) || + ((color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8)) + { + png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR"); + error = 1; + } + + if (interlace_type >= PNG_INTERLACE_LAST) + { + png_warning(png_ptr, "Unknown interlace method in IHDR"); + error = 1; + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Unknown compression method in IHDR"); + error = 1; + } + +# ifdef PNG_MNG_FEATURES_SUPPORTED + /* Accept filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not read a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) && + png_ptr->mng_features_permitted) + png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); + + if (filter_type != PNG_FILTER_TYPE_BASE) + { + if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && + ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA))) + { + png_warning(png_ptr, "Unknown filter method in IHDR"); + error = 1; + } + + if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) + { + png_warning(png_ptr, "Invalid filter method in IHDR"); + error = 1; + } + } + +# else + if (filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Unknown filter method in IHDR"); + error = 1; + } +# endif + + if (error == 1) + png_error(png_ptr, "Invalid IHDR data"); +} + +#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) +/* ASCII to fp functions */ +/* Check an ASCII formated floating point value, see the more detailed + * comments in pngpriv.h + */ +/* The following is used internally to preserve the sticky flags */ +#define png_fp_add(state, flags) ((state) |= (flags)) +#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY)) + +int /* PRIVATE */ +png_check_fp_number(png_const_charp string, png_size_t size, int *statep, + png_size_tp whereami) +{ + int state = *statep; + png_size_t i = *whereami; + + while (i < size) + { + int type; + /* First find the type of the next character */ + switch (string[i]) + { + case 43: type = PNG_FP_SAW_SIGN; break; + case 45: type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break; + case 46: type = PNG_FP_SAW_DOT; break; + case 48: type = PNG_FP_SAW_DIGIT; break; + case 49: case 50: case 51: case 52: + case 53: case 54: case 55: case 56: + case 57: type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break; + case 69: + case 101: type = PNG_FP_SAW_E; break; + default: goto PNG_FP_End; + } + + /* Now deal with this type according to the current + * state, the type is arranged to not overlap the + * bits of the PNG_FP_STATE. + */ + switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY)) + { + case PNG_FP_INTEGER + PNG_FP_SAW_SIGN: + if (state & PNG_FP_SAW_ANY) + goto PNG_FP_End; /* not a part of the number */ + + png_fp_add(state, type); + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_DOT: + /* Ok as trailer, ok as lead of fraction. */ + if (state & PNG_FP_SAW_DOT) /* two dots */ + goto PNG_FP_End; + + else if (state & PNG_FP_SAW_DIGIT) /* trailing dot? */ + png_fp_add(state, type); + + else + png_fp_set(state, PNG_FP_FRACTION | type); + + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT: + if (state & PNG_FP_SAW_DOT) /* delayed fraction */ + png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT); + + png_fp_add(state, type | PNG_FP_WAS_VALID); + + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_E: + if ((state & PNG_FP_SAW_DIGIT) == 0) + goto PNG_FP_End; + + png_fp_set(state, PNG_FP_EXPONENT); + + break; + + /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN: + goto PNG_FP_End; ** no sign in fraction */ + + /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT: + goto PNG_FP_End; ** Because SAW_DOT is always set */ + + case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT: + png_fp_add(state, type | PNG_FP_WAS_VALID); + break; + + case PNG_FP_FRACTION + PNG_FP_SAW_E: + /* This is correct because the trailing '.' on an + * integer is handled above - so we can only get here + * with the sequence ".E" (with no preceding digits). + */ + if ((state & PNG_FP_SAW_DIGIT) == 0) + goto PNG_FP_End; + + png_fp_set(state, PNG_FP_EXPONENT); + + break; + + case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN: + if (state & PNG_FP_SAW_ANY) + goto PNG_FP_End; /* not a part of the number */ + + png_fp_add(state, PNG_FP_SAW_SIGN); + + break; + + /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT: + goto PNG_FP_End; */ + + case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT: + png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID); + + break; + + /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E: + goto PNG_FP_End; */ + + default: goto PNG_FP_End; /* I.e. break 2 */ + } + + /* The character seems ok, continue. */ + ++i; + } + +PNG_FP_End: + /* Here at the end, update the state and return the correct + * return code. + */ + *statep = state; + *whereami = i; + + return (state & PNG_FP_SAW_DIGIT) != 0; +} + + +/* The same but for a complete string. */ +int +png_check_fp_string(png_const_charp string, png_size_t size) +{ + int state=0; + png_size_t char_index=0; + + if (png_check_fp_number(string, size, &state, &char_index) && + (char_index == size || string[char_index] == 0)) + return state /* must be non-zero - see above */; + + return 0; /* i.e. fail */ +} +#endif /* pCAL or sCAL */ + +#ifdef PNG_sCAL_SUPPORTED +# ifdef PNG_FLOATING_POINT_SUPPORTED +/* Utility used below - a simple accurate power of ten from an integral + * exponent. + */ +static double +png_pow10(int power) +{ + int recip = 0; + double d = 1; + + /* Handle negative exponent with a reciprocal at the end because + * 10 is exact whereas .1 is inexact in base 2 + */ + if (power < 0) + { + if (power < DBL_MIN_10_EXP) return 0; + recip = 1, power = -power; + } + + if (power > 0) + { + /* Decompose power bitwise. */ + double mult = 10; + do + { + if (power & 1) d *= mult; + mult *= mult; + power >>= 1; + } + while (power > 0); + + if (recip) d = 1/d; + } + /* else power is 0 and d is 1 */ + + return d; +} + +/* Function to format a floating point value in ASCII with a given + * precision. + */ +void /* PRIVATE */ +png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, + double fp, unsigned int precision) +{ + /* We use standard functions from math.h, but not printf because + * that would require stdio. The caller must supply a buffer of + * sufficient size or we will png_error. The tests on size and + * the space in ascii[] consumed are indicated below. + */ + if (precision < 1) + precision = DBL_DIG; + + /* Enforce the limit of the implementation precision too. */ + if (precision > DBL_DIG+1) + precision = DBL_DIG+1; + + /* Basic sanity checks */ + if (size >= precision+5) /* See the requirements below. */ + { + if (fp < 0) + { + fp = -fp; + *ascii++ = 45; /* '-' PLUS 1 TOTAL 1 */ + --size; + } + + if (fp >= DBL_MIN && fp <= DBL_MAX) + { + int exp_b10; /* A base 10 exponent */ + double base; /* 10^exp_b10 */ + + /* First extract a base 10 exponent of the number, + * the calculation below rounds down when converting + * from base 2 to base 10 (multiply by log10(2) - + * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to + * be increased. Note that the arithmetic shift + * performs a floor() unlike C arithmetic - using a + * C multiply would break the following for negative + * exponents. + */ + (void)frexp(fp, &exp_b10); /* exponent to base 2 */ + + exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */ + + /* Avoid underflow here. */ + base = png_pow10(exp_b10); /* May underflow */ + + while (base < DBL_MIN || base < fp) + { + /* And this may overflow. */ + double test = png_pow10(exp_b10+1); + + if (test <= DBL_MAX) + ++exp_b10, base = test; + + else + break; + } + + /* Normalize fp and correct exp_b10, after this fp is in the + * range [.1,1) and exp_b10 is both the exponent and the digit + * *before* which the decimal point should be inserted + * (starting with 0 for the first digit). Note that this + * works even if 10^exp_b10 is out of range because of the + * test on DBL_MAX above. + */ + fp /= base; + while (fp >= 1) fp /= 10, ++exp_b10; + + /* Because of the code above fp may, at this point, be + * less than .1, this is ok because the code below can + * handle the leading zeros this generates, so no attempt + * is made to correct that here. + */ + + { + int czero, clead, cdigits; + char exponent[10]; + + /* Allow up to two leading zeros - this will not lengthen + * the number compared to using E-n. + */ + if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */ + { + czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */ + exp_b10 = 0; /* Dot added below before first output. */ + } + else + czero = 0; /* No zeros to add */ + + /* Generate the digit list, stripping trailing zeros and + * inserting a '.' before a digit if the exponent is 0. + */ + clead = czero; /* Count of leading zeros */ + cdigits = 0; /* Count of digits in list. */ + + do + { + double d; + + fp *= 10; + /* Use modf here, not floor and subtract, so that + * the separation is done in one step. At the end + * of the loop don't break the number into parts so + * that the final digit is rounded. + */ + if (cdigits+czero-clead+1 < (int)precision) + fp = modf(fp, &d); + + else + { + d = floor(fp + .5); + + if (d > 9) + { + /* Rounding up to 10, handle that here. */ + if (czero > 0) + { + --czero, d = 1; + if (cdigits == 0) --clead; + } + else + { + while (cdigits > 0 && d > 9) + { + int ch = *--ascii; + + if (exp_b10 != (-1)) + ++exp_b10; + + else if (ch == 46) + { + ch = *--ascii, ++size; + /* Advance exp_b10 to '1', so that the + * decimal point happens after the + * previous digit. + */ + exp_b10 = 1; + } + + --cdigits; + d = ch - 47; /* I.e. 1+(ch-48) */ + } + + /* Did we reach the beginning? If so adjust the + * exponent but take into account the leading + * decimal point. + */ + if (d > 9) /* cdigits == 0 */ + { + if (exp_b10 == (-1)) + { + /* Leading decimal point (plus zeros?), if + * we lose the decimal point here it must + * be reentered below. + */ + int ch = *--ascii; + + if (ch == 46) + ++size, exp_b10 = 1; + + /* Else lost a leading zero, so 'exp_b10' is + * still ok at (-1) + */ + } + else + ++exp_b10; + + /* In all cases we output a '1' */ + d = 1; + } + } + } + fp = 0; /* Guarantees termination below. */ + } + + if (d == 0) + { + ++czero; + if (cdigits == 0) ++clead; + } + else + { + /* Included embedded zeros in the digit count. */ + cdigits += czero - clead; + clead = 0; + + while (czero > 0) + { + /* exp_b10 == (-1) means we just output the decimal + * place - after the DP don't adjust 'exp_b10' any + * more! + */ + if (exp_b10 != (-1)) + { + if (exp_b10 == 0) *ascii++ = 46, --size; + /* PLUS 1: TOTAL 4 */ + --exp_b10; + } + *ascii++ = 48, --czero; + } + + if (exp_b10 != (-1)) + { + if (exp_b10 == 0) *ascii++ = 46, --size; /* counted + above */ + --exp_b10; + } + *ascii++ = (char)(48 + (int)d), ++cdigits; + } + } + while (cdigits+czero-clead < (int)precision && fp > DBL_MIN); + + /* The total output count (max) is now 4+precision */ + + /* Check for an exponent, if we don't need one we are + * done and just need to terminate the string. At + * this point exp_b10==(-1) is effectively if flag - it got + * to '-1' because of the decrement after outputing + * the decimal point above (the exponent required is + * *not* -1!) + */ + if (exp_b10 >= (-1) && exp_b10 <= 2) + { + /* The following only happens if we didn't output the + * leading zeros above for negative exponent, so this + * doest add to the digit requirement. Note that the + * two zeros here can only be output if the two leading + * zeros were *not* output, so this doesn't increase + * the output count. + */ + while (--exp_b10 >= 0) *ascii++ = 48; + + *ascii = 0; + + /* Total buffer requirement (including the '\0') is + * 5+precision - see check at the start. + */ + return; + } + + /* Here if an exponent is required, adjust size for + * the digits we output but did not count. The total + * digit output here so far is at most 1+precision - no + * decimal point and no leading or trailing zeros have + * been output. + */ + size -= cdigits; + + *ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision */ + + /* The following use of an unsigned temporary avoids ambiguities in + * the signed arithmetic on exp_b10 and permits GCC at least to do + * better optimization. + */ + { + unsigned int uexp_b10; + + if (exp_b10 < 0) + { + *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */ + uexp_b10 = -exp_b10; + } + + else + uexp_b10 = exp_b10; + + cdigits = 0; + + while (uexp_b10 > 0) + { + exponent[cdigits++] = (char)(48 + uexp_b10 % 10); + uexp_b10 /= 10; + } + } + + /* Need another size check here for the exponent digits, so + * this need not be considered above. + */ + if ((int)size > cdigits) + { + while (cdigits > 0) *ascii++ = exponent[--cdigits]; + + *ascii = 0; + + return; + } + } + } + else if (!(fp >= DBL_MIN)) + { + *ascii++ = 48; /* '0' */ + *ascii = 0; + return; + } + else + { + *ascii++ = 105; /* 'i' */ + *ascii++ = 110; /* 'n' */ + *ascii++ = 102; /* 'f' */ + *ascii = 0; + return; + } + } + + /* Here on buffer too small. */ + png_error(png_ptr, "ASCII conversion buffer too small"); +} + +# endif /* FLOATING_POINT */ + +# ifdef PNG_FIXED_POINT_SUPPORTED +/* Function to format a fixed point value in ASCII. + */ +void /* PRIVATE */ +png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, + png_size_t size, png_fixed_point fp) +{ + /* Require space for 10 decimal digits, a decimal point, a minus sign and a + * trailing \0, 13 characters: + */ + if (size > 12) + { + png_uint_32 num; + + /* Avoid overflow here on the minimum integer. */ + if (fp < 0) + *ascii++ = 45, --size, num = -fp; + else + num = fp; + + if (num <= 0x80000000) /* else overflowed */ + { + unsigned int ndigits = 0, first = 16 /* flag value */; + char digits[10]; + + while (num) + { + /* Split the low digit off num: */ + unsigned int tmp = num/10; + num -= tmp*10; + digits[ndigits++] = (char)(48 + num); + /* Record the first non-zero digit, note that this is a number + * starting at 1, it's not actually the array index. + */ + if (first == 16 && num > 0) + first = ndigits; + num = tmp; + } + + if (ndigits > 0) + { + while (ndigits > 5) *ascii++ = digits[--ndigits]; + /* The remaining digits are fractional digits, ndigits is '5' or + * smaller at this point. It is certainly not zero. Check for a + * non-zero fractional digit: + */ + if (first <= 5) + { + unsigned int i; + *ascii++ = 46; /* decimal point */ + /* ndigits may be <5 for small numbers, output leading zeros + * then ndigits digits to first: + */ + i = 5; + while (ndigits < i) *ascii++ = 48, --i; + while (ndigits >= first) *ascii++ = digits[--ndigits]; + /* Don't output the trailing zeros! */ + } + } + else + *ascii++ = 48; + + /* And null terminate the string: */ + *ascii = 0; + return; + } + } + + /* Here on buffer too small. */ + png_error(png_ptr, "ASCII conversion buffer too small"); +} +# endif /* FIXED_POINT */ +#endif /* READ_SCAL */ + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ + defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ + (defined(PNG_sCAL_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) +png_fixed_point +png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text) +{ + double r = floor(100000 * fp + .5); + + if (r > 2147483647. || r < -2147483648.) + png_fixed_error(png_ptr, text); + + return (png_fixed_point)r; +} +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || \ + defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) +/* muldiv functions */ +/* This API takes signed arguments and rounds the result to the nearest + * integer (or, for a fixed point number - the standard argument - to + * the nearest .00001). Overflow and divide by zero are signalled in + * the result, a boolean - true on success, false on overflow. + */ +int +png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, + png_int_32 divisor) +{ + /* Return a * times / divisor, rounded. */ + if (divisor != 0) + { + if (a == 0 || times == 0) + { + *res = 0; + return 1; + } + else + { +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = a; + r *= times; + r /= divisor; + r = floor(r+.5); + + /* A png_fixed_point is a 32-bit integer. */ + if (r <= 2147483647. && r >= -2147483648.) + { + *res = (png_fixed_point)r; + return 1; + } +#else + int negative = 0; + png_uint_32 A, T, D; + png_uint_32 s16, s32, s00; + + if (a < 0) + negative = 1, A = -a; + else + A = a; + + if (times < 0) + negative = !negative, T = -times; + else + T = times; + + if (divisor < 0) + negative = !negative, D = -divisor; + else + D = divisor; + + /* Following can't overflow because the arguments only + * have 31 bits each, however the result may be 32 bits. + */ + s16 = (A >> 16) * (T & 0xffff) + + (A & 0xffff) * (T >> 16); + /* Can't overflow because the a*times bit is only 30 + * bits at most. + */ + s32 = (A >> 16) * (T >> 16) + (s16 >> 16); + s00 = (A & 0xffff) * (T & 0xffff); + + s16 = (s16 & 0xffff) << 16; + s00 += s16; + + if (s00 < s16) + ++s32; /* carry */ + + if (s32 < D) /* else overflow */ + { + /* s32.s00 is now the 64-bit product, do a standard + * division, we know that s32 < D, so the maximum + * required shift is 31. + */ + int bitshift = 32; + png_fixed_point result = 0; /* NOTE: signed */ + + while (--bitshift >= 0) + { + png_uint_32 d32, d00; + + if (bitshift > 0) + d32 = D >> (32-bitshift), d00 = D << bitshift; + + else + d32 = 0, d00 = D; + + if (s32 > d32) + { + if (s00 < d00) --s32; /* carry */ + s32 -= d32, s00 -= d00, result += 1<= d00) + s32 = 0, s00 -= d00, result += 1<= (D >> 1)) + ++result; + + if (negative) + result = -result; + + /* Check for overflow. */ + if ((negative && result <= 0) || (!negative && result >= 0)) + { + *res = result; + return 1; + } + } +#endif + } + } + + return 0; +} +#endif /* READ_GAMMA || INCH_CONVERSIONS */ + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) +/* The following is for when the caller doesn't much care about the + * result. + */ +png_fixed_point +png_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times, + png_int_32 divisor) +{ + png_fixed_point result; + + if (png_muldiv(&result, a, times, divisor)) + return result; + + png_warning(png_ptr, "fixed point overflow ignored"); + return 0; +} +#endif + +#ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */ +/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */ +png_fixed_point +png_reciprocal(png_fixed_point a) +{ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = floor(1E10/a+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; +#else + png_fixed_point res; + + if (png_muldiv(&res, 100000, 100000, a)) + return res; +#endif + + return 0; /* error/overflow */ +} + +/* This is the shared test on whether a gamma value is 'significant' - whether + * it is worth doing gamma correction. + */ +int /* PRIVATE */ +png_gamma_significant(png_fixed_point gamma_val) +{ + return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED || + gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED; +} +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* A local convenience routine. */ +static png_fixed_point +png_product2(png_fixed_point a, png_fixed_point b) +{ + /* The required result is 1/a * 1/b; the following preserves accuracy. */ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = a * 1E-5; + r *= b; + r = floor(r+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; +#else + png_fixed_point res; + + if (png_muldiv(&res, a, b, 100000)) + return res; +#endif + + return 0; /* overflow */ +} + +/* The inverse of the above. */ +png_fixed_point +png_reciprocal2(png_fixed_point a, png_fixed_point b) +{ + /* The required result is 1/a * 1/b; the following preserves accuracy. */ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = 1E15/a; + r /= b; + r = floor(r+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; +#else + /* This may overflow because the range of png_fixed_point isn't symmetric, + * but this API is only used for the product of file and screen gamma so it + * doesn't matter that the smallest number it can produce is 1/21474, not + * 1/100000 + */ + png_fixed_point res = png_product2(a, b); + + if (res != 0) + return png_reciprocal(res); +#endif + + return 0; /* overflow */ +} +#endif /* READ_GAMMA */ + +#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */ +#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED +/* Fixed point gamma. + * + * The code to calculate the tables used below can be found in the shell script + * contrib/tools/intgamma.sh + * + * To calculate gamma this code implements fast log() and exp() calls using only + * fixed point arithmetic. This code has sufficient precision for either 8-bit + * or 16-bit sample values. + * + * The tables used here were calculated using simple 'bc' programs, but C double + * precision floating point arithmetic would work fine. + * + * 8-bit log table + * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to + * 255, so it's the base 2 logarithm of a normalized 8-bit floating point + * mantissa. The numbers are 32-bit fractions. + */ +static const png_uint_32 +png_8bit_l2[128] = +{ + 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U, + 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U, + 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U, + 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U, + 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U, + 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U, + 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U, + 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U, + 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U, + 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U, + 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U, + 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U, + 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U, + 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U, + 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U, + 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U, + 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U, + 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U, + 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U, + 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U, + 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U, + 24347096U, 0U + +#if 0 + /* The following are the values for 16-bit tables - these work fine for the + * 8-bit conversions but produce very slightly larger errors in the 16-bit + * log (about 1.2 as opposed to 0.7 absolute error in the final value). To + * use these all the shifts below must be adjusted appropriately. + */ + 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054, + 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803, + 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068, + 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782, + 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887, + 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339, + 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098, + 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132, + 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415, + 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523, + 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495, + 1119, 744, 372 +#endif +}; + +static png_int_32 +png_log8bit(unsigned int x) +{ + unsigned int lg2 = 0; + /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log, + * because the log is actually negate that means adding 1. The final + * returned value thus has the range 0 (for 255 input) to 7.994 (for 1 + * input), return -1 for the overflow (log 0) case, - so the result is + * always at most 19 bits. + */ + if ((x &= 0xff) == 0) + return -1; + + if ((x & 0xf0) == 0) + lg2 = 4, x <<= 4; + + if ((x & 0xc0) == 0) + lg2 += 2, x <<= 2; + + if ((x & 0x80) == 0) + lg2 += 1, x <<= 1; + + /* result is at most 19 bits, so this cast is safe: */ + return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16)); +} + +/* The above gives exact (to 16 binary places) log2 values for 8-bit images, + * for 16-bit images we use the most significant 8 bits of the 16-bit value to + * get an approximation then multiply the approximation by a correction factor + * determined by the remaining up to 8 bits. This requires an additional step + * in the 16-bit case. + * + * We want log2(value/65535), we have log2(v'/255), where: + * + * value = v' * 256 + v'' + * = v' * f + * + * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128 + * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less + * than 258. The final factor also needs to correct for the fact that our 8-bit + * value is scaled by 255, whereas the 16-bit values must be scaled by 65535. + * + * This gives a final formula using a calculated value 'x' which is value/v' and + * scaling by 65536 to match the above table: + * + * log2(x/257) * 65536 + * + * Since these numbers are so close to '1' we can use simple linear + * interpolation between the two end values 256/257 (result -368.61) and 258/257 + * (result 367.179). The values used below are scaled by a further 64 to give + * 16-bit precision in the interpolation: + * + * Start (256): -23591 + * Zero (257): 0 + * End (258): 23499 + */ +static png_int_32 +png_log16bit(png_uint_32 x) +{ + unsigned int lg2 = 0; + + /* As above, but now the input has 16 bits. */ + if ((x &= 0xffff) == 0) + return -1; + + if ((x & 0xff00) == 0) + lg2 = 8, x <<= 8; + + if ((x & 0xf000) == 0) + lg2 += 4, x <<= 4; + + if ((x & 0xc000) == 0) + lg2 += 2, x <<= 2; + + if ((x & 0x8000) == 0) + lg2 += 1, x <<= 1; + + /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional + * value. + */ + lg2 <<= 28; + lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4; + + /* Now we need to interpolate the factor, this requires a division by the top + * 8 bits. Do this with maximum precision. + */ + x = ((x << 16) + (x >> 9)) / (x >> 8); + + /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24, + * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly + * 16 bits to interpolate to get the low bits of the result. Round the + * answer. Note that the end point values are scaled by 64 to retain overall + * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust + * the overall scaling by 6-12. Round at every step. + */ + x -= 1U << 24; + + if (x <= 65536U) /* <= '257' */ + lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12); + + else + lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12); + + /* Safe, because the result can't have more than 20 bits: */ + return (png_int_32)((lg2 + 2048) >> 12); +} + +/* The 'exp()' case must invert the above, taking a 20-bit fixed point + * logarithmic value and returning a 16 or 8-bit number as appropriate. In + * each case only the low 16 bits are relevant - the fraction - since the + * integer bits (the top 4) simply determine a shift. + * + * The worst case is the 16-bit distinction between 65535 and 65534, this + * requires perhaps spurious accuracty in the decoding of the logarithm to + * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance + * of getting this accuracy in practice. + * + * To deal with this the following exp() function works out the exponent of the + * frational part of the logarithm by using an accurate 32-bit value from the + * top four fractional bits then multiplying in the remaining bits. + */ +static const png_uint_32 +png_32bit_exp[16] = +{ + /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */ + 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U, + 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U, + 2553802834U, 2445529972U, 2341847524U, 2242560872U +}; + +/* Adjustment table; provided to explain the numbers in the code below. */ +#if 0 +for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"} + 11 44937.64284865548751208448 + 10 45180.98734845585101160448 + 9 45303.31936980687359311872 + 8 45364.65110595323018870784 + 7 45395.35850361789624614912 + 6 45410.72259715102037508096 + 5 45418.40724413220722311168 + 4 45422.25021786898173001728 + 3 45424.17186732298419044352 + 2 45425.13273269940811464704 + 1 45425.61317555035558641664 + 0 45425.85339951654943850496 +#endif + +static png_uint_32 +png_exp(png_fixed_point x) +{ + if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */ + { + /* Obtain a 4-bit approximation */ + png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf]; + + /* Incorporate the low 12 bits - these decrease the returned value by + * multiplying by a number less than 1 if the bit is set. The multiplier + * is determined by the above table and the shift. Notice that the values + * converge on 45426 and this is used to allow linear interpolation of the + * low bits. + */ + if (x & 0x800) + e -= (((e >> 16) * 44938U) + 16U) >> 5; + + if (x & 0x400) + e -= (((e >> 16) * 45181U) + 32U) >> 6; + + if (x & 0x200) + e -= (((e >> 16) * 45303U) + 64U) >> 7; + + if (x & 0x100) + e -= (((e >> 16) * 45365U) + 128U) >> 8; + + if (x & 0x080) + e -= (((e >> 16) * 45395U) + 256U) >> 9; + + if (x & 0x040) + e -= (((e >> 16) * 45410U) + 512U) >> 10; + + /* And handle the low 6 bits in a single block. */ + e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9; + + /* Handle the upper bits of x. */ + e >>= x >> 16; + return e; + } + + /* Check for overflow */ + if (x <= 0) + return png_32bit_exp[0]; + + /* Else underflow */ + return 0; +} + +static png_byte +png_exp8bit(png_fixed_point lg2) +{ + /* Get a 32-bit value: */ + png_uint_32 x = png_exp(lg2); + + /* Convert the 32-bit value to 0..255 by multiplying by 256-1, note that the + * second, rounding, step can't overflow because of the first, subtraction, + * step. + */ + x -= x >> 8; + return (png_byte)((x + 0x7fffffU) >> 24); +} + +static png_uint_16 +png_exp16bit(png_fixed_point lg2) +{ + /* Get a 32-bit value: */ + png_uint_32 x = png_exp(lg2); + + /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */ + x -= x >> 16; + return (png_uint_16)((x + 32767U) >> 16); +} +#endif /* FLOATING_ARITHMETIC */ + +png_byte +png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) +{ + if (value > 0 && value < 255) + { +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = floor(255*pow(value/255.,gamma_val*.00001)+.5); + return (png_byte)r; +# else + png_int_32 lg2 = png_log8bit(value); + png_fixed_point res; + + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1)) + return png_exp8bit(res); + + /* Overflow. */ + value = 0; +# endif + } + + return (png_byte)value; +} + +png_uint_16 +png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val) +{ + if (value > 0 && value < 65535) + { +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = floor(65535*pow(value/65535.,gamma_val*.00001)+.5); + return (png_uint_16)r; +# else + png_int_32 lg2 = png_log16bit(value); + png_fixed_point res; + + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1)) + return png_exp16bit(res); + + /* Overflow. */ + value = 0; +# endif + } + + return (png_uint_16)value; +} + +/* This does the right thing based on the bit_depth field of the + * png_struct, interpreting values as 8-bit or 16-bit. While the result + * is nominally a 16-bit value if bit depth is 8 then the result is + * 8-bit (as are the arguments.) + */ +png_uint_16 /* PRIVATE */ +png_gamma_correct(png_structrp png_ptr, unsigned int value, + png_fixed_point gamma_val) +{ + if (png_ptr->bit_depth == 8) + return png_gamma_8bit_correct(value, gamma_val); + + else + return png_gamma_16bit_correct(value, gamma_val); +} + +/* Internal function to build a single 16-bit table - the table consists of + * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount + * to shift the input values right (or 16-number_of_signifiant_bits). + * + * The caller is responsible for ensuring that the table gets cleaned up on + * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument + * should be somewhere that will be cleaned. + */ +static void +png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, + PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) +{ + /* Various values derived from 'shift': */ + PNG_CONST unsigned int num = 1U << (8U - shift); + PNG_CONST unsigned int max = (1U << (16U - shift))-1U; + PNG_CONST unsigned int max_by_2 = 1U << (15U-shift); + unsigned int i; + + png_uint_16pp table = *ptable = + (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); + + for (i = 0; i < num; i++) + { + png_uint_16p sub_table = table[i] = + (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16))); + + /* The 'threshold' test is repeated here because it can arise for one of + * the 16-bit tables even if the others don't hit it. + */ + if (png_gamma_significant(gamma_val)) + { + /* The old code would overflow at the end and this would cause the + * 'pow' function to return a result >1, resulting in an + * arithmetic error. This code follows the spec exactly; ig is + * the recovered input sample, it always has 8-16 bits. + * + * We want input * 65535/max, rounded, the arithmetic fits in 32 + * bits (unsigned) so long as max <= 32767. + */ + unsigned int j; + for (j = 0; j < 256; j++) + { + png_uint_32 ig = (j << (8-shift)) + i; +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* Inline the 'max' scaling operation: */ + double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5); + sub_table[j] = (png_uint_16)d; +# else + if (shift) + ig = (ig * 65535U + max_by_2)/max; + + sub_table[j] = png_gamma_16bit_correct(ig, gamma_val); +# endif + } + } + else + { + /* We must still build a table, but do it the fast way. */ + unsigned int j; + + for (j = 0; j < 256; j++) + { + png_uint_32 ig = (j << (8-shift)) + i; + + if (shift) + ig = (ig * 65535U + max_by_2)/max; + + sub_table[j] = (png_uint_16)ig; + } + } + } +} + +/* NOTE: this function expects the *inverse* of the overall gamma transformation + * required. + */ +static void +png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable, + PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) +{ + PNG_CONST unsigned int num = 1U << (8U - shift); + PNG_CONST unsigned int max = (1U << (16U - shift))-1U; + unsigned int i; + png_uint_32 last; + + png_uint_16pp table = *ptable = + (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); + + /* 'num' is the number of tables and also the number of low bits of low + * bits of the input 16-bit value used to select a table. Each table is + * itself index by the high 8 bits of the value. + */ + for (i = 0; i < num; i++) + table[i] = (png_uint_16p)png_malloc(png_ptr, + 256 * (sizeof (png_uint_16))); + + /* 'gamma_val' is set to the reciprocal of the value calculated above, so + * pow(out,g) is an *input* value. 'last' is the last input value set. + * + * In the loop 'i' is used to find output values. Since the output is + * 8-bit there are only 256 possible values. The tables are set up to + * select the closest possible output value for each input by finding + * the input value at the boundary between each pair of output values + * and filling the table up to that boundary with the lower output + * value. + * + * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9-bit + * values the code below uses a 16-bit value in i; the values start at + * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last + * entries are filled with 255). Start i at 128 and fill all 'last' + * table entries <= 'max' + */ + last = 0; + for (i = 0; i < 255; ++i) /* 8-bit output value */ + { + /* Find the corresponding maximum input value */ + png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */ + + /* Find the boundary value in 16 bits: */ + png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val); + + /* Adjust (round) to (16-shift) bits: */ + bound = (bound * max + 32768U)/65535U + 1U; + + while (last < bound) + { + table[last & (0xffU >> shift)][last >> (8U - shift)] = out; + last++; + } + } + + /* And fill in the final entries. */ + while (last < (num << 8)) + { + table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U; + last++; + } +} + +/* Build a single 8-bit table: same as the 16-bit case but much simpler (and + * typically much faster). Note that libpng currently does no sBIT processing + * (apparently contrary to the spec) so a 256 entry table is always generated. + */ +static void +png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable, + PNG_CONST png_fixed_point gamma_val) +{ + unsigned int i; + png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256); + + if (png_gamma_significant(gamma_val)) for (i=0; i<256; i++) + table[i] = png_gamma_8bit_correct(i, gamma_val); + + else for (i=0; i<256; ++i) + table[i] = (png_byte)i; +} + +/* Used from png_read_destroy and below to release the memory used by the gamma + * tables. + */ +void /* PRIVATE */ +png_destroy_gamma_table(png_structrp png_ptr) +{ + png_free(png_ptr, png_ptr->gamma_table); + png_ptr->gamma_table = NULL; + + if (png_ptr->gamma_16_table != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_table[i]); + } + png_free(png_ptr, png_ptr->gamma_16_table); + png_ptr->gamma_16_table = NULL; + } + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_free(png_ptr, png_ptr->gamma_from_1); + png_ptr->gamma_from_1 = NULL; + png_free(png_ptr, png_ptr->gamma_to_1); + png_ptr->gamma_to_1 = NULL; + + if (png_ptr->gamma_16_from_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_from_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_from_1); + png_ptr->gamma_16_from_1 = NULL; + } + if (png_ptr->gamma_16_to_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_to_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_to_1); + png_ptr->gamma_16_to_1 = NULL; + } +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ +} + +/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit + * tables, we don't make a full table if we are reducing to 8-bit in + * the future. Note also how the gamma_16 tables are segmented so that + * we don't need to allocate > 64K chunks for a full 16-bit table. + */ +void /* PRIVATE */ +png_build_gamma_table(png_structrp png_ptr, int bit_depth) +{ + png_debug(1, "in png_build_gamma_table"); + + /* Remove any existing table; this copes with multiple calls to + * png_read_update_info. The warning is because building the gamma tables + * multiple times is a performance hit - it's harmless but the ability to call + * png_read_update_info() multiple times is new in 1.5.6 so it seems sensible + * to warn if the app introduces such a hit. + */ + if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL) + { + png_warning(png_ptr, "gamma table being rebuilt"); + png_destroy_gamma_table(png_ptr); + } + + if (bit_depth <= 8) + { + png_build_8bit_table(png_ptr, &png_ptr->gamma_table, + png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) + { + png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, + png_reciprocal(png_ptr->colorspace.gamma)); + + png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1, + png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : + png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); + } +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ + } + else + { + png_byte shift, sig_bit; + + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit = png_ptr->sig_bit.red; + + if (png_ptr->sig_bit.green > sig_bit) + sig_bit = png_ptr->sig_bit.green; + + if (png_ptr->sig_bit.blue > sig_bit) + sig_bit = png_ptr->sig_bit.blue; + } + else + sig_bit = png_ptr->sig_bit.gray; + + /* 16-bit gamma code uses this equation: + * + * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8] + * + * Where 'iv' is the input color value and 'ov' is the output value - + * pow(iv, gamma). + * + * Thus the gamma table consists of up to 256 256 entry tables. The table + * is selected by the (8-gamma_shift) most significant of the low 8 bits of + * the color value then indexed by the upper 8 bits: + * + * table[low bits][high 8 bits] + * + * So the table 'n' corresponds to all those 'iv' of: + * + * ..<(n+1 << gamma_shift)-1> + * + */ + if (sig_bit > 0 && sig_bit < 16U) + shift = (png_byte)(16U - sig_bit); /* shift == insignificant bits */ + + else + shift = 0; /* keep all 16 bits */ + + if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) + { + /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively + * the significant bits in the *input* when the output will + * eventually be 8 bits. By default it is 11. + */ + if (shift < (16U - PNG_MAX_GAMMA_8)) + shift = (16U - PNG_MAX_GAMMA_8); + } + + if (shift > 8U) + shift = 8U; /* Guarantees at least one table! */ + + png_ptr->gamma_shift = shift; + +#ifdef PNG_16BIT_SUPPORTED + /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now + * PNG_COMPOSE). This effectively smashed the background calculation for + * 16-bit output because the 8-bit table assumes the result will be reduced + * to 8 bits. + */ + if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) +#endif + png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift, + png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); + +#ifdef PNG_16BIT_SUPPORTED + else + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift, + png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) + { + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift, + png_reciprocal(png_ptr->colorspace.gamma)); + + /* Notice that the '16 from 1' table should be full precision, however + * the lookup on this table still uses gamma_shift, so it can't be. + * TODO: fix this. + */ + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift, + png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : + png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); + } +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ + } +} +#endif /* READ_GAMMA */ + +/* HARDWARE OPTION SUPPORT */ +#ifdef PNG_SET_OPTION_SUPPORTED +int PNGAPI +png_set_option(png_structrp png_ptr, int option, int onoff) +{ + if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT && + (option & 1) == 0) + { + int mask = 3 << option; + int setting = (2 + (onoff != 0)) << option; + int current = png_ptr->options; + + png_ptr->options = (png_byte)((current & ~mask) | setting); + + return (current & mask) >> option; + } + + return PNG_OPTION_INVALID; +} +#endif + +/* sRGB support */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/* sRGB conversion tables; these are machine generated with the code in + * contrib/tools/makesRGB.c. The actual sRGB transfer curve defined in the + * specification (see the article at http://en.wikipedia.org/wiki/SRGB) + * is used, not the gamma=1/2.2 approximation use elsewhere in libpng. + * The sRGB to linear table is exact (to the nearest 16 bit linear fraction). + * The inverse (linear to sRGB) table has accuracies as follows: + * + * For all possible (255*65535+1) input values: + * + * error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact + * + * For the input values corresponding to the 65536 16-bit values: + * + * error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact + * + * In all cases the inexact readings are off by one. + */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* The convert-to-sRGB table is only currently required for read. */ +const png_uint_16 png_sRGB_table[256] = +{ + 0,20,40,60,80,99,119,139, + 159,179,199,219,241,264,288,313, + 340,367,396,427,458,491,526,562, + 599,637,677,718,761,805,851,898, + 947,997,1048,1101,1156,1212,1270,1330, + 1391,1453,1517,1583,1651,1720,1790,1863, + 1937,2013,2090,2170,2250,2333,2418,2504, + 2592,2681,2773,2866,2961,3058,3157,3258, + 3360,3464,3570,3678,3788,3900,4014,4129, + 4247,4366,4488,4611,4736,4864,4993,5124, + 5257,5392,5530,5669,5810,5953,6099,6246, + 6395,6547,6700,6856,7014,7174,7335,7500, + 7666,7834,8004,8177,8352,8528,8708,8889, + 9072,9258,9445,9635,9828,10022,10219,10417, + 10619,10822,11028,11235,11446,11658,11873,12090, + 12309,12530,12754,12980,13209,13440,13673,13909, + 14146,14387,14629,14874,15122,15371,15623,15878, + 16135,16394,16656,16920,17187,17456,17727,18001, + 18277,18556,18837,19121,19407,19696,19987,20281, + 20577,20876,21177,21481,21787,22096,22407,22721, + 23038,23357,23678,24002,24329,24658,24990,25325, + 25662,26001,26344,26688,27036,27386,27739,28094, + 28452,28813,29176,29542,29911,30282,30656,31033, + 31412,31794,32179,32567,32957,33350,33745,34143, + 34544,34948,35355,35764,36176,36591,37008,37429, + 37852,38278,38706,39138,39572,40009,40449,40891, + 41337,41785,42236,42690,43147,43606,44069,44534, + 45002,45473,45947,46423,46903,47385,47871,48359, + 48850,49344,49841,50341,50844,51349,51858,52369, + 52884,53401,53921,54445,54971,55500,56032,56567, + 57105,57646,58190,58737,59287,59840,60396,60955, + 61517,62082,62650,63221,63795,64372,64952,65535 +}; + +#endif /* simplified read only */ + +/* The base/delta tables are required for both read and write (but currently + * only the simplified versions.) + */ +const png_uint_16 png_sRGB_base[512] = +{ + 128,1782,3383,4644,5675,6564,7357,8074, + 8732,9346,9921,10463,10977,11466,11935,12384, + 12816,13233,13634,14024,14402,14769,15125,15473, + 15812,16142,16466,16781,17090,17393,17690,17981, + 18266,18546,18822,19093,19359,19621,19879,20133, + 20383,20630,20873,21113,21349,21583,21813,22041, + 22265,22487,22707,22923,23138,23350,23559,23767, + 23972,24175,24376,24575,24772,24967,25160,25352, + 25542,25730,25916,26101,26284,26465,26645,26823, + 27000,27176,27350,27523,27695,27865,28034,28201, + 28368,28533,28697,28860,29021,29182,29341,29500, + 29657,29813,29969,30123,30276,30429,30580,30730, + 30880,31028,31176,31323,31469,31614,31758,31902, + 32045,32186,32327,32468,32607,32746,32884,33021, + 33158,33294,33429,33564,33697,33831,33963,34095, + 34226,34357,34486,34616,34744,34873,35000,35127, + 35253,35379,35504,35629,35753,35876,35999,36122, + 36244,36365,36486,36606,36726,36845,36964,37083, + 37201,37318,37435,37551,37668,37783,37898,38013, + 38127,38241,38354,38467,38580,38692,38803,38915, + 39026,39136,39246,39356,39465,39574,39682,39790, + 39898,40005,40112,40219,40325,40431,40537,40642, + 40747,40851,40955,41059,41163,41266,41369,41471, + 41573,41675,41777,41878,41979,42079,42179,42279, + 42379,42478,42577,42676,42775,42873,42971,43068, + 43165,43262,43359,43456,43552,43648,43743,43839, + 43934,44028,44123,44217,44311,44405,44499,44592, + 44685,44778,44870,44962,45054,45146,45238,45329, + 45420,45511,45601,45692,45782,45872,45961,46051, + 46140,46229,46318,46406,46494,46583,46670,46758, + 46846,46933,47020,47107,47193,47280,47366,47452, + 47538,47623,47709,47794,47879,47964,48048,48133, + 48217,48301,48385,48468,48552,48635,48718,48801, + 48884,48966,49048,49131,49213,49294,49376,49458, + 49539,49620,49701,49782,49862,49943,50023,50103, + 50183,50263,50342,50422,50501,50580,50659,50738, + 50816,50895,50973,51051,51129,51207,51285,51362, + 51439,51517,51594,51671,51747,51824,51900,51977, + 52053,52129,52205,52280,52356,52432,52507,52582, + 52657,52732,52807,52881,52956,53030,53104,53178, + 53252,53326,53400,53473,53546,53620,53693,53766, + 53839,53911,53984,54056,54129,54201,54273,54345, + 54417,54489,54560,54632,54703,54774,54845,54916, + 54987,55058,55129,55199,55269,55340,55410,55480, + 55550,55620,55689,55759,55828,55898,55967,56036, + 56105,56174,56243,56311,56380,56448,56517,56585, + 56653,56721,56789,56857,56924,56992,57059,57127, + 57194,57261,57328,57395,57462,57529,57595,57662, + 57728,57795,57861,57927,57993,58059,58125,58191, + 58256,58322,58387,58453,58518,58583,58648,58713, + 58778,58843,58908,58972,59037,59101,59165,59230, + 59294,59358,59422,59486,59549,59613,59677,59740, + 59804,59867,59930,59993,60056,60119,60182,60245, + 60308,60370,60433,60495,60558,60620,60682,60744, + 60806,60868,60930,60992,61054,61115,61177,61238, + 61300,61361,61422,61483,61544,61605,61666,61727, + 61788,61848,61909,61969,62030,62090,62150,62211, + 62271,62331,62391,62450,62510,62570,62630,62689, + 62749,62808,62867,62927,62986,63045,63104,63163, + 63222,63281,63340,63398,63457,63515,63574,63632, + 63691,63749,63807,63865,63923,63981,64039,64097, + 64155,64212,64270,64328,64385,64443,64500,64557, + 64614,64672,64729,64786,64843,64900,64956,65013, + 65070,65126,65183,65239,65296,65352,65409,65465 +}; + +const png_byte png_sRGB_delta[512] = +{ + 207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54, + 52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36, + 35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28, + 28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24, + 23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21, + 21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19, + 19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17, + 17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; +#endif /* SIMPLIFIED READ/WRITE sRGB support */ + +/* SIMPLIFIED READ/WRITE SUPPORT */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +static int +png_image_free_function(png_voidp argument) +{ + png_imagep image = png_voidcast(png_imagep, argument); + png_controlp cp = image->opaque; + png_control c; + + /* Double check that we have a png_ptr - it should be impossible to get here + * without one. + */ + if (cp->png_ptr == NULL) + return 0; + + /* First free any data held in the control structure. */ +# ifdef PNG_STDIO_SUPPORTED + if (cp->owned_file) + { + FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr); + cp->owned_file = 0; + + /* Ignore errors here. */ + if (fp != NULL) + { + cp->png_ptr->io_ptr = NULL; + (void)fclose(fp); + } + } +# endif + + /* Copy the control structure so that the original, allocated, version can be + * safely freed. Notice that a png_error here stops the remainder of the + * cleanup, but this is probably fine because that would indicate bad memory + * problems anyway. + */ + c = *cp; + image->opaque = &c; + png_free(c.png_ptr, cp); + + /* Then the structures, calling the correct API. */ + if (c.for_write) + { +# ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED + png_destroy_write_struct(&c.png_ptr, &c.info_ptr); +# else + png_error(c.png_ptr, "simplified write not supported"); +# endif + } + else + { +# ifdef PNG_SIMPLIFIED_READ_SUPPORTED + png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL); +# else + png_error(c.png_ptr, "simplified read not supported"); +# endif + } + + /* Success. */ + return 1; +} + +void PNGAPI +png_image_free(png_imagep image) +{ + /* Safely call the real function, but only if doing so is safe at this point + * (if not inside an error handling context). Otherwise assume + * png_safe_execute will call this API after the return. + */ + if (image != NULL && image->opaque != NULL && + image->opaque->error_buf == NULL) + { + /* Ignore errors here: */ + (void)png_safe_execute(image, png_image_free_function, image); + image->opaque = NULL; + } +} + +int /* PRIVATE */ +png_image_error(png_imagep image, png_const_charp error_message) +{ + /* Utility to log an error. */ + png_safecat(image->message, (sizeof image->message), 0, error_message); + image->warning_or_error |= PNG_IMAGE_ERROR; + png_image_free(image); + return 0; +} + +#endif /* SIMPLIFIED READ/WRITE */ +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ +#endif diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngerror.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngerror.c new file mode 100644 index 0000000000..e53c932542 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngerror.c @@ -0,0 +1,933 @@ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +/* pngerror.c - stub functions for i/o and memory allocation + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all error handling. Users who + * need special error handling are expected to write replacement functions + * and use png_set_error_fn() to use those functions. See the instructions + * at each function. + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr, + png_const_charp error_message)),PNG_NORETURN); + +#ifdef PNG_WARNINGS_SUPPORTED +static void /* PRIVATE */ +png_default_warning PNGARG((png_const_structrp png_ptr, + png_const_charp warning_message)); +#endif /* PNG_WARNINGS_SUPPORTED */ + +/* This function is called whenever there is a fatal error. This function + * should not be changed. If there is a need to handle errors differently, + * you should supply a replacement error function and use png_set_error_fn() + * to replace the error function at run-time. + */ +#ifdef PNG_ERROR_TEXT_SUPPORTED +PNG_FUNCTION(void,PNGAPI +png_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) +{ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + char msg[16]; + if (png_ptr != NULL) + { + if (png_ptr->flags& + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) + { + if (*error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + for (offset = 1; offset<15; offset++) + if (error_message[offset] == ' ') + break; + + if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + { + int i; + for (i = 0; i < offset - 1; i++) + msg[i] = error_message[i + 1]; + msg[i - 1] = '\0'; + error_message = msg; + } + + else + error_message += offset; + } + + else + { + if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + { + msg[0] = '0'; + msg[1] = '\0'; + error_message = msg; + } + } + } + } +#endif + if (png_ptr != NULL && png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), + error_message); + + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ + png_default_error(png_ptr, error_message); +} +#else +PNG_FUNCTION(void,PNGAPI +png_err,(png_const_structrp png_ptr),PNG_NORETURN) +{ + /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed + * erroneously as '\0', instead of the empty string "". This was + * apparently an error, introduced in libpng-1.2.20, and png_default_error + * will crash in this case. + */ + if (png_ptr != NULL && png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), ""); + + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ + png_default_error(png_ptr, ""); +} +#endif /* PNG_ERROR_TEXT_SUPPORTED */ + +/* Utility to safely appends strings to a buffer. This never errors out so + * error checking is not required in the caller. + */ +size_t +png_safecat(png_charp buffer, size_t bufsize, size_t pos, + png_const_charp string) +{ + if (buffer != NULL && pos < bufsize) + { + if (string != NULL) + while (*string != '\0' && pos < bufsize-1) + buffer[pos++] = *string++; + + buffer[pos] = '\0'; + } + + return pos; +} + +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) +/* Utility to dump an unsigned value into a buffer, given a start pointer and + * and end pointer (which should point just *beyond* the end of the buffer!) + * Returns the pointer to the start of the formatted string. + */ +png_charp +png_format_number(png_const_charp start, png_charp end, int format, + png_alloc_size_t number) +{ + int count = 0; /* number of digits output */ + int mincount = 1; /* minimum number required */ + int output = 0; /* digit output (for the fixed point format) */ + + *--end = '\0'; + + /* This is written so that the loop always runs at least once, even with + * number zero. + */ + while (end > start && (number != 0 || count < mincount)) + { + + static const char digits[] = "0123456789ABCDEF"; + + switch (format) + { + case PNG_NUMBER_FORMAT_fixed: + /* Needs five digits (the fraction) */ + mincount = 5; + if (output || number % 10 != 0) + { + *--end = digits[number % 10]; + output = 1; + } + number /= 10; + break; + + case PNG_NUMBER_FORMAT_02u: + /* Expects at least 2 digits. */ + mincount = 2; + /* FALL THROUGH */ + + case PNG_NUMBER_FORMAT_u: + *--end = digits[number % 10]; + number /= 10; + break; + + case PNG_NUMBER_FORMAT_02x: + /* This format expects at least two digits */ + mincount = 2; + /* FALL THROUGH */ + + case PNG_NUMBER_FORMAT_x: + *--end = digits[number & 0xf]; + number >>= 4; + break; + + default: /* an error */ + number = 0; + break; + } + + /* Keep track of the number of digits added */ + ++count; + + /* Float a fixed number here: */ + if (format == PNG_NUMBER_FORMAT_fixed) if (count == 5) if (end > start) + { + /* End of the fraction, but maybe nothing was output? In that case + * drop the decimal point. If the number is a true zero handle that + * here. + */ + if (output) + *--end = '.'; + else if (number == 0) /* and !output */ + *--end = '0'; + } + } + + return end; +} +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* This function is called whenever there is a non-fatal error. This function + * should not be changed. If there is a need to handle warnings differently, + * you should supply a replacement warning function and use + * png_set_error_fn() to replace the warning function at run-time. + */ +void PNGAPI +png_warning(png_const_structrp png_ptr, png_const_charp warning_message) +{ + int offset = 0; + if (png_ptr != NULL) + { +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (png_ptr->flags& + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) +#endif + { + if (*warning_message == PNG_LITERAL_SHARP) + { + for (offset = 1; offset < 15; offset++) + if (warning_message[offset] == ' ') + break; + } + } + } + if (png_ptr != NULL && png_ptr->warning_fn != NULL) + (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr), + warning_message + offset); + else + png_default_warning(png_ptr, warning_message + offset); +} + +/* These functions support 'formatted' warning messages with up to + * PNG_WARNING_PARAMETER_COUNT parameters. In the format string the parameter + * is introduced by @, where 'number' starts at 1. This follows the + * standard established by X/Open for internationalizable error messages. + */ +void +png_warning_parameter(png_warning_parameters p, int number, + png_const_charp string) +{ + if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT) + (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string); +} + +void +png_warning_parameter_unsigned(png_warning_parameters p, int number, int format, + png_alloc_size_t value) +{ + char buffer[PNG_NUMBER_BUFFER_SIZE]; + png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value)); +} + +void +png_warning_parameter_signed(png_warning_parameters p, int number, int format, + png_int_32 value) +{ + png_alloc_size_t u; + png_charp str; + char buffer[PNG_NUMBER_BUFFER_SIZE]; + + /* Avoid overflow by doing the negate in a png_alloc_size_t: */ + u = (png_alloc_size_t)value; + if (value < 0) + u = ~u + 1; + + str = PNG_FORMAT_NUMBER(buffer, format, u); + + if (value < 0 && str > buffer) + *--str = '-'; + + png_warning_parameter(p, number, str); +} + +void +png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p, + png_const_charp message) +{ + /* The internal buffer is just 192 bytes - enough for all our messages, + * overflow doesn't happen because this code checks! If someone figures + * out how to send us a message longer than 192 bytes, all that will + * happen is that the message will be truncated appropriately. + */ + size_t i = 0; /* Index in the msg[] buffer: */ + char msg[192]; + + /* Each iteration through the following loop writes at most one character + * to msg[i++] then returns here to validate that there is still space for + * the trailing '\0'. It may (in the case of a parameter) read more than + * one character from message[]; it must check for '\0' and continue to the + * test if it finds the end of string. + */ + while (i<(sizeof msg)-1 && *message != '\0') + { + /* '@' at end of string is now just printed (previously it was skipped); + * it is an error in the calling code to terminate the string with @. + */ + if (p != NULL && *message == '@' && message[1] != '\0') + { + int parameter_char = *++message; /* Consume the '@' */ + static const char valid_parameters[] = "123456789"; + int parameter = 0; + + /* Search for the parameter digit, the index in the string is the + * parameter to use. + */ + while (valid_parameters[parameter] != parameter_char && + valid_parameters[parameter] != '\0') + ++parameter; + + /* If the parameter digit is out of range it will just get printed. */ + if (parameter < PNG_WARNING_PARAMETER_COUNT) + { + /* Append this parameter */ + png_const_charp parm = p[parameter]; + png_const_charp pend = p[parameter] + (sizeof p[parameter]); + + /* No need to copy the trailing '\0' here, but there is no guarantee + * that parm[] has been initialized, so there is no guarantee of a + * trailing '\0': + */ + while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend) + msg[i++] = *parm++; + + /* Consume the parameter digit too: */ + ++message; + continue; + } + + /* else not a parameter and there is a character after the @ sign; just + * copy that. This is known not to be '\0' because of the test above. + */ + } + + /* At this point *message can't be '\0', even in the bad parameter case + * above where there is a lone '@' at the end of the message string. + */ + msg[i++] = *message++; + } + + /* i is always less than (sizeof msg), so: */ + msg[i] = '\0'; + + /* And this is the formatted message. It may be larger than + * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these + * are not (currently) formatted. + */ + png_warning(png_ptr, msg); +} +#endif /* PNG_WARNINGS_SUPPORTED */ + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) +{ + if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) + { +# ifdef PNG_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + png_ptr->chunk_name != 0) + png_chunk_warning(png_ptr, error_message); + else +# endif + png_warning(png_ptr, error_message); + } + + else + { +# ifdef PNG_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + png_ptr->chunk_name != 0) + png_chunk_error(png_ptr, error_message); + else +# endif + png_error(png_ptr, error_message); + } +} + +void /* PRIVATE */ +png_app_warning(png_const_structrp png_ptr, png_const_charp error_message) +{ + if (png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); +} + +void /* PRIVATE */ +png_app_error(png_const_structrp png_ptr, png_const_charp error_message) +{ + if (png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); +} +#endif /* BENIGN_ERRORS */ + +/* These utilities are used internally to build an error message that relates + * to the current chunk. The chunk name comes from png_ptr->chunk_name, + * this is used to prefix the message. The message is limited in length + * to 63 bytes, the name characters are output as hex digits wrapped in [] + * if the character is invalid. + */ +#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) +static PNG_CONST char png_digit[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' +}; + +#define PNG_MAX_ERROR_TEXT 196 /* Currently limited be profile_error in png.c */ +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) +static void /* PRIVATE */ +png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp + error_message) +{ + png_uint_32 chunk_name = png_ptr->chunk_name; + int iout = 0, ishift = 24; + + while (ishift >= 0) + { + int c = (int)(chunk_name >> ishift) & 0xff; + + ishift -= 8; + if (isnonalpha(c)) + { + buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; + buffer[iout++] = png_digit[(c & 0xf0) >> 4]; + buffer[iout++] = png_digit[c & 0x0f]; + buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET; + } + + else + { + buffer[iout++] = (char)c; + } + } + + if (error_message == NULL) + buffer[iout] = '\0'; + + else + { + int iin = 0; + + buffer[iout++] = ':'; + buffer[iout++] = ' '; + + while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0') + buffer[iout++] = error_message[iin++]; + + /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */ + buffer[iout] = '\0'; + } +} +#endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */ + +#if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) +PNG_FUNCTION(void,PNGAPI +png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) +{ + char msg[18+PNG_MAX_ERROR_TEXT]; + if (png_ptr == NULL) + png_error(png_ptr, error_message); + + else + { + png_format_buffer(png_ptr, msg, error_message); + png_error(png_ptr, msg); + } +} +#endif /* PNG_READ_SUPPORTED && PNG_ERROR_TEXT_SUPPORTED */ + +#ifdef PNG_WARNINGS_SUPPORTED +void PNGAPI +png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message) +{ + char msg[18+PNG_MAX_ERROR_TEXT]; + if (png_ptr == NULL) + png_warning(png_ptr, warning_message); + + else + { + png_format_buffer(png_ptr, msg, warning_message); + png_warning(png_ptr, msg); + } +} +#endif /* PNG_WARNINGS_SUPPORTED */ + +#ifdef PNG_READ_SUPPORTED +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp + error_message) +{ + if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) + png_chunk_warning(png_ptr, error_message); + + else + png_chunk_error(png_ptr, error_message); +} +#endif +#endif /* PNG_READ_SUPPORTED */ + +void /* PRIVATE */ +png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) +{ + /* This is always supported, but for just read or just write it + * unconditionally does the right thing. + */ +# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) + if (png_ptr->mode & PNG_IS_READ_STRUCT) +# endif + +# ifdef PNG_READ_SUPPORTED + { + if (error < PNG_CHUNK_ERROR) + png_chunk_warning(png_ptr, message); + + else + png_chunk_benign_error(png_ptr, message); + } +# endif + +# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) + else if (!(png_ptr->mode & PNG_IS_READ_STRUCT)) +# endif + +# ifdef PNG_WRITE_SUPPORTED + { + if (error < PNG_CHUNK_WRITE_ERROR) + png_app_warning(png_ptr, message); + + else + png_app_error(png_ptr, message); + } +# endif +} + +#ifdef PNG_ERROR_TEXT_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_FUNCTION(void, +png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN) +{ +# define fixed_message "fixed point overflow in " +# define fixed_message_ln ((sizeof fixed_message)-1) + int iin; + char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT]; + memcpy(msg, fixed_message, fixed_message_ln); + iin = 0; + if (name != NULL) while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0) + { + msg[fixed_message_ln + iin] = name[iin]; + ++iin; + } + msg[fixed_message_ln + iin] = 0; + png_error(png_ptr, msg); +} +#endif +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This API only exists if ANSI-C style error handling is used, + * otherwise it is necessary for png_default_error to be overridden. + */ +jmp_buf* PNGAPI +png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn, + size_t jmp_buf_size) +{ + /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value + * and it must not change after that. Libpng doesn't care how big the + * buffer is, just that it doesn't change. + * + * If the buffer size is no *larger* than the size of jmp_buf when libpng is + * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0 + * semantics that this call will not fail. If the size is larger, however, + * the buffer is allocated and this may fail, causing the function to return + * NULL. + */ + if (png_ptr == NULL) + return NULL; + + if (png_ptr->jmp_buf_ptr == NULL) + { + png_ptr->jmp_buf_size = 0; /* not allocated */ + + if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local)) + png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; + + else + { + png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *, + png_malloc_warn(png_ptr, jmp_buf_size)); + + if (png_ptr->jmp_buf_ptr == NULL) + return NULL; /* new NULL return on OOM */ + + png_ptr->jmp_buf_size = jmp_buf_size; + } + } + + else /* Already allocated: check the size */ + { + size_t size = png_ptr->jmp_buf_size; + + if (size == 0) + { + size = (sizeof png_ptr->jmp_buf_local); + if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local) + { + /* This is an internal error in libpng: somehow we have been left + * with a stack allocated jmp_buf when the application regained + * control. It's always possible to fix this up, but for the moment + * this is a png_error because that makes it easy to detect. + */ + png_error(png_ptr, "Libpng jmp_buf still allocated"); + /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */ + } + } + + if (size != jmp_buf_size) + { + png_warning(png_ptr, "Application jmp_buf size changed"); + return NULL; /* caller will probably crash: no choice here */ + } + } + + /* Finally fill in the function, now we have a satisfactory buffer. It is + * valid to change the function on every call. + */ + png_ptr->longjmp_fn = longjmp_fn; + return png_ptr->jmp_buf_ptr; +} + +void /* PRIVATE */ +png_free_jmpbuf(png_structrp png_ptr) +{ + if (png_ptr != NULL) + { + jmp_buf *jb = png_ptr->jmp_buf_ptr; + + /* A size of 0 is used to indicate a local, stack, allocation of the + * pointer; used here and in png.c + */ + if (jb != NULL && png_ptr->jmp_buf_size > 0) + { + + /* This stuff is so that a failure to free the error control structure + * does not leave libpng in a state with no valid error handling: the + * free always succeeds, if there is an error it gets ignored. + */ + if (jb != &png_ptr->jmp_buf_local) + { + /* Make an internal, libpng, jmp_buf to return here */ + jmp_buf free_jmp_buf; + + if (!setjmp(free_jmp_buf)) + { + png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */ + png_ptr->jmp_buf_size = 0; /* stack allocation */ + png_ptr->longjmp_fn = longjmp; + png_free(png_ptr, jb); /* Return to setjmp on error */ + } + } + } + + /* *Always* cancel everything out: */ + png_ptr->jmp_buf_size = 0; + png_ptr->jmp_buf_ptr = NULL; + png_ptr->longjmp_fn = 0; + } +} +#endif + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static PNG_FUNCTION(void /* PRIVATE */, +png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) +{ +#ifdef PNG_CONSOLE_IO_SUPPORTED +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + /* Check on NULL only added in 1.5.4 */ + if (error_message != NULL && *error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + char error_number[16]; + for (offset = 0; offset<15; offset++) + { + error_number[offset] = error_message[offset + 1]; + if (error_message[offset] == ' ') + break; + } + + if ((offset > 1) && (offset < 15)) + { + error_number[offset - 1] = '\0'; + fprintf(stderr, "libpng error no. %s: %s", + error_number, error_message + offset + 1); + fprintf(stderr, PNG_STRING_NEWLINE); + } + + else + { + fprintf(stderr, "libpng error: %s, offset=%d", + error_message, offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +#endif + { + fprintf(stderr, "libpng error: %s", error_message ? error_message : + "undefined"); + fprintf(stderr, PNG_STRING_NEWLINE); + } +#else + PNG_UNUSED(error_message) /* Make compiler happy */ +#endif + png_longjmp(png_ptr, 1); +} + +PNG_FUNCTION(void,PNGAPI +png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN) +{ +#ifdef PNG_SETJMP_SUPPORTED + if (png_ptr && png_ptr->longjmp_fn && png_ptr->jmp_buf_ptr) + png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val); +#endif + + /* Here if not setjmp support or if png_ptr is null. */ + PNG_ABORT(); +} + +#ifdef PNG_WARNINGS_SUPPORTED +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want them to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void /* PRIVATE */ +png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message) +{ +#ifdef PNG_CONSOLE_IO_SUPPORTED +# ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*warning_message == PNG_LITERAL_SHARP) + { + int offset; + char warning_number[16]; + for (offset = 0; offset < 15; offset++) + { + warning_number[offset] = warning_message[offset + 1]; + if (warning_message[offset] == ' ') + break; + } + + if ((offset > 1) && (offset < 15)) + { + warning_number[offset + 1] = '\0'; + fprintf(stderr, "libpng warning no. %s: %s", + warning_number, warning_message + offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + + else + { + fprintf(stderr, "libpng warning: %s", + warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +# endif + + { + fprintf(stderr, "libpng warning: %s", warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } +#else + PNG_UNUSED(warning_message) /* Make compiler happy */ +#endif + PNG_UNUSED(png_ptr) /* Make compiler happy */ +} +#endif /* PNG_WARNINGS_SUPPORTED */ + +/* This function is called when the application wants to use another method + * of handling errors and warnings. Note that the error function MUST NOT + * return to the calling routine or serious problems will occur. The return + * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1) + */ +void PNGAPI +png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->error_ptr = error_ptr; + png_ptr->error_fn = error_fn; +#ifdef PNG_WARNINGS_SUPPORTED + png_ptr->warning_fn = warning_fn; +#else + PNG_UNUSED(warning_fn) +#endif +} + + +/* This function returns a pointer to the error_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_error_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return NULL; + + return ((png_voidp)png_ptr->error_ptr); +} + + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +void PNGAPI +png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode) +{ + if (png_ptr != NULL) + { + png_ptr->flags &= + ((~(PNG_FLAG_STRIP_ERROR_NUMBERS | + PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); + } +} +#endif + +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) + /* Currently the above both depend on SETJMP_SUPPORTED, however it would be + * possible to implement without setjmp support just so long as there is some + * way to handle the error return here: + */ +PNG_FUNCTION(void /* PRIVATE */, +png_safe_error,(png_structp png_nonconst_ptr, png_const_charp error_message), + PNG_NORETURN) +{ + const png_const_structrp png_ptr = png_nonconst_ptr; + png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); + + /* An error is always logged here, overwriting anything (typically a warning) + * that is already there: + */ + if (image != NULL) + { + png_safecat(image->message, (sizeof image->message), 0, error_message); + image->warning_or_error |= PNG_IMAGE_ERROR; + + /* Retrieve the jmp_buf from within the png_control, making this work for + * C++ compilation too is pretty tricky: C++ wants a pointer to the first + * element of a jmp_buf, but C doesn't tell us the type of that. + */ + if (image->opaque != NULL && image->opaque->error_buf != NULL) + longjmp(png_control_jmp_buf(image->opaque), 1); + + /* Missing longjmp buffer, the following is to help debugging: */ + { + size_t pos = png_safecat(image->message, (sizeof image->message), 0, + "bad longjmp: "); + png_safecat(image->message, (sizeof image->message), pos, + error_message); + } + } + + /* Here on an internal programming error. */ + abort(); +} + +#ifdef PNG_WARNINGS_SUPPORTED +void /* PRIVATE */ +png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message) +{ + const png_const_structrp png_ptr = png_nonconst_ptr; + png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); + + /* A warning is only logged if there is no prior warning or error. */ + if (image->warning_or_error == 0) + { + png_safecat(image->message, (sizeof image->message), 0, warning_message); + image->warning_or_error |= PNG_IMAGE_WARNING; + } +} +#endif + +int /* PRIVATE */ +png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg) +{ + volatile png_imagep image = image_in; + volatile int result; + volatile png_voidp saved_error_buf; + jmp_buf safe_jmpbuf; + + /* Safely execute function(arg) with png_error returning to this function. */ + saved_error_buf = image->opaque->error_buf; + result = setjmp(safe_jmpbuf) == 0; + + if (result) + { + + image->opaque->error_buf = safe_jmpbuf; + result = function(arg); + } + + image->opaque->error_buf = saved_error_buf; + + /* And do the cleanup prior to any failure return. */ + if (!result) + png_image_free(image); + + return result; +} +#endif /* SIMPLIFIED READ/WRITE */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngget.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngget.c new file mode 100644 index 0000000000..56ba97090e --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngget.c @@ -0,0 +1,1178 @@ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +/* pngget.c - retrieval of values from info struct + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +png_uint_32 PNGAPI +png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 flag) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->valid & flag); + + return(0); +} + +png_size_t PNGAPI +png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->rowbytes); + + return(0); +} + +#ifdef PNG_INFO_IMAGE_SUPPORTED +png_bytepp PNGAPI +png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->row_pointers); + + return(0); +} +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Easy access to info, added in libpng-0.99 */ +png_uint_32 PNGAPI +png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->width; + + return (0); +} + +png_uint_32 PNGAPI +png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->height; + + return (0); +} + +png_byte PNGAPI +png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->bit_depth; + + return (0); +} + +png_byte PNGAPI +png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->color_type; + + return (0); +} + +png_byte PNGAPI +png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->filter_type; + + return (0); +} + +png_byte PNGAPI +png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->interlace_type; + + return (0); +} + +png_byte PNGAPI +png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->compression_type; + + return (0); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) +{ +#ifdef PNG_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function", + "png_get_x_pixels_per_meter"); + + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) + return (info_ptr->x_pixels_per_unit); + } +#endif + + return (0); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) +{ +#ifdef PNG_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function", + "png_get_y_pixels_per_meter"); + + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) + return (info_ptr->y_pixels_per_unit); + } +#endif + + return (0); +} + +png_uint_32 PNGAPI +png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter"); + + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER && + info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit) + return (info_ptr->x_pixels_per_unit); + } +#endif + + return (0); +} + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp + info_ptr) +{ +#ifdef PNG_READ_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio"); + + if (info_ptr->x_pixels_per_unit != 0) + return ((float)((float)info_ptr->y_pixels_per_unit + /(float)info_ptr->x_pixels_per_unit)); + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return ((float)0.0); +} +#endif + +#ifdef PNG_FIXED_POINT_SUPPORTED +png_fixed_point PNGAPI +png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) +{ +#ifdef PNG_READ_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) + && info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 + && info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX + && info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX) + { + png_fixed_point res; + + png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio_fixed"); + + /* The following casts work because a PNG 4 byte integer only has a valid + * range of 0..2^31-1; otherwise the cast might overflow. + */ + if (png_muldiv(&res, (png_int_32)info_ptr->y_pixels_per_unit, PNG_FP_1, + (png_int_32)info_ptr->x_pixels_per_unit)) + return res; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return 0; +} +#endif + +png_int_32 PNGAPI +png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + { + png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); + + if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) + return (info_ptr->x_offset); + } +#endif + + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + { + png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); + + if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) + return (info_ptr->y_offset); + } +#endif + + return (0); +} + +png_int_32 PNGAPI +png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + { + png_debug1(1, "in %s retrieval function", "png_get_x_offset_pixels"); + + if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) + return (info_ptr->x_offset); + } +#endif + + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + { + png_debug1(1, "in %s retrieval function", "png_get_y_offset_pixels"); + + if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) + return (info_ptr->y_offset); + } +#endif + + return (0); +} + +#ifdef PNG_INCH_CONVERSIONS_SUPPORTED +static png_uint_32 +ppi_from_ppm(png_uint_32 ppm) +{ +#if 0 + /* The conversion is *(2.54/100), in binary (32 digits): + * .00000110100000001001110101001001 + */ + png_uint_32 t1001, t1101; + ppm >>= 1; /* .1 */ + t1001 = ppm + (ppm >> 3); /* .1001 */ + t1101 = t1001 + (ppm >> 1); /* .1101 */ + ppm >>= 20; /* .000000000000000000001 */ + t1101 += t1101 >> 15; /* .1101000000000001101 */ + t1001 >>= 11; /* .000000000001001 */ + t1001 += t1001 >> 12; /* .000000000001001000000001001 */ + ppm += t1001; /* .000000000001001000001001001 */ + ppm += t1101; /* .110100000001001110101001001 */ + return (ppm + 16) >> 5;/* .00000110100000001001110101001001 */ +#else + /* The argument is a PNG unsigned integer, so it is not permitted + * to be bigger than 2^31. + */ + png_fixed_point result; + if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127, + 5000)) + return result; + + /* Overflow. */ + return 0; +#endif +} + +png_uint_32 PNGAPI +png_get_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + return ppi_from_ppm(png_get_pixels_per_meter(png_ptr, info_ptr)); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + return ppi_from_ppm(png_get_x_pixels_per_meter(png_ptr, info_ptr)); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + return ppi_from_ppm(png_get_y_pixels_per_meter(png_ptr, info_ptr)); +} + +#ifdef PNG_FIXED_POINT_SUPPORTED +static png_fixed_point +png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns) +{ + /* Convert from metres * 1,000,000 to inches * 100,000, meters to + * inches is simply *(100/2.54), so we want *(10/2.54) == 500/127. + * Notice that this can overflow - a warning is output and 0 is + * returned. + */ + return png_muldiv_warn(png_ptr, microns, 500, 127); +} + +png_fixed_point PNGAPI +png_get_x_offset_inches_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) +{ + return png_fixed_inches_from_microns(png_ptr, + png_get_x_offset_microns(png_ptr, info_ptr)); +} +#endif + +#ifdef PNG_FIXED_POINT_SUPPORTED +png_fixed_point PNGAPI +png_get_y_offset_inches_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) +{ + return png_fixed_inches_from_microns(png_ptr, + png_get_y_offset_microns(png_ptr, info_ptr)); +} +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_x_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + /* To avoid the overflow do the conversion directly in floating + * point. + */ + return (float)(png_get_x_offset_microns(png_ptr, info_ptr) * .00003937); +} +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_y_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + /* To avoid the overflow do the conversion directly in floating + * point. + */ + return (float)(png_get_y_offset_microns(png_ptr, info_ptr) * .00003937); +} +#endif + +#ifdef PNG_pHYs_SUPPORTED +png_uint_32 PNGAPI +png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function", "pHYs"); + + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + + if (*unit_type == 1) + { + if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50); + if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50); + } + } + } + + return (retval); +} +#endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ + +/* png_get_channels really belongs in here, too, but it's been around longer */ + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + + +png_byte PNGAPI +png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->channels); + + return (0); +} + +#ifdef PNG_READ_SUPPORTED +png_const_bytep PNGAPI +png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->signature); + + return (NULL); +} +#endif + +#ifdef PNG_bKGD_SUPPORTED +png_uint_32 PNGAPI +png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, + png_color_16p *background) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) + && background != NULL) + { + png_debug1(1, "in %s retrieval function", "bKGD"); + + *background = &(info_ptr->background); + return (PNG_INFO_bKGD); + } + + return (0); +} +#endif + +#ifdef PNG_cHRM_SUPPORTED +/* The XYZ APIs were added in 1.5.5 to take advantage of the code added at the + * same time to correct the rgb grayscale coefficient defaults obtained from the + * cHRM chunk in 1.5.4 + */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *white_x, double *white_y, double *red_x, double *red_y, + double *green_x, double *green_y, double *blue_x, double *blue_y) +{ + /* Quiet API change: this code used to only return the end points if a cHRM + * chunk was present, but the end points can also come from iCCP or sRGB + * chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and + * the png_set_ APIs merely check that set end points are mutually + * consistent. + */ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) + { + png_debug1(1, "in %s retrieval function", "cHRM"); + + if (white_x != NULL) + *white_x = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.whitex, "cHRM white X"); + if (white_y != NULL) + *white_y = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.whitey, "cHRM white Y"); + if (red_x != NULL) + *red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx, + "cHRM red X"); + if (red_y != NULL) + *red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy, + "cHRM red Y"); + if (green_x != NULL) + *green_x = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.greenx, "cHRM green X"); + if (green_y != NULL) + *green_y = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.greeny, "cHRM green Y"); + if (blue_x != NULL) + *blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex, + "cHRM blue X"); + if (blue_y != NULL) + *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey, + "cHRM blue Y"); + return (PNG_INFO_cHRM); + } + + return (0); +} + +png_uint_32 PNGAPI +png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *red_X, double *red_Y, double *red_Z, double *green_X, + double *green_Y, double *green_Z, double *blue_X, double *blue_Y, + double *blue_Z) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) + { + png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)"); + + if (red_X != NULL) + *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X, + "cHRM red X"); + if (red_Y != NULL) + *red_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Y, + "cHRM red Y"); + if (red_Z != NULL) + *red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Z, + "cHRM red Z"); + if (green_X != NULL) + *green_X = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_X, "cHRM green X"); + if (green_Y != NULL) + *green_Y = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_Y, "cHRM green Y"); + if (green_Z != NULL) + *green_Z = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_Z, "cHRM green Z"); + if (blue_X != NULL) + *blue_X = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_X, "cHRM blue X"); + if (blue_Y != NULL) + *blue_Y = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_Y, "cHRM blue Y"); + if (blue_Z != NULL) + *blue_Z = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z"); + return (PNG_INFO_cHRM); + } + + return (0); +} +# endif + +# ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) + { + png_debug1(1, "in %s retrieval function", "cHRM_XYZ"); + + if (int_red_X != NULL) + *int_red_X = info_ptr->colorspace.end_points_XYZ.red_X; + if (int_red_Y != NULL) + *int_red_Y = info_ptr->colorspace.end_points_XYZ.red_Y; + if (int_red_Z != NULL) + *int_red_Z = info_ptr->colorspace.end_points_XYZ.red_Z; + if (int_green_X != NULL) + *int_green_X = info_ptr->colorspace.end_points_XYZ.green_X; + if (int_green_Y != NULL) + *int_green_Y = info_ptr->colorspace.end_points_XYZ.green_Y; + if (int_green_Z != NULL) + *int_green_Z = info_ptr->colorspace.end_points_XYZ.green_Z; + if (int_blue_X != NULL) + *int_blue_X = info_ptr->colorspace.end_points_XYZ.blue_X; + if (int_blue_Y != NULL) + *int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y; + if (int_blue_Z != NULL) + *int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z; + return (PNG_INFO_cHRM); + } + + return (0); +} + +png_uint_32 PNGAPI +png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, + png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, + png_fixed_point *blue_x, png_fixed_point *blue_y) +{ + png_debug1(1, "in %s retrieval function", "cHRM"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) + { + if (white_x != NULL) + *white_x = info_ptr->colorspace.end_points_xy.whitex; + if (white_y != NULL) + *white_y = info_ptr->colorspace.end_points_xy.whitey; + if (red_x != NULL) + *red_x = info_ptr->colorspace.end_points_xy.redx; + if (red_y != NULL) + *red_y = info_ptr->colorspace.end_points_xy.redy; + if (green_x != NULL) + *green_x = info_ptr->colorspace.end_points_xy.greenx; + if (green_y != NULL) + *green_y = info_ptr->colorspace.end_points_xy.greeny; + if (blue_x != NULL) + *blue_x = info_ptr->colorspace.end_points_xy.bluex; + if (blue_y != NULL) + *blue_y = info_ptr->colorspace.end_points_xy.bluey; + return (PNG_INFO_cHRM); + } + + return (0); +} +# endif +#endif + +#ifdef PNG_gAMA_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *file_gamma) +{ + png_debug1(1, "in %s retrieval function", "gAMA"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) && + file_gamma != NULL) + { + *file_gamma = info_ptr->colorspace.gamma; + return (PNG_INFO_gAMA); + } + + return (0); +} +# endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *file_gamma) +{ + png_debug1(1, "in %s retrieval function", "gAMA(float)"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) && + file_gamma != NULL) + { + *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma, + "png_get_gAMA"); + return (PNG_INFO_gAMA); + } + + return (0); +} +# endif +#endif + +#ifdef PNG_sRGB_SUPPORTED +png_uint_32 PNGAPI +png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *file_srgb_intent) +{ + png_debug1(1, "in %s retrieval function", "sRGB"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) + && file_srgb_intent != NULL) + { + *file_srgb_intent = info_ptr->colorspace.rendering_intent; + return (PNG_INFO_sRGB); + } + + return (0); +} +#endif + +#ifdef PNG_iCCP_SUPPORTED +png_uint_32 PNGAPI +png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, + png_charpp name, int *compression_type, + png_bytepp profile, png_uint_32 *proflen) +{ + png_debug1(1, "in %s retrieval function", "iCCP"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) + && name != NULL && compression_type != NULL && profile != NULL && + proflen != NULL) + { + *name = info_ptr->iccp_name; + *profile = info_ptr->iccp_profile; + *proflen = png_get_uint_32(info_ptr->iccp_profile); + /* This is somewhat irrelevant since the profile data returned has + * actually been uncompressed. + */ + *compression_type = PNG_COMPRESSION_TYPE_BASE; + return (PNG_INFO_iCCP); + } + + return (0); +} +#endif + +#ifdef PNG_sPLT_SUPPORTED +int PNGAPI +png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr, + png_sPLT_tpp spalettes) +{ + if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) + { + *spalettes = info_ptr->splt_palettes; + return info_ptr->splt_palettes_num; + } + + return (0); +} +#endif + +#ifdef PNG_hIST_SUPPORTED +png_uint_32 PNGAPI +png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_16p *hist) +{ + png_debug1(1, "in %s retrieval function", "hIST"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) + && hist != NULL) + { + *hist = info_ptr->hist; + return (PNG_INFO_hIST); + } + + return (0); +} +#endif + +png_uint_32 PNGAPI +png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 *width, png_uint_32 *height, int *bit_depth, + int *color_type, int *interlace_type, int *compression_type, + int *filter_type) +{ + png_debug1(1, "in %s retrieval function", "IHDR"); + + if (png_ptr == NULL || info_ptr == NULL || width == NULL || + height == NULL || bit_depth == NULL || color_type == NULL) + return (0); + + *width = info_ptr->width; + *height = info_ptr->height; + *bit_depth = info_ptr->bit_depth; + *color_type = info_ptr->color_type; + + if (compression_type != NULL) + *compression_type = info_ptr->compression_type; + + if (filter_type != NULL) + *filter_type = info_ptr->filter_type; + + if (interlace_type != NULL) + *interlace_type = info_ptr->interlace_type; + + /* This is redundant if we can be sure that the info_ptr values were all + * assigned in png_set_IHDR(). We do the check anyhow in case an + * application has ignored our advice not to mess with the members + * of info_ptr directly. + */ + png_check_IHDR(png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, + info_ptr->compression_type, info_ptr->filter_type); + + return (1); +} + +#ifdef PNG_oFFs_SUPPORTED +png_uint_32 PNGAPI +png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) +{ + png_debug1(1, "in %s retrieval function", "oFFs"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) + && offset_x != NULL && offset_y != NULL && unit_type != NULL) + { + *offset_x = info_ptr->x_offset; + *offset_y = info_ptr->y_offset; + *unit_type = (int)info_ptr->offset_unit_type; + return (PNG_INFO_oFFs); + } + + return (0); +} +#endif + +#ifdef PNG_pCAL_SUPPORTED +png_uint_32 PNGAPI +png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, + png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, + png_charp *units, png_charpp *params) +{ + png_debug1(1, "in %s retrieval function", "pCAL"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) + && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && + nparams != NULL && units != NULL && params != NULL) + { + *purpose = info_ptr->pcal_purpose; + *X0 = info_ptr->pcal_X0; + *X1 = info_ptr->pcal_X1; + *type = (int)info_ptr->pcal_type; + *nparams = (int)info_ptr->pcal_nparams; + *units = info_ptr->pcal_units; + *params = info_ptr->pcal_params; + return (PNG_INFO_pCAL); + } + + return (0); +} +#endif + +#ifdef PNG_sCAL_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED +# if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ + defined(PNG_FLOATING_POINT_SUPPORTED) +png_uint_32 PNGAPI +png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *unit, png_fixed_point *width, png_fixed_point *height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL)) + { + *unit = info_ptr->scal_unit; + /*TODO: make this work without FP support; the API is currently eliminated + * if neither floating point APIs nor internal floating point arithmetic + * are enabled. + */ + *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width"); + *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height), + "sCAL height"); + return (PNG_INFO_sCAL); + } + + return(0); +} +# endif /* FLOATING_ARITHMETIC */ +# endif /* FIXED_POINT */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *unit, double *width, double *height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL)) + { + *unit = info_ptr->scal_unit; + *width = atof(info_ptr->scal_s_width); + *height = atof(info_ptr->scal_s_height); + return (PNG_INFO_sCAL); + } + + return(0); +} +# endif /* FLOATING POINT */ +png_uint_32 PNGAPI +png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *unit, png_charpp width, png_charpp height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL)) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_s_width; + *height = info_ptr->scal_s_height; + return (PNG_INFO_sCAL); + } + + return(0); +} +#endif /* sCAL */ + +#ifdef PNG_pHYs_SUPPORTED +png_uint_32 PNGAPI +png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + png_debug1(1, "in %s retrieval function", "pHYs"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs)) + { + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + } + } + + return (retval); +} +#endif /* pHYs */ + +png_uint_32 PNGAPI +png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr, + png_colorp *palette, int *num_palette) +{ + png_debug1(1, "in %s retrieval function", "PLTE"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) + && palette != NULL) + { + *palette = info_ptr->palette; + *num_palette = info_ptr->num_palette; + png_debug1(3, "num_palette = %d", *num_palette); + return (PNG_INFO_PLTE); + } + + return (0); +} + +#ifdef PNG_sBIT_SUPPORTED +png_uint_32 PNGAPI +png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, + png_color_8p *sig_bit) +{ + png_debug1(1, "in %s retrieval function", "sBIT"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) + && sig_bit != NULL) + { + *sig_bit = &(info_ptr->sig_bit); + return (PNG_INFO_sBIT); + } + + return (0); +} +#endif + +#ifdef PNG_TEXT_SUPPORTED +int PNGAPI +png_get_text(png_const_structrp png_ptr, png_inforp info_ptr, + png_textp *text_ptr, int *num_text) +{ + if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) + { + png_debug1(1, "in 0x%lx retrieval function", + (unsigned long)png_ptr->chunk_name); + + if (text_ptr != NULL) + *text_ptr = info_ptr->text; + + if (num_text != NULL) + *num_text = info_ptr->num_text; + + return info_ptr->num_text; + } + + if (num_text != NULL) + *num_text = 0; + + return(0); +} +#endif + +#ifdef PNG_tIME_SUPPORTED +png_uint_32 PNGAPI +png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr, + png_timep *mod_time) +{ + png_debug1(1, "in %s retrieval function", "tIME"); + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) + && mod_time != NULL) + { + *mod_time = &(info_ptr->mod_time); + return (PNG_INFO_tIME); + } + + return (0); +} +#endif + +#ifdef PNG_tRNS_SUPPORTED +png_uint_32 PNGAPI +png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color) +{ + png_uint_32 retval = 0; + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + png_debug1(1, "in %s retrieval function", "tRNS"); + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (trans_alpha != NULL) + { + *trans_alpha = info_ptr->trans_alpha; + retval |= PNG_INFO_tRNS; + } + + if (trans_color != NULL) + *trans_color = &(info_ptr->trans_color); + } + + else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ + { + if (trans_color != NULL) + { + *trans_color = &(info_ptr->trans_color); + retval |= PNG_INFO_tRNS; + } + + if (trans_alpha != NULL) + *trans_alpha = NULL; + } + + if (num_trans != NULL) + { + *num_trans = info_ptr->num_trans; + retval |= PNG_INFO_tRNS; + } + } + + return (retval); +} +#endif + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +int PNGAPI +png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr, + png_unknown_chunkpp unknowns) +{ + if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) + { + *unknowns = info_ptr->unknown_chunks; + return info_ptr->unknown_chunks_num; + } + + return (0); +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +png_byte PNGAPI +png_get_rgb_to_gray_status (png_const_structrp png_ptr) +{ + return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0); +} +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +png_voidp PNGAPI +png_get_user_chunk_ptr(png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_chunk_ptr : NULL); +} +#endif + +png_size_t PNGAPI +png_get_compression_buffer_size(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return 0; + +# ifdef PNG_WRITE_SUPPORTED + if (png_ptr->mode & PNG_IS_READ_STRUCT) +# endif + { +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + return png_ptr->IDAT_read_size; +# else + return PNG_IDAT_READ_SIZE; +# endif + } + +# ifdef PNG_WRITE_SUPPORTED + else + return png_ptr->zbuffer_size; +# endif +} + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* These functions were added to libpng 1.2.6 and were enabled + * by default in libpng-1.4.0 */ +png_uint_32 PNGAPI +png_get_user_width_max (png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_width_max : 0); +} + +png_uint_32 PNGAPI +png_get_user_height_max (png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_height_max : 0); +} + +/* This function was added to libpng 1.4.0 */ +png_uint_32 PNGAPI +png_get_chunk_cache_max (png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_chunk_cache_max : 0); +} + +/* This function was added to libpng 1.4.1 */ +png_alloc_size_t PNGAPI +png_get_chunk_malloc_max (png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_chunk_malloc_max : 0); +} +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ + +/* These functions were added to libpng 1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED +png_uint_32 PNGAPI +png_get_io_state (png_const_structrp png_ptr) +{ + return png_ptr->io_state; +} + +png_uint_32 PNGAPI +png_get_io_chunk_type (png_const_structrp png_ptr) +{ + return png_ptr->chunk_name; +} +#endif /* ?PNG_IO_STATE_SUPPORTED */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +int PNGAPI +png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return png_ptr->num_palette_max; + + return (-1); +} +# endif +#endif + +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngmem.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngmem.c new file mode 100644 index 0000000000..446bc6879a --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngmem.c @@ -0,0 +1,291 @@ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +/* pngmem.c - stub functions for memory allocation + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all memory allocation. Users who + * need special memory handling are expected to supply replacement + * functions for png_malloc() and png_free(), and to use + * png_create_read_struct_2() and png_create_write_struct_2() to + * identify the replacement functions. + */ + +#include "pngpriv.h" + +#if defined(_FX_MANAGED_CODE_) && defined(__cplusplus) +extern "C" { +#endif + +void* FXMEM_DefaultAlloc(int byte_size, int); +void FXMEM_DefaultFree(void* pointer, int); + +#if defined(_FX_MANAGED_CODE_) && defined(__cplusplus) +} +#endif + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Free a png_struct */ +void /* PRIVATE */ +png_destroy_png_struct(png_structrp png_ptr) +{ + if (png_ptr != NULL) + { + /* png_free might call png_error and may certainly call + * png_get_mem_ptr, so fake a temporary png_struct to support this. + */ + png_struct dummy_struct = *png_ptr; + memset(png_ptr, 0, (sizeof *png_ptr)); + png_free(&dummy_struct, png_ptr); + +# ifdef PNG_SETJMP_SUPPORTED + /* We may have a jmp_buf left to deallocate. */ + png_free_jmpbuf(&dummy_struct); +# endif + } +} + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more then 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + */ +PNG_FUNCTION(png_voidp,PNGAPI +png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +{ + png_voidp ret; + + ret = png_malloc(png_ptr, size); + + if (ret != NULL) + memset(ret, 0, size); + + return ret; +} + +/* png_malloc_base, an internal function added at libpng 1.6.0, does the work of + * allocating memory, taking into account limits and PNG_USER_MEM_SUPPORTED. + * Checking and error handling must happen outside this routine; it returns NULL + * if the allocation cannot be done (for any reason.) + */ +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED) +{ + /* Moved to png_malloc_base from png_malloc_default in 1.6.0; the DOS + * allocators have also been removed in 1.6.0, so any 16-bit system now has + * to implement a user memory handler. This checks to be sure it isn't + * called with big numbers. + */ +#ifdef PNG_USER_MEM_SUPPORTED + PNG_UNUSED(png_ptr) +#endif + if (size > 0 && size <= PNG_SIZE_MAX +# ifdef PNG_MAX_MALLOC_64K + && size <= 65536U +# endif + ) + { +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr != NULL && png_ptr->malloc_fn != NULL) + return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size); + + else +#endif + return FXMEM_DefaultAlloc((int)size, 0); + //return malloc((size_t)size); /* checked for truncation above */ + } + + else + return NULL; +} + +/* This is really here only to work round a spurious warning in GCC 4.6 and 4.7 + * that arises because of the checks in png_realloc_array that are repeated in + * png_malloc_array. + */ +static png_voidp +png_malloc_array_checked(png_const_structrp png_ptr, int nelements, + size_t element_size) +{ + png_alloc_size_t req = nelements; /* known to be > 0 */ + + if (req <= PNG_SIZE_MAX/element_size) + return png_malloc_base(png_ptr, req * element_size); + + /* The failure case when the request is too large */ + return NULL; +} + +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_malloc_array,(png_const_structrp png_ptr, int nelements, + size_t element_size),PNG_ALLOCATED) +{ + if (nelements <= 0 || element_size == 0) + png_error(png_ptr, "internal error: array alloc"); + + return png_malloc_array_checked(png_ptr, nelements, element_size); +} + +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array, + int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED) +{ + /* These are internal errors: */ + if (add_elements <= 0 || element_size == 0 || old_elements < 0 || + (old_array == NULL && old_elements > 0)) + png_error(png_ptr, "internal error: array realloc"); + + /* Check for overflow on the elements count (so the caller does not have to + * check.) + */ + if (add_elements <= INT_MAX - old_elements) + { + png_voidp new_array = png_malloc_array_checked(png_ptr, + old_elements+add_elements, element_size); + + if (new_array != NULL) + { + /* Because png_malloc_array worked the size calculations below cannot + * overflow. + */ + if (old_elements > 0) + memcpy(new_array, old_array, element_size*(unsigned)old_elements); + + memset((char*)new_array + element_size*(unsigned)old_elements, 0, + element_size*(unsigned)add_elements); + + return new_array; + } + } + + return NULL; /* error */ +} + +/* Various functions that have different error handling are derived from this. + * png_malloc always exists, but if PNG_USER_MEM_SUPPORTED is defined a separate + * function png_malloc_default is also provided. + */ +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +{ + png_voidp ret; + + if (png_ptr == NULL) + return NULL; + + ret = png_malloc_base(png_ptr, size); + + if (ret == NULL) + png_error(png_ptr, "Out of memory"); /* 'm' means png_malloc */ + + return ret; +} + +#ifdef PNG_USER_MEM_SUPPORTED +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED PNG_DEPRECATED) +{ + png_voidp ret; + + if (png_ptr == NULL) + return NULL; + + /* Passing 'NULL' here bypasses the application provided memory handler. */ + ret = png_malloc_base(NULL/*use malloc*/, size); + + if (ret == NULL) + png_error(png_ptr, "Out of Memory"); /* 'M' means png_malloc_default */ + + return ret; +} +#endif /* PNG_USER_MEM_SUPPORTED */ + +/* This function was added at libpng version 1.2.3. The png_malloc_warn() + * function will issue a png_warning and return NULL instead of issuing a + * png_error, if it fails to allocate the requested memory. + */ +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc_warn,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED) +{ + if (png_ptr != NULL) + { + png_voidp ret = png_malloc_base(png_ptr, size); + + if (ret != NULL) + return ret; + + png_warning(png_ptr, "Out of memory"); + } + + return NULL; +} + +/* Free a pointer allocated by png_malloc(). If ptr is NULL, return + * without taking any action. + */ +void PNGAPI +png_free(png_const_structrp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->free_fn != NULL) + png_ptr->free_fn(png_constcast(png_structrp,png_ptr), ptr); + + else + png_free_default(png_ptr, ptr); +} + +PNG_FUNCTION(void,PNGAPI +png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED) +{ + if (png_ptr == NULL || ptr == NULL) + return; +#endif /* PNG_USER_MEM_SUPPORTED */ + + FXMEM_DefaultFree(ptr, 0); + //free(ptr); +} + +#ifdef PNG_USER_MEM_SUPPORTED +/* This function is called when the application wants to use another method + * of allocating and freeing memory. + */ +void PNGAPI +png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr + malloc_fn, png_free_ptr free_fn) +{ + if (png_ptr != NULL) + { + png_ptr->mem_ptr = mem_ptr; + png_ptr->malloc_fn = malloc_fn; + png_ptr->free_fn = free_fn; + } +} + +/* This function returns a pointer to the mem_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_mem_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return NULL; + + return png_ptr->mem_ptr; +} +#endif /* PNG_USER_MEM_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngpread.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngpread.c new file mode 100644 index 0000000000..6d5053f849 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngpread.c @@ -0,0 +1,1292 @@ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +/* pngpread.c - read a png file in push mode + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + +/* Push model modes */ +#define PNG_READ_SIG_MODE 0 +#define PNG_READ_CHUNK_MODE 1 +#define PNG_READ_IDAT_MODE 2 +#define PNG_SKIP_MODE 3 +#define PNG_READ_tEXt_MODE 4 +#define PNG_READ_zTXt_MODE 5 +#define PNG_READ_DONE_MODE 6 +#define PNG_READ_iTXt_MODE 7 +#define PNG_ERROR_MODE 8 + +void PNGAPI +png_process_data(png_structrp png_ptr, png_inforp info_ptr, + png_bytep buffer, png_size_t buffer_size) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_push_restore_buffer(png_ptr, buffer, buffer_size); + + while (png_ptr->buffer_size) + { + png_process_some_data(png_ptr, info_ptr); + } +} + +png_size_t PNGAPI +png_process_data_pause(png_structrp png_ptr, int save) +{ + if (png_ptr != NULL) + { + /* It's easiest for the caller if we do the save, then the caller doesn't + * have to supply the same data again: + */ + if (save) + png_push_save_buffer(png_ptr); + else + { + /* This includes any pending saved bytes: */ + png_size_t remaining = png_ptr->buffer_size; + png_ptr->buffer_size = 0; + + /* So subtract the saved buffer size, unless all the data + * is actually 'saved', in which case we just return 0 + */ + if (png_ptr->save_buffer_size < remaining) + return remaining - png_ptr->save_buffer_size; + } + } + + return 0; +} + +png_uint_32 PNGAPI +png_process_data_skip(png_structrp png_ptr) +{ + png_uint_32 remaining = 0; + + if (png_ptr != NULL && png_ptr->process_mode == PNG_SKIP_MODE && + png_ptr->skip_length > 0) + { + /* At the end of png_process_data the buffer size must be 0 (see the loop + * above) so we can detect a broken call here: + */ + if (png_ptr->buffer_size != 0) + png_error(png_ptr, + "png_process_data_skip called inside png_process_data"); + + /* If is impossible for there to be a saved buffer at this point - + * otherwise we could not be in SKIP mode. This will also happen if + * png_process_skip is called inside png_process_data (but only very + * rarely.) + */ + if (png_ptr->save_buffer_size != 0) + png_error(png_ptr, "png_process_data_skip called with saved data"); + + remaining = png_ptr->skip_length; + png_ptr->skip_length = 0; + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } + + return remaining; +} + +/* What we do with the incoming data depends on what we were previously + * doing before we ran out of data... + */ +void /* PRIVATE */ +png_process_some_data(png_structrp png_ptr, png_inforp info_ptr) +{ + if (png_ptr == NULL) + return; + + switch (png_ptr->process_mode) + { + case PNG_READ_SIG_MODE: + { + png_push_read_sig(png_ptr, info_ptr); + break; + } + + case PNG_READ_CHUNK_MODE: + { + png_push_read_chunk(png_ptr, info_ptr); + break; + } + + case PNG_READ_IDAT_MODE: + { + png_push_read_IDAT(png_ptr); + break; + } + + case PNG_SKIP_MODE: + { + png_push_crc_finish(png_ptr); + break; + } + + default: + { + png_ptr->buffer_size = 0; + break; + } + } +} + +/* Read any remaining signature bytes from the stream and compare them with + * the correct PNG signature. It is possible that this routine is called + * with bytes already read from the signature, either because they have been + * checked by the calling application, or because of multiple calls to this + * routine. + */ +void /* PRIVATE */ +png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr) +{ + png_size_t num_checked = png_ptr->sig_bytes, /* SAFE, does not exceed 8 */ + num_to_check = 8 - num_checked; + + if (png_ptr->buffer_size < num_to_check) + { + num_to_check = png_ptr->buffer_size; + } + + png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), + num_to_check); + png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check); + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + else + { + if (png_ptr->sig_bytes >= 8) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } + } +} + +void /* PRIVATE */ +png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) +{ + png_uint_32 chunk_name; +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; /* unknown handling method */ +#endif + + /* First we make sure we have enough data for the 4 byte chunk name + * and the 4 byte chunk length before proceeding with decoding the + * chunk data. To fully decode each of these chunks, we also make + * sure we have enough data in the buffer for the 4 byte CRC at the + * end of every chunk (except IDAT, which is handled separately). + */ + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + { + png_byte chunk_length[4]; + png_byte chunk_tag[4]; + + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, chunk_tag, 4); + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + } + + chunk_name = png_ptr->chunk_name; + + if (chunk_name == png_IDAT) + { + if (png_ptr->mode & PNG_AFTER_IDAT) + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + + /* If we reach an IDAT chunk, this means we have read all of the + * header chunks, and we can start reading the image (or if this + * is called after the image has been read - we have an error). + */ + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + + png_ptr->mode |= PNG_HAVE_IDAT; + + if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + if (png_ptr->push_length == 0) + return; + + if (png_ptr->mode & PNG_AFTER_IDAT) + png_benign_error(png_ptr, "Too many IDATs found"); + } + + if (chunk_name == png_IHDR) + { + if (png_ptr->push_length != 13) + png_error(png_ptr, "Invalid IHDR length"); + + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); + } + + else if (chunk_name == png_IEND) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); + + png_ptr->process_mode = PNG_READ_DONE_MODE; + png_push_have_end(png_ptr, info_ptr); + } + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep); + + if (chunk_name == png_PLTE) + png_ptr->mode |= PNG_HAVE_PLTE; + } + +#endif + else if (chunk_name == png_PLTE) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); + } + + else if (chunk_name == png_IDAT) + { + png_ptr->idat_size = png_ptr->push_length; + png_ptr->process_mode = PNG_READ_IDAT_MODE; + png_push_have_info(png_ptr, info_ptr); + png_ptr->zstream.avail_out = + (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1; + png_ptr->zstream.next_out = png_ptr->row_buf; + return; + } + +#ifdef PNG_READ_gAMA_SUPPORTED + else if (png_ptr->chunk_name == png_gAMA) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + else if (png_ptr->chunk_name == png_sBIT) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + else if (png_ptr->chunk_name == png_cHRM) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + else if (chunk_name == png_sRGB) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + else if (png_ptr->chunk_name == png_iCCP) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + else if (chunk_name == png_sPLT) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + else if (chunk_name == png_tRNS) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_bKGD_SUPPORTED + else if (chunk_name == png_bKGD) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_hIST_SUPPORTED + else if (chunk_name == png_hIST) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + else if (chunk_name == png_pHYs) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + else if (chunk_name == png_oFFs) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); + } +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED + else if (chunk_name == png_pCAL) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + else if (chunk_name == png_sCAL) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tIME_SUPPORTED + else if (chunk_name == png_tIME) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + else if (chunk_name == png_tEXt) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + else if (chunk_name == png_zTXt) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + else if (chunk_name == png_iTXt) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif + else + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, + PNG_HANDLE_CHUNK_AS_DEFAULT); + } + + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; +} + +void /* PRIVATE */ +png_push_crc_skip(png_structrp png_ptr, png_uint_32 skip) +{ + png_ptr->process_mode = PNG_SKIP_MODE; + png_ptr->skip_length = skip; +} + +void /* PRIVATE */ +png_push_crc_finish(png_structrp png_ptr) +{ + if (png_ptr->skip_length && png_ptr->save_buffer_size) + { + png_size_t save_size = png_ptr->save_buffer_size; + png_uint_32 skip_length = png_ptr->skip_length; + + /* We want the smaller of 'skip_length' and 'save_buffer_size', but + * they are of different types and we don't know which variable has the + * fewest bits. Carefully select the smaller and cast it to the type of + * the larger - this cannot overflow. Do not cast in the following test + * - it will break on either 16 or 64 bit platforms. + */ + if (skip_length < save_size) + save_size = (png_size_t)skip_length; + + else + skip_length = (png_uint_32)save_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->skip_length -= skip_length; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (png_ptr->skip_length && png_ptr->current_buffer_size) + { + png_size_t save_size = png_ptr->current_buffer_size; + png_uint_32 skip_length = png_ptr->skip_length; + + /* We want the smaller of 'skip_length' and 'current_buffer_size', here, + * the same problem exists as above and the same solution. + */ + if (skip_length < save_size) + save_size = (png_size_t)skip_length; + + else + skip_length = (png_uint_32)save_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->skip_length -= skip_length; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + if (!png_ptr->skip_length) + { + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_crc_finish(png_ptr, 0); + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } +} + +void PNGCBAPI +png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) +{ + png_bytep ptr; + + if (png_ptr == NULL) + return; + + ptr = buffer; + if (png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (length < png_ptr->save_buffer_size) + save_size = length; + + else + save_size = png_ptr->save_buffer_size; + + memcpy(ptr, png_ptr->save_buffer_ptr, save_size); + length -= save_size; + ptr += save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (length && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (length < png_ptr->current_buffer_size) + save_size = length; + + else + save_size = png_ptr->current_buffer_size; + + memcpy(ptr, png_ptr->current_buffer_ptr, save_size); + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } +} + +void /* PRIVATE */ +png_push_save_buffer(png_structrp png_ptr) +{ + if (png_ptr->save_buffer_size) + { + if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) + { + png_size_t i, istop; + png_bytep sp; + png_bytep dp; + + istop = png_ptr->save_buffer_size; + for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; + i < istop; i++, sp++, dp++) + { + *dp = *sp; + } + } + } + if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > + png_ptr->save_buffer_max) + { + png_size_t new_max; + png_bytep old_buffer; + + if (png_ptr->save_buffer_size > PNG_SIZE_MAX - + (png_ptr->current_buffer_size + 256)) + { + png_error(png_ptr, "Potential overflow of save_buffer"); + } + + new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; + old_buffer = png_ptr->save_buffer; + png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, + (png_size_t)new_max); + + if (png_ptr->save_buffer == NULL) + { + png_free(png_ptr, old_buffer); + png_error(png_ptr, "Insufficient memory for save_buffer"); + } + + memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); + png_free(png_ptr, old_buffer); + png_ptr->save_buffer_max = new_max; + } + if (png_ptr->current_buffer_size) + { + memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, + png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); + png_ptr->save_buffer_size += png_ptr->current_buffer_size; + png_ptr->current_buffer_size = 0; + } + png_ptr->save_buffer_ptr = png_ptr->save_buffer; + png_ptr->buffer_size = 0; +} + +void /* PRIVATE */ +png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + png_ptr->current_buffer = buffer; + png_ptr->current_buffer_size = buffer_length; + png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size; + png_ptr->current_buffer_ptr = png_ptr->current_buffer; +} + +void /* PRIVATE */ +png_push_read_IDAT(png_structrp png_ptr) +{ + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + { + png_byte chunk_length[4]; + png_byte chunk_tag[4]; + + /* TODO: this code can be commoned up with the same code in push_read */ + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, chunk_tag, 4); + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + + if (png_ptr->chunk_name != png_IDAT) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + + if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) + png_error(png_ptr, "Not enough compressed data"); + + return; + } + + png_ptr->idat_size = png_ptr->push_length; + } + + if (png_ptr->idat_size && png_ptr->save_buffer_size) + { + png_size_t save_size = png_ptr->save_buffer_size; + png_uint_32 idat_size = png_ptr->idat_size; + + /* We want the smaller of 'idat_size' and 'current_buffer_size', but they + * are of different types and we don't know which variable has the fewest + * bits. Carefully select the smaller and cast it to the type of the + * larger - this cannot overflow. Do not cast in the following test - it + * will break on either 16 or 64 bit platforms. + */ + if (idat_size < save_size) + save_size = (png_size_t)idat_size; + + else + idat_size = (png_uint_32)save_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->idat_size -= idat_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + + if (png_ptr->idat_size && png_ptr->current_buffer_size) + { + png_size_t save_size = png_ptr->current_buffer_size; + png_uint_32 idat_size = png_ptr->idat_size; + + /* We want the smaller of 'idat_size' and 'current_buffer_size', but they + * are of different types and we don't know which variable has the fewest + * bits. Carefully select the smaller and cast it to the type of the + * larger - this cannot overflow. + */ + if (idat_size < save_size) + save_size = (png_size_t)idat_size; + + else + idat_size = (png_uint_32)save_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->idat_size -= idat_size; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + if (!png_ptr->idat_size) + { + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_crc_finish(png_ptr, 0); + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->zowner = 0; + } +} + +void /* PRIVATE */ +png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + /* The caller checks for a non-zero buffer length. */ + if (!(buffer_length > 0) || buffer == NULL) + png_error(png_ptr, "No IDAT data (internal error)"); + + /* This routine must process all the data it has been given + * before returning, calling the row callback as required to + * handle the uncompressed results. + */ + png_ptr->zstream.next_in = buffer; + /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ + png_ptr->zstream.avail_in = (uInt)buffer_length; + + /* Keep going until the decompressed data is all processed + * or the stream marked as finished. + */ + while (png_ptr->zstream.avail_in > 0 && + !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) + { + int ret; + + /* We have data for zlib, but we must check that zlib + * has someplace to put the results. It doesn't matter + * if we don't expect any results -- it may be the input + * data is just the LZ end code. + */ + if (!(png_ptr->zstream.avail_out > 0)) + { + /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ + png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1); + + png_ptr->zstream.next_out = png_ptr->row_buf; + } + + /* Using Z_SYNC_FLUSH here means that an unterminated + * LZ stream (a stream with a missing end code) can still + * be handled, otherwise (Z_NO_FLUSH) a future zlib + * implementation might defer output and therefore + * change the current behavior (see comments in inflate.c + * for why this doesn't happen at present with zlib 1.2.5). + */ + ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH); + + /* Check for any failure before proceeding. */ + if (ret != Z_OK && ret != Z_STREAM_END) + { + /* Terminate the decompression. */ + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + png_ptr->zowner = 0; + + /* This may be a truncated stream (missing or + * damaged end code). Treat that as a warning. + */ + if (png_ptr->row_number >= png_ptr->num_rows || + png_ptr->pass > 6) + png_warning(png_ptr, "Truncated compressed data in IDAT"); + + else + png_error(png_ptr, "Decompression error in IDAT"); + + /* Skip the check on unprocessed input */ + return; + } + + /* Did inflate output any data? */ + if (png_ptr->zstream.next_out != png_ptr->row_buf) + { + /* Is this unexpected data after the last row? + * If it is, artificially terminate the LZ output + * here. + */ + if (png_ptr->row_number >= png_ptr->num_rows || + png_ptr->pass > 6) + { + /* Extra data. */ + png_warning(png_ptr, "Extra compressed data in IDAT"); + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + png_ptr->zowner = 0; + + /* Do no more processing; skip the unprocessed + * input check below. + */ + return; + } + + /* Do we have a complete row? */ + if (png_ptr->zstream.avail_out == 0) + png_push_process_row(png_ptr); + } + + /* And check for the end of the stream. */ + if (ret == Z_STREAM_END) + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + } + + /* All the data should have been processed, if anything + * is left at this point we have bytes of IDAT data + * after the zlib end code. + */ + if (png_ptr->zstream.avail_in > 0) + png_warning(png_ptr, "Extra compression data in IDAT"); +} + +void /* PRIVATE */ +png_push_process_row(png_structrp png_ptr) +{ + /* 1.5.6: row_info moved out of png_struct to a local here. */ + png_row_info row_info; + + row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ + row_info.color_type = png_ptr->color_type; + row_info.bit_depth = png_ptr->bit_depth; + row_info.channels = png_ptr->channels; + row_info.pixel_depth = png_ptr->pixel_depth; + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); + + if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) + { + if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) + png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, + png_ptr->prev_row + 1, png_ptr->row_buf[0]); + else + png_error(png_ptr, "bad adaptive filter value"); + } + + /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before + * 1.5.6, while the buffer really is this big in current versions of libpng + * it may not be in the future, so this was changed just to copy the + * interlaced row count: + */ + memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + if (png_ptr->transformations) + png_do_read_transformations(png_ptr, &row_info); +#endif + + /* The transformed pixel depth should match the depth now in row_info. */ + if (png_ptr->transformed_pixel_depth == 0) + { + png_ptr->transformed_pixel_depth = row_info.pixel_depth; + if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) + png_error(png_ptr, "progressive row overflow"); + } + + else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) + png_error(png_ptr, "internal progressive row size calculation error"); + + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Blow up interlaced rows to full size */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + if (png_ptr->pass < 6) + png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, + png_ptr->transformations); + + switch (png_ptr->pass) + { + case 0: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 0; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */ + } + + if (png_ptr->pass == 2) /* Pass 1 might be empty */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + if (png_ptr->pass == 4 && png_ptr->height <= 4) + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + if (png_ptr->pass == 6 && png_ptr->height <= 4) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + case 1: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 1; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 2) /* Skip top 4 generated rows */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 2: + { + int i; + + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 4) /* Pass 3 might be empty */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 3: + { + int i; + + for (i = 0; i < 4 && png_ptr->pass == 3; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 4) /* Skip top two generated rows */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 4: + { + int i; + + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 6) /* Pass 5 might be empty */ + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + case 5: + { + int i; + + for (i = 0; i < 2 && png_ptr->pass == 5; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 6) /* Skip top generated row */ + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + default: + case 6: + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + + if (png_ptr->pass != 6) + break; + + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + } + else +#endif + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } +} + +void /* PRIVATE */ +png_read_push_finish_row(png_structrp png_ptr) +{ +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + + /* Height of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h + static PNG_CONST png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; + */ +#endif + + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + do + { + png_ptr->pass++; + if ((png_ptr->pass == 1 && png_ptr->width < 5) || + (png_ptr->pass == 3 && png_ptr->width < 3) || + (png_ptr->pass == 5 && png_ptr->width < 2)) + png_ptr->pass++; + + if (png_ptr->pass > 7) + png_ptr->pass--; + + if (png_ptr->pass >= 7) + break; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + if (png_ptr->transformations & PNG_INTERLACE) + break; + + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + + } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); + } +#endif /* PNG_READ_INTERLACING_SUPPORTED */ +} + +void /* PRIVATE */ +png_push_have_info(png_structrp png_ptr, png_inforp info_ptr) +{ + if (png_ptr->info_fn != NULL) + (*(png_ptr->info_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_end(png_structrp png_ptr, png_inforp info_ptr) +{ + if (png_ptr->end_fn != NULL) + (*(png_ptr->end_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_row(png_structrp png_ptr, png_bytep row) +{ + if (png_ptr->row_fn != NULL) + (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, + (int)png_ptr->pass); +} + +#ifdef PNG_READ_INTERLACING_SUPPORTED +void PNGAPI +png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row, + png_const_bytep new_row) +{ + if (png_ptr == NULL) + return; + + /* new_row is a flag here - if it is NULL then the app callback was called + * from an empty row (see the calls to png_struct::row_fn below), otherwise + * it must be png_ptr->row_buf+1 + */ + if (new_row != NULL) + png_combine_row(png_ptr, old_row, 1/*display*/); +} +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + +void PNGAPI +png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->info_fn = info_fn; + png_ptr->row_fn = row_fn; + png_ptr->end_fn = end_fn; + + png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); +} + +png_voidp PNGAPI +png_get_progressive_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + + return png_ptr->io_ptr; +} +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ +#endif diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngread.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngread.c new file mode 100644 index 0000000000..3918e8396f --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngread.c @@ -0,0 +1,4001 @@ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +/* pngread.c - read a PNG file + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains routines that an application calls directly to + * read a PNG file or stream. + */ + +#include "pngpriv.h" +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +# include +#endif + +#ifdef PNG_READ_SUPPORTED + +/* Create a PNG structure for reading, and allocate any memory needed. */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) +{ +#ifndef PNG_USER_MEM_SUPPORTED + png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, NULL, NULL, NULL); +#else + return png_create_read_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL); +} + +/* Alternate create PNG structure for reading, and allocate any memory + * needed. + */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) +{ + png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* PNG_USER_MEM_SUPPORTED */ + + if (png_ptr != NULL) + { + png_ptr->mode = PNG_IS_READ_STRUCT; + + /* Added in libpng-1.6.0; this can be used to detect a read structure if + * required (it will be zero in a write structure.) + */ +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + png_ptr->IDAT_read_size = PNG_IDAT_READ_SIZE; +# endif + +# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; + + /* In stable builds only warn if an application error can be completely + * handled. + */ +# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; +# endif +# endif + + /* TODO: delay this, it can be done in png_init_io (if the app doesn't + * do it itself) avoiding setting the default function if it is not + * required. + */ + png_set_read_fn(png_ptr, NULL, NULL); + } + + return png_ptr; +} + + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. This has been + * changed in v0.90 to allow reading a file that already has the magic + * bytes read from the stream. You can tell libpng how many bytes have + * been read from the beginning of the stream (up to the maximum of 8) + * via png_set_sig_bytes(), and we will only check the remaining bytes + * here. The application can then have access to the signature bytes we + * read if it is determined that this isn't a valid PNG file. + */ +void PNGAPI +png_read_info(png_structrp png_ptr, png_inforp info_ptr) +{ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; +#endif + + png_debug(1, "in png_read_info"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Read and check the PNG file signature. */ + png_read_sig(png_ptr, info_ptr); + + for (;;) + { + png_uint_32 length = png_read_chunk_header(png_ptr); + png_uint_32 chunk_name = png_ptr->chunk_name; + + /* IDAT logic needs to happen here to simplify getting the two flags + * right. + */ + if (chunk_name == png_IDAT) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_chunk_error(png_ptr, "Missing PLTE before IDAT"); + + else if (png_ptr->mode & PNG_AFTER_IDAT) + png_chunk_benign_error(png_ptr, "Too many IDATs found"); + + png_ptr->mode |= PNG_HAVE_IDAT; + } + + else if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + + /* This should be a binary subdivision search or a hash for + * matching the chunk name rather than a linear search. + */ + if (chunk_name == png_IHDR) + png_handle_IHDR(png_ptr, info_ptr, length); + + else if (chunk_name == png_IEND) + png_handle_IEND(png_ptr, info_ptr, length); + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) + { + png_handle_unknown(png_ptr, info_ptr, length, keep); + + if (chunk_name == png_PLTE) + png_ptr->mode |= PNG_HAVE_PLTE; + + else if (chunk_name == png_IDAT) + { + png_ptr->idat_size = 0; /* It has been consumed */ + break; + } + } +#endif + else if (chunk_name == png_PLTE) + png_handle_PLTE(png_ptr, info_ptr, length); + + else if (chunk_name == png_IDAT) + { + png_ptr->idat_size = length; + break; + } + +#ifdef PNG_READ_bKGD_SUPPORTED + else if (chunk_name == png_bKGD) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED + else if (chunk_name == png_cHRM) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED + else if (chunk_name == png_gAMA) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_hIST_SUPPORTED + else if (chunk_name == png_hIST) + png_handle_hIST(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED + else if (chunk_name == png_oFFs) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED + else if (chunk_name == png_pCAL) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED + else if (chunk_name == png_sCAL) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED + else if (chunk_name == png_pHYs) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED + else if (chunk_name == png_sBIT) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED + else if (chunk_name == png_sRGB) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED + else if (chunk_name == png_iCCP) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED + else if (chunk_name == png_sPLT) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED + else if (chunk_name == png_tEXt) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tIME_SUPPORTED + else if (chunk_name == png_tIME) + png_handle_tIME(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED + else if (chunk_name == png_tRNS) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED + else if (chunk_name == png_zTXt) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED + else if (chunk_name == png_iTXt) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + + else + png_handle_unknown(png_ptr, info_ptr, length, + PNG_HANDLE_CHUNK_AS_DEFAULT); + } +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +/* Optional call to update the users info_ptr structure */ +void PNGAPI +png_read_update_info(png_structrp png_ptr, png_inforp info_ptr) +{ + png_debug(1, "in png_read_update_info"); + + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + png_read_start_row(png_ptr); + +# ifdef PNG_READ_TRANSFORMS_SUPPORTED + png_read_transform_info(png_ptr, info_ptr); +# else + PNG_UNUSED(info_ptr) +# endif + } + + /* New in 1.6.0 this avoids the bug of doing the initializations twice */ + else + png_app_error(png_ptr, + "png_read_update_info/png_start_read_image: duplicate call"); + } +} + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Initialize palette, background, etc, after transformations + * are set, but before any reading takes place. This allows + * the user to obtain a gamma-corrected palette, for example. + * If the user doesn't call this, we will do it ourselves. + */ +void PNGAPI +png_start_read_image(png_structrp png_ptr) +{ + png_debug(1, "in png_start_read_image"); + + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + png_read_start_row(png_ptr); + + /* New in 1.6.0 this avoids the bug of doing the initializations twice */ + else + png_app_error(png_ptr, + "png_start_read_image/png_read_update_info: duplicate call"); + } +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +void PNGAPI +png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) +{ + png_row_info row_info; + + if (png_ptr == NULL) + return; + + png_debug2(1, "in png_read_row (row %lu, pass %d)", + (unsigned long)png_ptr->row_number, png_ptr->pass); + + /* png_read_start_row sets the information (in particular iwidth) for this + * interlace pass. + */ + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); + + /* 1.5.6: row_info moved out of png_struct to a local here. */ + row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ + row_info.color_type = png_ptr->color_type; + row_info.bit_depth = png_ptr->bit_depth; + row_info.channels = png_ptr->channels; + row_info.pixel_depth = png_ptr->pixel_depth; + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); + + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* Check for transforms that have been set but were defined out */ +#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ + !defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined"); +#endif + } + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* If interlaced and we do not need a new row, combine row and return. + * Notice that the pixels we have from previous rows have been transformed + * already; we can only combine like with like (transformed or + * untransformed) and, because of the libpng API for interlaced images, this + * means we must transform before de-interlacing. + */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + png_read_finish_row(png_ptr); + return; + } + break; + + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + if (dsp_row != NULL && (png_ptr->row_number & 4)) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 3: + if ((png_ptr->row_number & 3) || png_ptr->width < 3) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 4: + if ((png_ptr->row_number & 3) != 2) + { + if (dsp_row != NULL && (png_ptr->row_number & 2)) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 5: + if ((png_ptr->row_number & 1) || png_ptr->width < 2) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + default: + case 6: + if (!(png_ptr->row_number & 1)) + { + png_read_finish_row(png_ptr); + return; + } + break; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "Invalid attempt to read row data"); + + /* Fill the row with IDAT data: */ + png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1); + + if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) + { + if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) + png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, + png_ptr->prev_row + 1, png_ptr->row_buf[0]); + else + png_error(png_ptr, "bad adaptive filter value"); + } + + /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before + * 1.5.6, while the buffer really is this big in current versions of libpng + * it may not be in the future, so this was changed just to copy the + * interlaced count: + */ + memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_read_intrapixel(&row_info, png_ptr->row_buf + 1); + } +#endif + + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + if (png_ptr->transformations) + png_do_read_transformations(png_ptr, &row_info); +#endif + + /* The transformed pixel depth should match the depth now in row_info. */ + if (png_ptr->transformed_pixel_depth == 0) + { + png_ptr->transformed_pixel_depth = row_info.pixel_depth; + if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) + png_error(png_ptr, "sequential row overflow"); + } + + else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) + png_error(png_ptr, "internal sequential row size calculation error"); + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Blow up interlaced rows to full size */ + if (png_ptr->interlaced && + (png_ptr->transformations & PNG_INTERLACE)) + { + if (png_ptr->pass < 6) + png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, + png_ptr->transformations); + + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + if (row != NULL) + png_combine_row(png_ptr, row, 0/*row*/); + } + + else +#endif + { + if (row != NULL) + png_combine_row(png_ptr, row, -1/*ignored*/); + + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, -1/*ignored*/); + } + png_read_finish_row(png_ptr); + + if (png_ptr->read_row_fn != NULL) + (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); + +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. If the image is interlaced, + * and png_set_interlace_handling() has been called, the rows need to + * contain the contents of the rows from the previous pass. If the + * image has alpha or transparency, and png_handle_alpha()[*] has been + * called, the rows contents must be initialized to the contents of the + * screen. + * + * "row" holds the actual image, and pixels are placed in it + * as they arrive. If the image is displayed after each pass, it will + * appear to "sparkle" in. "display_row" can be used to display a + * "chunky" progressive image, with finer detail added as it becomes + * available. If you do not want this "chunky" display, you may pass + * NULL for display_row. If you do not want the sparkle display, and + * you have not called png_handle_alpha(), you may pass NULL for rows. + * If you have called png_handle_alpha(), and the image has either an + * alpha channel or a transparency chunk, you must provide a buffer for + * rows. In this case, you do not have to provide a display_row buffer + * also, but you may. If the image is not interlaced, or if you have + * not called png_set_interlace_handling(), the display_row buffer will + * be ignored, so pass NULL to it. + * + * [*] png_handle_alpha() does not exist yet, as of this version of libpng + */ + +void PNGAPI +png_read_rows(png_structrp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows) +{ + png_uint_32 i; + png_bytepp rp; + png_bytepp dp; + + png_debug(1, "in png_read_rows"); + + if (png_ptr == NULL) + return; + + rp = row; + dp = display_row; + if (rp != NULL && dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp++; + png_bytep dptr = *dp++; + + png_read_row(png_ptr, rptr, dptr); + } + + else if (rp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp; + png_read_row(png_ptr, rptr, NULL); + rp++; + } + + else if (dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep dptr = *dp; + png_read_row(png_ptr, NULL, dptr); + dp++; + } +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the entire image. If the image has an alpha channel or a tRNS + * chunk, and you have called png_handle_alpha()[*], you will need to + * initialize the image to the current image that PNG will be overlaying. + * We set the num_rows again here, in case it was incorrectly set in + * png_read_start_row() by a call to png_read_update_info() or + * png_start_read_image() if png_set_interlace_handling() wasn't called + * prior to either of these functions like it should have been. You can + * only call this function once. If you desire to have an image for + * each pass of a interlaced image, use png_read_rows() instead. + * + * [*] png_handle_alpha() does not exist yet, as of this version of libpng + */ +void PNGAPI +png_read_image(png_structrp png_ptr, png_bytepp image) +{ + png_uint_32 i, image_height; + int pass, j; + png_bytepp rp; + + png_debug(1, "in png_read_image"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + { + pass = png_set_interlace_handling(png_ptr); + /* And make sure transforms are initialized. */ + png_start_read_image(png_ptr); + } + else + { + if (png_ptr->interlaced && !(png_ptr->transformations & PNG_INTERLACE)) + { + /* Caller called png_start_read_image or png_read_update_info without + * first turning on the PNG_INTERLACE transform. We can fix this here, + * but the caller should do it! + */ + png_warning(png_ptr, "Interlace handling should be turned on when " + "using png_read_image"); + /* Make sure this is set correctly */ + png_ptr->num_rows = png_ptr->height; + } + + /* Obtain the pass number, which also turns on the PNG_INTERLACE flag in + * the above error case. + */ + pass = png_set_interlace_handling(png_ptr); + } +#else + if (png_ptr->interlaced) + png_error(png_ptr, + "Cannot read interlaced image -- interlace handler disabled"); + + pass = 1; +#endif + + image_height=png_ptr->height; + + for (j = 0; j < pass; j++) + { + rp = image; + for (i = 0; i < image_height; i++) + { + png_read_row(png_ptr, *rp, NULL); + rp++; + } + } +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. Will not read past the end of the + * file, will verify the end is accurate, and will read any comments + * or time information at the end of the file, if info is not NULL. + */ +void PNGAPI +png_read_end(png_structrp png_ptr, png_inforp info_ptr) +{ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; +#endif + + png_debug(1, "in png_read_end"); + + if (png_ptr == NULL) + return; + + /* If png_read_end is called in the middle of reading the rows there may + * still be pending IDAT data and an owned zstream. Deal with this here. + */ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (!png_chunk_unknown_handling(png_ptr, png_IDAT)) +#endif + png_read_finish_IDAT(png_ptr); + +#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Report invalid palette index; added at libng-1.5.10 */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max > png_ptr->num_palette) + png_benign_error(png_ptr, "Read palette index exceeding num_palette"); +#endif + + do + { + png_uint_32 length = png_read_chunk_header(png_ptr); + png_uint_32 chunk_name = png_ptr->chunk_name; + + if (chunk_name == png_IHDR) + png_handle_IHDR(png_ptr, info_ptr, length); + + else if (chunk_name == png_IEND) + png_handle_IEND(png_ptr, info_ptr, length); + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) + { + if (chunk_name == png_IDAT) + { + if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + png_benign_error(png_ptr, "Too many IDATs found"); + } + png_handle_unknown(png_ptr, info_ptr, length, keep); + if (chunk_name == png_PLTE) + png_ptr->mode |= PNG_HAVE_PLTE; + } +#endif + + else if (chunk_name == png_IDAT) + { + /* Zero length IDATs are legal after the last IDAT has been + * read, but not after other chunks have been read. + */ + if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + png_benign_error(png_ptr, "Too many IDATs found"); + + png_crc_finish(png_ptr, length); + } + else if (chunk_name == png_PLTE) + png_handle_PLTE(png_ptr, info_ptr, length); + +#ifdef PNG_READ_bKGD_SUPPORTED + else if (chunk_name == png_bKGD) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED + else if (chunk_name == png_cHRM) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED + else if (chunk_name == png_gAMA) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_hIST_SUPPORTED + else if (chunk_name == png_hIST) + png_handle_hIST(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED + else if (chunk_name == png_oFFs) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED + else if (chunk_name == png_pCAL) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED + else if (chunk_name == png_sCAL) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED + else if (chunk_name == png_pHYs) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED + else if (chunk_name == png_sBIT) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED + else if (chunk_name == png_sRGB) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED + else if (chunk_name == png_iCCP) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED + else if (chunk_name == png_sPLT) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED + else if (chunk_name == png_tEXt) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tIME_SUPPORTED + else if (chunk_name == png_tIME) + png_handle_tIME(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED + else if (chunk_name == png_tRNS) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED + else if (chunk_name == png_zTXt) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED + else if (chunk_name == png_iTXt) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + + else + png_handle_unknown(png_ptr, info_ptr, length, + PNG_HANDLE_CHUNK_AS_DEFAULT); + } while (!(png_ptr->mode & PNG_HAVE_IEND)); +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +/* Free all memory used in the read struct */ +static void +png_read_destroy(png_structrp png_ptr) +{ + png_debug(1, "in png_read_destroy"); + +#ifdef PNG_READ_GAMMA_SUPPORTED + png_destroy_gamma_table(png_ptr); +#endif + + png_free(png_ptr, png_ptr->big_row_buf); + png_free(png_ptr, png_ptr->big_prev_row); + png_free(png_ptr, png_ptr->read_buffer); + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + png_free(png_ptr, png_ptr->palette_lookup); + png_free(png_ptr, png_ptr->quantize_index); +#endif + + if (png_ptr->free_me & PNG_FREE_PLTE) + png_zfree(png_ptr, png_ptr->palette); + png_ptr->free_me &= ~PNG_FREE_PLTE; + +#if defined(PNG_tRNS_SUPPORTED) || \ + defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->free_me & PNG_FREE_TRNS) + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->free_me &= ~PNG_FREE_TRNS; +#endif + + inflateEnd(&png_ptr->zstream); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_free(png_ptr, png_ptr->save_buffer); +#endif + +#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) &&\ + defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_free(png_ptr, png_ptr->unknown_chunk.data); +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + png_free(png_ptr, png_ptr->chunk_list); +#endif + + /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error + * callbacks are still set at this point. They are required to complete the + * destruction of the png_struct itself. + */ +} + +/* Free all memory used by the read */ +void PNGAPI +png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, + png_infopp end_info_ptr_ptr) +{ + png_structrp png_ptr = NULL; + + png_debug(1, "in png_destroy_read_struct"); + + if (png_ptr_ptr != NULL) + png_ptr = *png_ptr_ptr; + + if (png_ptr == NULL) + return; + + /* libpng 1.6.0: use the API to destroy info structs to ensure consistent + * behavior. Prior to 1.6.0 libpng did extra 'info' destruction in this API. + * The extra was, apparently, unnecessary yet this hides memory leak bugs. + */ + png_destroy_info_struct(png_ptr, end_info_ptr_ptr); + png_destroy_info_struct(png_ptr, info_ptr_ptr); + + *png_ptr_ptr = NULL; + png_read_destroy(png_ptr); + png_destroy_png_struct(png_ptr); +} + +void PNGAPI +png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->read_row_fn = read_row_fn; +} + + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_read_png(png_structrp png_ptr, png_inforp info_ptr, + int transforms, + voidp params) +{ + int row; + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). + */ + png_read_info(png_ptr, info_ptr); + if (info_ptr->height > PNG_UINT_32_MAX/(sizeof (png_bytep))) + png_error(png_ptr, "Image is too high to process with png_read_png()"); + + /* -------------- image transformations start here ------------------- */ + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + /* Tell libpng to strip 16-bit/color files down to 8 bits per color. + */ + if (transforms & PNG_TRANSFORM_SCALE_16) + { + /* Added at libpng-1.5.4. "strip_16" produces the same result that it + * did in earlier versions, while "scale_16" is now more accurate. + */ + png_set_scale_16(png_ptr); + } +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* If both SCALE and STRIP are required pngrtran will effectively cancel the + * latter by doing SCALE first. This is ok and allows apps not to check for + * which is supported to get the right answer. + */ + if (transforms & PNG_TRANSFORM_STRIP_16) + png_set_strip_16(png_ptr); +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + /* Strip alpha bytes from the input data without combining with + * the background (not recommended). + */ + if (transforms & PNG_TRANSFORM_STRIP_ALPHA) + png_set_strip_alpha(png_ptr); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) + /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + if (transforms & PNG_TRANSFORM_PACKING) + png_set_packing(png_ptr); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). + */ + if (transforms & PNG_TRANSFORM_PACKSWAP) + png_set_packswap(png_ptr); +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED + /* Expand paletted colors into true RGB triplets + * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel + * Expand paletted or RGB images with transparency to full alpha + * channels so the data will be available as RGBA quartets. + */ + if (transforms & PNG_TRANSFORM_EXPAND) + if ((png_ptr->bit_depth < 8) || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || + (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) + png_set_expand(png_ptr); +#endif + + /* We don't handle background color or gamma transformation or quantizing. + */ + +#ifdef PNG_READ_INVERT_SUPPORTED + /* Invert monochrome files to have 0 as white and 1 as black + */ + if (transforms & PNG_TRANSFORM_INVERT_MONO) + png_set_invert_mono(png_ptr); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if ((transforms & PNG_TRANSFORM_SHIFT) + && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) + { + png_color_8p sig_bit; + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + png_set_shift(png_ptr, sig_bit); + } +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ + if (transforms & PNG_TRANSFORM_BGR) + png_set_bgr(png_ptr); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + png_set_swap_alpha(png_ptr); +#endif + +#ifdef PNG_READ_SWAP_SUPPORTED + /* Swap bytes of 16-bit files to least significant byte first */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + png_set_swap(png_ptr); +#endif + +/* Added at libpng-1.2.41 */ +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + +/* Added at libpng-1.2.41 */ +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* Expand grayscale image to RGB */ + if (transforms & PNG_TRANSFORM_GRAY_TO_RGB) + png_set_gray_to_rgb(png_ptr); +#endif + +/* Added at libpng-1.5.4 */ +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if (transforms & PNG_TRANSFORM_EXPAND_16) + png_set_expand_16(png_ptr); +#endif + + /* We don't handle adding filler bytes */ + + /* We use png_read_image and rely on that for interlace handling, but we also + * call png_read_update_info therefore must turn on interlace handling now: + */ + (void)png_set_interlace_handling(png_ptr); + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (i.e., you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* -------------- image transformations end here ------------------- */ + + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); + if (info_ptr->row_pointers == NULL) + { + png_uint_32 iptr; + + info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, + info_ptr->height * (sizeof (png_bytep))); + for (iptr=0; iptrheight; iptr++) + info_ptr->row_pointers[iptr] = NULL; + + info_ptr->free_me |= PNG_FREE_ROWS; + + for (row = 0; row < (int)info_ptr->height; row++) + info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr)); + } + + png_read_image(png_ptr, info_ptr->row_pointers); + info_ptr->valid |= PNG_INFO_IDAT; + + /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); + + PNG_UNUSED(transforms) /* Quiet compiler warnings */ + PNG_UNUSED(params) + +} +#endif /* PNG_INFO_IMAGE_SUPPORTED */ +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* SIMPLIFIED READ + * + * This code currently relies on the sequential reader, though it could easily + * be made to work with the progressive one. + */ +/* Arguments to png_image_finish_read: */ + +/* Encoding of PNG data (used by the color-map code) */ +/* TODO: change these, dang, ANSI-C reserves the 'E' namespace. */ +# define E_NOTSET 0 /* File encoding not yet known */ +# define E_sRGB 1 /* 8-bit encoded to sRGB gamma */ +# define E_LINEAR 2 /* 16-bit linear: not encoded, NOT pre-multiplied! */ +# define E_FILE 3 /* 8-bit encoded to file gamma, not sRGB or linear */ +# define E_LINEAR8 4 /* 8-bit linear: only from a file value */ + +/* Color-map processing: after libpng has run on the PNG image further + * processing may be needed to conver the data to color-map indicies. + */ +#define PNG_CMAP_NONE 0 +#define PNG_CMAP_GA 1 /* Process GA data to a color-map with alpha */ +#define PNG_CMAP_TRANS 2 /* Process GA data to a background index */ +#define PNG_CMAP_RGB 3 /* Process RGB data */ +#define PNG_CMAP_RGB_ALPHA 4 /* Process RGBA data */ + +/* The following document where the background is for each processing case. */ +#define PNG_CMAP_NONE_BACKGROUND 256 +#define PNG_CMAP_GA_BACKGROUND 231 +#define PNG_CMAP_TRANS_BACKGROUND 254 +#define PNG_CMAP_RGB_BACKGROUND 256 +#define PNG_CMAP_RGB_ALPHA_BACKGROUND 216 + +typedef struct +{ + /* Arguments: */ + png_imagep image; + png_voidp buffer; + png_int_32 row_stride; + png_voidp colormap; + png_const_colorp background; + /* Local variables: */ + png_voidp local_row; + png_voidp first_row; + ptrdiff_t row_bytes; /* step between rows */ + int file_encoding; /* E_ values above */ + png_fixed_point gamma_to_linear; /* For E_FILE, reciprocal of gamma */ + int colormap_processing; /* PNG_CMAP_ values above */ +} png_image_read_control; + +/* Do all the *safe* initialization - 'safe' means that png_error won't be + * called, so setting up the jmp_buf is not required. This means that anything + * called from here must *not* call png_malloc - it has to call png_malloc_warn + * instead so that control is returned safely back to this routine. + */ +static int +png_image_read_init(png_imagep image) +{ + if (image->opaque == NULL) + { + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, image, + png_safe_error, png_safe_warning); + + /* And set the rest of the structure to NULL to ensure that the various + * fields are consistent. + */ + memset(image, 0, (sizeof *image)); + image->version = PNG_IMAGE_VERSION; + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + png_controlp control = png_voidcast(png_controlp, + png_malloc_warn(png_ptr, (sizeof *control))); + + if (control != NULL) + { + memset(control, 0, (sizeof *control)); + + control->png_ptr = png_ptr; + control->info_ptr = info_ptr; + control->for_write = 0; + + image->opaque = control; + return 1; + } + + /* Error clean up */ + png_destroy_info_struct(png_ptr, &info_ptr); + } + + png_destroy_read_struct(&png_ptr, NULL, NULL); + } + + return png_image_error(image, "png_image_read: out of memory"); + } + + return png_image_error(image, "png_image_read: opaque pointer not NULL"); +} + +/* Utility to find the base format of a PNG file from a png_struct. */ +static png_uint_32 +png_image_format(png_structrp png_ptr) +{ + png_uint_32 format = 0; + + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + format |= PNG_FORMAT_FLAG_COLOR; + + if (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) + format |= PNG_FORMAT_FLAG_ALPHA; + + /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS + * sets the png_struct fields; that's all we are interested in here. The + * precise interaction with an app call to png_set_tRNS and PNG file reading + * is unclear. + */ + else if (png_ptr->num_trans > 0) + format |= PNG_FORMAT_FLAG_ALPHA; + + if (png_ptr->bit_depth == 16) + format |= PNG_FORMAT_FLAG_LINEAR; + + if (png_ptr->color_type & PNG_COLOR_MASK_PALETTE) + format |= PNG_FORMAT_FLAG_COLORMAP; + + return format; +} + +/* Is the given gamma significantly different from sRGB? The test is the same + * one used in pngrtran.c when deciding whether to do gamma correction. The + * arithmetic optimizes the division by using the fact that the inverse of the + * file sRGB gamma is 2.2 + */ +static int +png_gamma_not_sRGB(png_fixed_point g) +{ + if (g < PNG_FP_1) + { + /* An uninitialized gamma is assumed to be sRGB for the simplified API. */ + if (g == 0) + return 0; + + return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */); + } + + return 1; +} + +/* Do the main body of a 'png_image_begin_read' function; read the PNG file + * header and fill in all the information. This is executed in a safe context, + * unlike the init routine above. + */ +static int +png_image_read_header(png_voidp argument) +{ + png_imagep image = png_voidcast(png_imagep, argument); + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + + png_set_benign_errors(png_ptr, 1/*warn*/); + png_read_info(png_ptr, info_ptr); + + /* Do this the fast way; just read directly out of png_struct. */ + image->width = png_ptr->width; + image->height = png_ptr->height; + + { + png_uint_32 format = png_image_format(png_ptr); + + image->format = format; + +#ifdef PNG_COLORSPACE_SUPPORTED + /* Does the colorspace match sRGB? If there is no color endpoint + * (colorant) information assume yes, otherwise require the + * 'ENDPOINTS_MATCHE_sRGB' colorspace flag to have been set. If the + * colorspace has been determined to be invalid ignore it. + */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags + & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB| + PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS)) + image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB; +#endif + } + + /* We need the maximum number of entries regardless of the format the + * application sets here. + */ + { + png_uint_32 cmap_entries; + + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + cmap_entries = 1U << png_ptr->bit_depth; + break; + + case PNG_COLOR_TYPE_PALETTE: + cmap_entries = png_ptr->num_palette; + break; + + default: + cmap_entries = 256; + break; + } + + if (cmap_entries > 256) + cmap_entries = 256; + + image->colormap_entries = cmap_entries; + } + + return 1; +} + +#ifdef PNG_STDIO_SUPPORTED +int PNGAPI +png_image_begin_read_from_stdio(png_imagep image, FILE* file) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file != NULL) + { + if (png_image_read_init(image)) + { + /* This is slightly evil, but png_init_io doesn't do anything other + * than this and we haven't changed the standard IO functions so + * this saves a 'safe' function. + */ + image->opaque->png_ptr->io_ptr = file; + return png_safe_execute(image, png_image_read_header, image); + } + } + + else + return png_image_error(image, + "png_image_begin_read_from_stdio: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION"); + + return 0; +} + +int PNGAPI +png_image_begin_read_from_file(png_imagep image, const char *file_name) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file_name != NULL) + { + FILE *fp = fopen(file_name, "rb"); + + if (fp != NULL) + { + if (png_image_read_init(image)) + { + image->opaque->png_ptr->io_ptr = fp; + image->opaque->owned_file = 1; + return png_safe_execute(image, png_image_read_header, image); + } + + /* Clean up: just the opened file. */ + (void)fclose(fp); + } + + else + return png_image_error(image, strerror(errno)); + } + + else + return png_image_error(image, + "png_image_begin_read_from_file: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION"); + + return 0; +} +#endif /* PNG_STDIO_SUPPORTED */ + +static void PNGCBAPI +png_image_memory_read(png_structp png_ptr, png_bytep out, png_size_t need) +{ + if (png_ptr != NULL) + { + png_imagep image = png_voidcast(png_imagep, png_ptr->io_ptr); + if (image != NULL) + { + png_controlp cp = image->opaque; + if (cp != NULL) + { + png_const_bytep memory = cp->memory; + png_size_t size = cp->size; + + if (memory != NULL && size >= need) + { + memcpy(out, memory, need); + cp->memory = memory + need; + cp->size = size - need; + return; + } + + png_error(png_ptr, "read beyond end of data"); + } + } + + png_error(png_ptr, "invalid memory read"); + } +} + +int PNGAPI png_image_begin_read_from_memory(png_imagep image, + png_const_voidp memory, png_size_t size) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (memory != NULL && size > 0) + { + if (png_image_read_init(image)) + { + /* Now set the IO functions to read from the memory buffer and + * store it into io_ptr. Again do this in-place to avoid calling a + * libpng function that requires error handling. + */ + image->opaque->memory = png_voidcast(png_const_bytep, memory); + image->opaque->size = size; + image->opaque->png_ptr->io_ptr = image; + image->opaque->png_ptr->read_data_fn = png_image_memory_read; + + return png_safe_execute(image, png_image_read_header, image); + } + } + + else + return png_image_error(image, + "png_image_begin_read_from_memory: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION"); + + return 0; +} + +/* Utility function to skip chunks that are not used by the simplified image + * read functions and an appropriate macro to call it. + */ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +static void +png_image_skip_unused_chunks(png_structrp png_ptr) +{ + /* Prepare the reader to ignore all recognized chunks whose data will not + * be used, i.e., all chunks recognized by libpng except for those + * involved in basic image reading: + * + * IHDR, PLTE, IDAT, IEND + * + * Or image data handling: + * + * tRNS, bKGD, gAMA, cHRM, sRGB, iCCP and sBIT. + * + * This provides a small performance improvement and eliminates any + * potential vulnerability to security problems in the unused chunks. + */ + { + static PNG_CONST png_byte chunks_to_process[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 99, 72, 82, 77, '\0', /* cHRM */ + 103, 65, 77, 65, '\0', /* gAMA */ + 105, 67, 67, 80, '\0', /* iCCP */ + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 82, 71, 66, '\0', /* sRGB */ + }; + + /* Ignore unknown chunks and all other chunks except for the + * IHDR, PLTE, tRNS, IDAT, and IEND chunks. + */ + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, + NULL, -1); + + /* But do not ignore image data handling chunks */ + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT, + chunks_to_process, (sizeof chunks_to_process)/5); + } +} + +# define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p) +#else +# define PNG_SKIP_CHUNKS(p) ((void)0) +#endif /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */ + +/* The following macro gives the exact rounded answer for all values in the + * range 0..255 (it actually divides by 51.2, but the rounding still generates + * the correct numbers 0..5 + */ +#define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8) + +/* Utility functions to make particular color-maps */ +static void +set_file_encoding(png_image_read_control *display) +{ + png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma; + if (png_gamma_significant(g)) + { + if (png_gamma_not_sRGB(g)) + { + display->file_encoding = E_FILE; + display->gamma_to_linear = png_reciprocal(g); + } + + else + display->file_encoding = E_sRGB; + } + + else + display->file_encoding = E_LINEAR8; +} + +static unsigned int +decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) +{ + if (encoding == E_FILE) /* double check */ + encoding = display->file_encoding; + + if (encoding == E_NOTSET) /* must be the file encoding */ + { + set_file_encoding(display); + encoding = display->file_encoding; + } + + switch (encoding) + { + case E_FILE: + value = png_gamma_16bit_correct(value*257, display->gamma_to_linear); + break; + + case E_sRGB: + value = png_sRGB_table[value]; + break; + + case E_LINEAR: + break; + + case E_LINEAR8: + value *= 257; + break; + + default: + png_error(display->image->opaque->png_ptr, + "unexpected encoding (internal error)"); + break; + } + + return value; +} + +static png_uint_32 +png_colormap_compose(png_image_read_control *display, + png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha, + png_uint_32 background, int encoding) +{ + /* The file value is composed on the background, the background has the given + * encoding and so does the result, the file is encoded with E_FILE and the + * file and alpha are 8-bit values. The (output) encoding will always be + * E_LINEAR or E_sRGB. + */ + png_uint_32 f = decode_gamma(display, foreground, foreground_encoding); + png_uint_32 b = decode_gamma(display, background, encoding); + + /* The alpha is always an 8-bit value (it comes from the palette), the value + * scaled by 255 is what PNG_sRGB_FROM_LINEAR requires. + */ + f = f * alpha + b * (255-alpha); + + if (encoding == E_LINEAR) + { + /* Scale to 65535; divide by 255, approximately (in fact this is extremely + * accurate, it divides by 255.00000005937181414556, with no overflow.) + */ + f *= 257; /* Now scaled by 65535 */ + f += f >> 16; + f = (f+32768) >> 16; + } + + else /* E_sRGB */ + f = PNG_sRGB_FROM_LINEAR(f); + + return f; +} + +/* NOTE: E_LINEAR values to this routine must be 16-bit, but E_FILE values must + * be 8-bit. + */ +static void +png_create_colormap_entry(png_image_read_control *display, + png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue, + png_uint_32 alpha, int encoding) +{ + png_imagep image = display->image; + const int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) ? + E_LINEAR : E_sRGB; + const int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 && + (red != green || green != blue); + + if (ip > 255) + png_error(image->opaque->png_ptr, "color-map index out of range"); + + /* Update the cache with whether the file gamma is significantly different + * from sRGB. + */ + if (encoding == E_FILE) + { + if (display->file_encoding == E_NOTSET) + set_file_encoding(display); + + /* Note that the cached value may be E_FILE too, but if it is then the + * gamma_to_linear member has been set. + */ + encoding = display->file_encoding; + } + + if (encoding == E_FILE) + { + png_fixed_point g = display->gamma_to_linear; + + red = png_gamma_16bit_correct(red*257, g); + green = png_gamma_16bit_correct(green*257, g); + blue = png_gamma_16bit_correct(blue*257, g); + + if (convert_to_Y || output_encoding == E_LINEAR) + { + alpha *= 257; + encoding = E_LINEAR; + } + + else + { + red = PNG_sRGB_FROM_LINEAR(red * 255); + green = PNG_sRGB_FROM_LINEAR(green * 255); + blue = PNG_sRGB_FROM_LINEAR(blue * 255); + encoding = E_sRGB; + } + } + + else if (encoding == E_LINEAR8) + { + /* This encoding occurs quite frequently in test cases because PngSuite + * includes a gAMA 1.0 chunk with most images. + */ + red *= 257; + green *= 257; + blue *= 257; + alpha *= 257; + encoding = E_LINEAR; + } + + else if (encoding == E_sRGB && (convert_to_Y || output_encoding == E_LINEAR)) + { + /* The values are 8-bit sRGB values, but must be converted to 16-bit + * linear. + */ + red = png_sRGB_table[red]; + green = png_sRGB_table[green]; + blue = png_sRGB_table[blue]; + alpha *= 257; + encoding = E_LINEAR; + } + + /* This is set if the color isn't gray but the output is. */ + if (encoding == E_LINEAR) + { + if (convert_to_Y) + { + /* NOTE: these values are copied from png_do_rgb_to_gray */ + png_uint_32 y = (png_uint_32)6968 * red + (png_uint_32)23434 * green + + (png_uint_32)2366 * blue; + + if (output_encoding == E_LINEAR) + y = (y + 16384) >> 15; + + else + { + /* y is scaled by 32768, we need it scaled by 255: */ + y = (y + 128) >> 8; + y *= 255; + y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7); + encoding = E_sRGB; + } + + blue = red = green = y; + } + + else if (output_encoding == E_sRGB) + { + red = PNG_sRGB_FROM_LINEAR(red * 255); + green = PNG_sRGB_FROM_LINEAR(green * 255); + blue = PNG_sRGB_FROM_LINEAR(blue * 255); + alpha = PNG_DIV257(alpha); + encoding = E_sRGB; + } + } + + if (encoding != output_encoding) + png_error(image->opaque->png_ptr, "bad encoding (internal error)"); + + /* Store the value. */ + { +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else +# define afirst 0 +# endif +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int bgr = (image->format & PNG_FORMAT_FLAG_BGR) ? 2 : 0; +# else +# define bgr 0 +# endif + + if (output_encoding == E_LINEAR) + { + png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap); + + entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); + + /* The linear 16-bit values must be pre-multiplied by the alpha channel + * value, if less than 65535 (this is, effectively, composite on black + * if the alpha channel is removed.) + */ + switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) + { + case 4: + entry[afirst ? 0 : 3] = (png_uint_16)alpha; + /* FALL THROUGH */ + + case 3: + if (alpha < 65535) + { + if (alpha > 0) + { + blue = (blue * alpha + 32767U)/65535U; + green = (green * alpha + 32767U)/65535U; + red = (red * alpha + 32767U)/65535U; + } + + else + red = green = blue = 0; + } + entry[afirst + (2 ^ bgr)] = (png_uint_16)blue; + entry[afirst + 1] = (png_uint_16)green; + entry[afirst + bgr] = (png_uint_16)red; + break; + + case 2: + entry[1 ^ afirst] = (png_uint_16)alpha; + /* FALL THROUGH */ + + case 1: + if (alpha < 65535) + { + if (alpha > 0) + green = (green * alpha + 32767U)/65535U; + + else + green = 0; + } + entry[afirst] = (png_uint_16)green; + break; + + default: + break; + } + } + + else /* output encoding is E_sRGB */ + { + png_bytep entry = png_voidcast(png_bytep, display->colormap); + + entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); + + switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) + { + case 4: + entry[afirst ? 0 : 3] = (png_byte)alpha; + case 3: + entry[afirst + (2 ^ bgr)] = (png_byte)blue; + entry[afirst + 1] = (png_byte)green; + entry[afirst + bgr] = (png_byte)red; + break; + + case 2: + entry[1 ^ afirst] = (png_byte)alpha; + case 1: + entry[afirst] = (png_byte)green; + break; + + default: + break; + } + } + +# ifdef afirst +# undef afirst +# endif +# ifdef bgr +# undef bgr +# endif + } +} + +static int +make_gray_file_colormap(png_image_read_control *display) +{ + unsigned int i; + + for (i=0; i<256; ++i) + png_create_colormap_entry(display, i, i, i, i, 255, E_FILE); + + return i; +} + +static int +make_gray_colormap(png_image_read_control *display) +{ + unsigned int i; + + for (i=0; i<256; ++i) + png_create_colormap_entry(display, i, i, i, i, 255, E_sRGB); + + return i; +} +#define PNG_GRAY_COLORMAP_ENTRIES 256 + +static int +make_ga_colormap(png_image_read_control *display) +{ + unsigned int i, a; + + /* Alpha is retained, the output will be a color-map with entries + * selected by six levels of alpha. One transparent entry, 6 gray + * levels for all the intermediate alpha values, leaving 230 entries + * for the opaque grays. The color-map entries are the six values + * [0..5]*51, the GA processing uses PNG_DIV51(value) to find the + * relevant entry. + * + * if (alpha > 229) // opaque + * { + * // The 231 entries are selected to make the math below work: + * base = 0; + * entry = (231 * gray + 128) >> 8; + * } + * else if (alpha < 26) // transparent + * { + * base = 231; + * entry = 0; + * } + * else // partially opaque + * { + * base = 226 + 6 * PNG_DIV51(alpha); + * entry = PNG_DIV51(gray); + * } + */ + i = 0; + while (i < 231) + { + unsigned int gray = (i * 256 + 115) / 231; + png_create_colormap_entry(display, i++, gray, gray, gray, 255, E_sRGB); + } + + /* 255 is used here for the component values for consistency with the code + * that undoes premultiplication in pngwrite.c. + */ + png_create_colormap_entry(display, i++, 255, 255, 255, 0, E_sRGB); + + for (a=1; a<5; ++a) + { + unsigned int g; + + for (g=0; g<6; ++g) + png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51, + E_sRGB); + } + + return i; +} + +#define PNG_GA_COLORMAP_ENTRIES 256 + +static int +make_rgb_colormap(png_image_read_control *display) +{ + unsigned int i, r; + + /* Build a 6x6x6 opaque RGB cube */ + for (i=r=0; r<6; ++r) + { + unsigned int g; + + for (g=0; g<6; ++g) + { + unsigned int b; + + for (b=0; b<6; ++b) + png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255, + E_sRGB); + } + } + + return i; +} + +#define PNG_RGB_COLORMAP_ENTRIES 216 + +/* Return a palette index to the above palette given three 8-bit sRGB values. */ +#define PNG_RGB_INDEX(r,g,b) \ + ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b))) + +static int +png_image_read_colormap(png_voidp argument) +{ + png_image_read_control *display = + png_voidcast(png_image_read_control*, argument); + const png_imagep image = display->image; + + const png_structrp png_ptr = image->opaque->png_ptr; + const png_uint_32 output_format = image->format; + const int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) ? + E_LINEAR : E_sRGB; + + unsigned int cmap_entries; + unsigned int output_processing; /* Output processing option */ + unsigned int data_encoding = E_NOTSET; /* Encoding libpng must produce */ + + /* Background information; the background color and the index of this color + * in the color-map if it exists (else 256). + */ + unsigned int background_index = 256; + png_uint_32 back_r, back_g, back_b; + + /* Flags to accumulate things that need to be done to the input. */ + int expand_tRNS = 0; + + /* Exclude the NYI feature of compositing onto a color-mapped buffer; it is + * very difficult to do, the results look awful, and it is difficult to see + * what possible use it is because the application can't control the + * color-map. + */ + if (((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 || + png_ptr->num_trans > 0) /* alpha in input */ && + ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */) + { + if (output_encoding == E_LINEAR) /* compose on black */ + back_b = back_g = back_r = 0; + + else if (display->background == NULL /* no way to remove it */) + png_error(png_ptr, + "a background color must be supplied to remove alpha/transparency"); + + /* Get a copy of the background color (this avoids repeating the checks + * below.) The encoding is 8-bit sRGB or 16-bit linear, depending on the + * output format. + */ + else + { + back_g = display->background->green; + if (output_format & PNG_FORMAT_FLAG_COLOR) + { + back_r = display->background->red; + back_b = display->background->blue; + } + else + back_b = back_r = back_g; + } + } + + else if (output_encoding == E_LINEAR) + back_b = back_r = back_g = 65535; + + else + back_b = back_r = back_g = 255; + + /* Default the input file gamma if required - this is necessary because + * libpng assumes that if no gamma information is present the data is in the + * output format, but the simplified API deduces the gamma from the input + * format. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0) + { + /* Do this directly, not using the png_colorspace functions, to ensure + * that it happens even if the colorspace is invalid (though probably if + * it is the setting will be ignored) Note that the same thing can be + * achieved at the application interface with png_set_gAMA. + */ + if (png_ptr->bit_depth == 16 && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR; + + else + png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE; + + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + } + + /* Decide what to do based on the PNG color type of the input data. The + * utility function png_create_colormap_entry deals with most aspects of the + * output transformations; this code works out how to produce bytes of + * color-map entries from the original format. + */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + if (png_ptr->bit_depth <= 8) + { + /* There at most 256 colors in the output, regardless of + * transparency. + */ + unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0; + + cmap_entries = 1U << png_ptr->bit_depth; + if (cmap_entries > image->colormap_entries) + png_error(png_ptr, "gray[8] color-map: too few entries"); + + step = 255 / (cmap_entries - 1); + output_processing = PNG_CMAP_NONE; + + /* If there is a tRNS chunk then this either selects a transparent + * value or, if the output has no alpha, the background color. + */ + if (png_ptr->num_trans > 0) + { + trans = png_ptr->trans_color.gray; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) + back_alpha = output_encoding == E_LINEAR ? 65535 : 255; + } + + /* png_create_colormap_entry just takes an RGBA and writes the + * corresponding color-map entry using the format from 'image', + * including the required conversion to sRGB or linear as + * appropriate. The input values are always either sRGB (if the + * gamma correction flag is 0) or 0..255 scaled file encoded values + * (if the function must gamma correct them). + */ + for (i=val=0; ibit_depth < 8) + png_set_packing(png_ptr); + } + + else /* bit depth is 16 */ + { + /* The 16-bit input values can be converted directly to 8-bit gamma + * encoded values; however, if a tRNS chunk is present 257 color-map + * entries are required. This means that the extra entry requires + * special processing; add an alpha channel, sacrifice gray level + * 254 and convert transparent (alpha==0) entries to that. + * + * Use libpng to chop the data to 8 bits. Convert it to sRGB at the + * same time to minimize quality loss. If a tRNS chunk is present + * this means libpng must handle it too; otherwise it is impossible + * to do the exact match on the 16-bit value. + * + * If the output has no alpha channel *and* the background color is + * gray then it is possible to let libpng handle the substitution by + * ensuring that the corresponding gray level matches the background + * color exactly. + */ + data_encoding = E_sRGB; + + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray[16] color-map: too few entries"); + + cmap_entries = make_gray_colormap(display); + + if (png_ptr->num_trans > 0) + { + unsigned int back_alpha; + + if (output_format & PNG_FORMAT_FLAG_ALPHA) + back_alpha = 0; + + else + { + if (back_r == back_g && back_g == back_b) + { + /* Background is gray; no special processing will be + * required. + */ + png_color_16 c; + png_uint_32 gray = back_g; + + if (output_encoding == E_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry + * matches. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 65535, E_LINEAR); + } + + /* The background passed to libpng, however, must be the + * sRGB value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + /* NOTE: does this work without expanding tRNS to alpha? + * It should be the color->gray case below apparently + * doesn't. + */ + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_NONE; + break; + } + + back_alpha = output_encoding == E_LINEAR ? 65535 : 255; + } + + /* output_processing means that the libpng-processed row will be + * 8-bit GA and it has to be processing to single byte color-map + * values. Entry 254 is replaced by either a completely + * transparent entry or by the background color at full + * precision (and the background color is not a simple gray leve + * in this case.) + */ + expand_tRNS = 1; + output_processing = PNG_CMAP_TRANS; + background_index = 254; + + /* And set (overwrite) color-map entry 254 to the actual + * background color at full precision. + */ + png_create_colormap_entry(display, 254, back_r, back_g, back_b, + back_alpha, output_encoding); + } + + else + output_processing = PNG_CMAP_NONE; + } + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + /* 8-bit or 16-bit PNG with two channels - gray and alpha. A minimum + * of 65536 combinations. If, however, the alpha channel is to be + * removed there are only 256 possibilities if the background is gray. + * (Otherwise there is a subset of the 65536 possibilities defined by + * the triangle between black, white and the background color.) + * + * Reduce 16-bit files to 8-bit and sRGB encode the result. No need to + * worry about tRNS matching - tRNS is ignored if there is an alpha + * channel. + */ + data_encoding = E_sRGB; + + if (output_format & PNG_FORMAT_FLAG_ALPHA) + { + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray+alpha color-map: too few entries"); + + cmap_entries = make_ga_colormap(display); + + background_index = PNG_CMAP_GA_BACKGROUND; + output_processing = PNG_CMAP_GA; + } + + else /* alpha is removed */ + { + /* Alpha must be removed as the PNG data is processed when the + * background is a color because the G and A channels are + * independent and the vector addition (non-parallel vectors) is a + * 2-D problem. + * + * This can be reduced to the same algorithm as above by making a + * colormap containing gray levels (for the opaque grays), a + * background entry (for a transparent pixel) and a set of four six + * level color values, one set for each intermediate alpha value. + * See the comments in make_ga_colormap for how this works in the + * per-pixel processing. + * + * If the background is gray, however, we only need a 256 entry gray + * level color map. It is sufficient to make the entry generated + * for the background color be exactly the color specified. + */ + if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 || + (back_r == back_g && back_g == back_b)) + { + /* Background is gray; no special processing will be required. */ + png_color_16 c; + png_uint_32 gray = back_g; + + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray-alpha color-map: too few entries"); + + cmap_entries = make_gray_colormap(display); + + if (output_encoding == E_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry matches. */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 65535, E_LINEAR); + } + + /* The background passed to libpng, however, must be the sRGB + * value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_NONE; + } + + else + { + png_uint_32 i, a; + + /* This is the same as png_make_ga_colormap, above, except that + * the entries are all opaque. + */ + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "ga-alpha color-map: too few entries"); + + i = 0; + while (i < 231) + { + png_uint_32 gray = (i * 256 + 115) / 231; + png_create_colormap_entry(display, i++, gray, gray, gray, + 255, E_sRGB); + } + + /* NOTE: this preserves the full precision of the application + * background color. + */ + background_index = i; + png_create_colormap_entry(display, i++, back_r, back_g, back_b, + output_encoding == E_LINEAR ? 65535U : 255U, output_encoding); + + /* For non-opaque input composite on the sRGB background - this + * requires inverting the encoding for each component. The input + * is still converted to the sRGB encoding because this is a + * reasonable approximate to the logarithmic curve of human + * visual sensitivity, at least over the narrow range which PNG + * represents. Consequently 'G' is always sRGB encoded, while + * 'A' is linear. We need the linear background colors. + */ + if (output_encoding == E_sRGB) /* else already linear */ + { + /* This may produce a value not exactly matching the + * background, but that's ok because these numbers are only + * used when alpha != 0 + */ + back_r = png_sRGB_table[back_r]; + back_g = png_sRGB_table[back_g]; + back_b = png_sRGB_table[back_b]; + } + + for (a=1; a<5; ++a) + { + unsigned int g; + + /* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled + * by an 8-bit alpha value (0..255). + */ + png_uint_32 alpha = 51 * a; + png_uint_32 back_rx = (255-alpha) * back_r; + png_uint_32 back_gx = (255-alpha) * back_g; + png_uint_32 back_bx = (255-alpha) * back_b; + + for (g=0; g<6; ++g) + { + png_uint_32 gray = png_sRGB_table[g*51] * alpha; + + png_create_colormap_entry(display, i++, + PNG_sRGB_FROM_LINEAR(gray + back_rx), + PNG_sRGB_FROM_LINEAR(gray + back_gx), + PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, E_sRGB); + } + } + + cmap_entries = i; + output_processing = PNG_CMAP_GA; + } + } + break; + + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + /* Exclude the case where the output is gray; we can always handle this + * with the cases above. + */ + if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0) + { + /* The color-map will be grayscale, so we may as well convert the + * input RGB values to a simple grayscale and use the grayscale + * code above. + * + * NOTE: calling this apparently damages the recognition of the + * transparent color in background color handling; call + * png_set_tRNS_to_alpha before png_set_background_fixed. + */ + png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1, + -1); + data_encoding = E_sRGB; + + /* The output will now be one or two 8-bit gray or gray+alpha + * channels. The more complex case arises when the input has alpha. + */ + if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) && + (output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Both input and output have an alpha channel, so no background + * processing is required; just map the GA bytes to the right + * color-map entry. + */ + expand_tRNS = 1; + + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb[ga] color-map: too few entries"); + + cmap_entries = make_ga_colormap(display); + background_index = PNG_CMAP_GA_BACKGROUND; + output_processing = PNG_CMAP_GA; + } + + else + { + /* Either the input or the output has no alpha channel, so there + * will be no non-opaque pixels in the color-map; it will just be + * grayscale. + */ + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb[gray] color-map: too few entries"); + + /* Ideally this code would use libpng to do the gamma correction, + * but if an input alpha channel is to be removed we will hit the + * libpng bug in gamma+compose+rgb-to-gray (the double gamma + * correction bug). Fix this by dropping the gamma correction in + * this case and doing it in the palette; this will result in + * duplicate palette entries, but that's better than the + * alternative of double gamma correction. + */ + if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) && + png_gamma_not_sRGB(png_ptr->colorspace.gamma)) + { + cmap_entries = make_gray_file_colormap(display); + data_encoding = E_FILE; + } + + else + cmap_entries = make_gray_colormap(display); + + /* But if the input has alpha or transparency it must be removed + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) + { + png_color_16 c; + png_uint_32 gray = back_g; + + /* We need to ensure that the application background exists in + * the colormap and that completely transparent pixels map to + * it. Achieve this simply by ensuring that the entry + * selected for the background really is the background color. + */ + if (data_encoding == E_FILE) /* from the fixup above */ + { + /* The app supplied a gray which is in output_encoding, we + * need to convert it to a value of the input (E_FILE) + * encoding then set this palette entry to the required + * output encoding. + */ + if (output_encoding == E_sRGB) + gray = png_sRGB_table[gray]; /* now E_LINEAR */ + + gray = PNG_DIV257(png_gamma_16bit_correct(gray, + png_ptr->colorspace.gamma)); /* now E_FILE */ + + /* And make sure the corresponding palette entry contains + * exactly the required sRGB value. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 0/*unused*/, output_encoding); + } + + else if (output_encoding == E_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry matches. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 0/*unused*/, E_LINEAR); + } + + /* The background passed to libpng, however, must be the + * output (normally sRGB) value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + /* NOTE: the following is apparently a bug in libpng. Without + * it the transparent color recognition in + * png_set_background_fixed seems to go wrong. + */ + expand_tRNS = 1; + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + } + + output_processing = PNG_CMAP_NONE; + } + } + + else /* output is color */ + { + /* We could use png_quantize here so long as there is no transparent + * color or alpha; png_quantize ignores alpha. Easier overall just + * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube. + * Consequently we always want libpng to produce sRGB data. + */ + data_encoding = E_sRGB; + + /* Is there any transparency or alpha? */ + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) + { + /* Is there alpha in the output too? If so all four channels are + * processed into a special RGB cube with alpha support. + */ + if (output_format & PNG_FORMAT_FLAG_ALPHA) + { + png_uint_32 r; + + if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) + png_error(png_ptr, "rgb+alpha color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + + /* Add a transparent entry. */ + png_create_colormap_entry(display, cmap_entries, 255, 255, + 255, 0, E_sRGB); + + /* This is stored as the background index for the processing + * algorithm. + */ + background_index = cmap_entries++; + + /* Add 27 r,g,b entries each with alpha 0.5. */ + for (r=0; r<256; r = (r << 1) | 0x7f) + { + png_uint_32 g; + + for (g=0; g<256; g = (g << 1) | 0x7f) + { + png_uint_32 b; + + /* This generates components with the values 0, 127 and + * 255 + */ + for (b=0; b<256; b = (b << 1) | 0x7f) + png_create_colormap_entry(display, cmap_entries++, + r, g, b, 128, E_sRGB); + } + } + + expand_tRNS = 1; + output_processing = PNG_CMAP_RGB_ALPHA; + } + + else + { + /* Alpha/transparency must be removed. The background must + * exist in the color map (achieved by setting adding it after + * the 666 color-map). If the standard processing code will + * pick up this entry automatically that's all that is + * required; libpng can be called to do the background + * processing. + */ + unsigned int sample_size = + PNG_IMAGE_SAMPLE_SIZE(output_format); + png_uint_32 r, g, b; /* sRGB background */ + + if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) + png_error(png_ptr, "rgb-alpha color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + + png_create_colormap_entry(display, cmap_entries, back_r, + back_g, back_b, 0/*unused*/, output_encoding); + + if (output_encoding == E_LINEAR) + { + r = PNG_sRGB_FROM_LINEAR(back_r * 255); + g = PNG_sRGB_FROM_LINEAR(back_g * 255); + b = PNG_sRGB_FROM_LINEAR(back_b * 255); + } + + else + { + r = back_r; + g = back_g; + b = back_g; + } + + /* Compare the newly-created color-map entry with the one the + * PNG_CMAP_RGB algorithm will use. If the two entries don't + * match, add the new one and set this as the background + * index. + */ + if (memcmp((png_const_bytep)display->colormap + + sample_size * cmap_entries, + (png_const_bytep)display->colormap + + sample_size * PNG_RGB_INDEX(r,g,b), + sample_size) != 0) + { + /* The background color must be added. */ + background_index = cmap_entries++; + + /* Add 27 r,g,b entries each with created by composing with + * the background at alpha 0.5. + */ + for (r=0; r<256; r = (r << 1) | 0x7f) + { + for (g=0; g<256; g = (g << 1) | 0x7f) + { + /* This generates components with the values 0, 127 + * and 255 + */ + for (b=0; b<256; b = (b << 1) | 0x7f) + png_create_colormap_entry(display, cmap_entries++, + png_colormap_compose(display, r, E_sRGB, 128, + back_r, output_encoding), + png_colormap_compose(display, g, E_sRGB, 128, + back_g, output_encoding), + png_colormap_compose(display, b, E_sRGB, 128, + back_b, output_encoding), + 0/*unused*/, output_encoding); + } + } + + expand_tRNS = 1; + output_processing = PNG_CMAP_RGB_ALPHA; + } + + else /* background color is in the standard color-map */ + { + png_color_16 c; + + c.index = 0; /*unused*/ + c.red = (png_uint_16)back_r; + c.gray = c.green = (png_uint_16)back_g; + c.blue = (png_uint_16)back_b; + + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_RGB; + } + } + } + + else /* no alpha or transparency in the input */ + { + /* Alpha in the output is irrelevant, simply map the opaque input + * pixels to the 6x6x6 color-map. + */ + if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + output_processing = PNG_CMAP_RGB; + } + } + break; + + case PNG_COLOR_TYPE_PALETTE: + /* It's already got a color-map. It may be necessary to eliminate the + * tRNS entries though. + */ + { + unsigned int num_trans = png_ptr->num_trans; + png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL; + png_const_colorp colormap = png_ptr->palette; + const int do_background = trans != NULL && + (output_format & PNG_FORMAT_FLAG_ALPHA) == 0; + unsigned int i; + + /* Just in case: */ + if (trans == NULL) + num_trans = 0; + + output_processing = PNG_CMAP_NONE; + data_encoding = E_FILE; /* Don't change from color-map indicies */ + cmap_entries = png_ptr->num_palette; + if (cmap_entries > 256) + cmap_entries = 256; + + if (cmap_entries > image->colormap_entries) + png_error(png_ptr, "palette color-map: too few entries"); + + for (i=0; i < cmap_entries; ++i) + { + if (do_background && i < num_trans && trans[i] < 255) + { + if (trans[i] == 0) + png_create_colormap_entry(display, i, back_r, back_g, + back_b, 0, output_encoding); + + else + { + /* Must compose the PNG file color in the color-map entry + * on the sRGB color in 'back'. + */ + png_create_colormap_entry(display, i, + png_colormap_compose(display, colormap[i].red, E_FILE, + trans[i], back_r, output_encoding), + png_colormap_compose(display, colormap[i].green, E_FILE, + trans[i], back_g, output_encoding), + png_colormap_compose(display, colormap[i].blue, E_FILE, + trans[i], back_b, output_encoding), + output_encoding == E_LINEAR ? trans[i] * 257U : + trans[i], + output_encoding); + } + } + + else + png_create_colormap_entry(display, i, colormap[i].red, + colormap[i].green, colormap[i].blue, + i < num_trans ? trans[i] : 255U, E_FILE/*8-bit*/); + } + + /* The PNG data may have indicies packed in fewer than 8 bits, it + * must be expanded if so. + */ + if (png_ptr->bit_depth < 8) + png_set_packing(png_ptr); + } + break; + + default: + png_error(png_ptr, "invalid PNG color type"); + /*NOT REACHED*/ + break; + } + + /* Now deal with the output processing */ + if (expand_tRNS && png_ptr->num_trans > 0 && + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0) + png_set_tRNS_to_alpha(png_ptr); + + switch (data_encoding) + { + default: + png_error(png_ptr, "bad data option (internal error)"); + break; + + case E_sRGB: + /* Change to 8-bit sRGB */ + png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB); + /* FALL THROUGH */ + + case E_FILE: + if (png_ptr->bit_depth > 8) + png_set_scale_16(png_ptr); + break; + } + + if (cmap_entries > 256 || cmap_entries > image->colormap_entries) + png_error(png_ptr, "color map overflow (BAD internal error)"); + + image->colormap_entries = cmap_entries; + + /* Double check using the recorded background index */ + switch (output_processing) + { + case PNG_CMAP_NONE: + if (background_index != PNG_CMAP_NONE_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_GA: + if (background_index != PNG_CMAP_GA_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_TRANS: + if (background_index >= cmap_entries || + background_index != PNG_CMAP_TRANS_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_RGB: + if (background_index != PNG_CMAP_RGB_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_RGB_ALPHA: + if (background_index != PNG_CMAP_RGB_ALPHA_BACKGROUND) + goto bad_background; + break; + + default: + png_error(png_ptr, "bad processing option (internal error)"); + + bad_background: + png_error(png_ptr, "bad background index (internal error)"); + } + + display->colormap_processing = output_processing; + + return 1/*ok*/; +} + +/* The final part of the color-map read called from png_image_finish_read. */ +static int +png_image_read_and_map(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + int passes; + + /* Called when the libpng data must be transformed into the color-mapped + * form. There is a local row buffer in display->local and this routine must + * do the interlace handling. + */ + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + passes = 0; + png_error(png_ptr, "unknown interlace type"); + } + + { + png_uint_32 height = image->height; + png_uint_32 width = image->width; + int proc = display->colormap_processing; + png_bytep first_row = png_voidcast(png_bytep, display->first_row); + ptrdiff_t step_row = display->row_bytes; + int pass; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass); + stepx = PNG_PASS_COL_OFFSET(pass); + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = stepy = 1; + } + + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read read the libpng data into the temporary buffer. */ + png_read_row(png_ptr, inrow, NULL); + + /* Now process the row according to the processing option, note + * that the caller verifies that the format of the libpng output + * data is as required. + */ + outrow += startx; + switch (proc) + { + case PNG_CMAP_GA: + for (; outrow < end_row; outrow += stepx) + { + /* The data is always in the PNG order */ + unsigned int gray = *inrow++; + unsigned int alpha = *inrow++; + unsigned int entry; + + /* NOTE: this code is copied as a comment in + * make_ga_colormap above. Please update the + * comment if you change this code! + */ + if (alpha > 229) /* opaque */ + { + entry = (231 * gray + 128) >> 8; + } + else if (alpha < 26) /* transparent */ + { + entry = 231; + } + else /* partially opaque */ + { + entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray); + } + + *outrow = (png_byte)entry; + } + break; + + case PNG_CMAP_TRANS: + for (; outrow < end_row; outrow += stepx) + { + png_byte gray = *inrow++; + png_byte alpha = *inrow++; + + if (alpha == 0) + *outrow = PNG_CMAP_TRANS_BACKGROUND; + + else if (gray != PNG_CMAP_TRANS_BACKGROUND) + *outrow = gray; + + else + *outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1); + } + break; + + case PNG_CMAP_RGB: + for (; outrow < end_row; outrow += stepx) + { + *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]); + inrow += 3; + } + break; + + case PNG_CMAP_RGB_ALPHA: + for (; outrow < end_row; outrow += stepx) + { + unsigned int alpha = inrow[3]; + + /* Because the alpha entries only hold alpha==0.5 values + * split the processing at alpha==0.25 (64) and 0.75 + * (196). + */ + + if (alpha >= 196) + *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], + inrow[2]); + + else if (alpha < 64) + *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND; + + else + { + /* Likewise there are three entries for each of r, g + * and b. We could select the entry by popcount on + * the top two bits on those architectures that + * support it, this is what the code below does, + * crudely. + */ + unsigned int back_i = PNG_CMAP_RGB_ALPHA_BACKGROUND+1; + + /* Here are how the values map: + * + * 0x00 .. 0x3f -> 0 + * 0x40 .. 0xbf -> 1 + * 0xc0 .. 0xff -> 2 + * + * So, as above with the explicit alpha checks, the + * breakpoints are at 64 and 196. + */ + if (inrow[0] & 0x80) back_i += 9; /* red */ + if (inrow[0] & 0x40) back_i += 9; + if (inrow[0] & 0x80) back_i += 3; /* green */ + if (inrow[0] & 0x40) back_i += 3; + if (inrow[0] & 0x80) back_i += 1; /* blue */ + if (inrow[0] & 0x40) back_i += 1; + + *outrow = (png_byte)back_i; + } + + inrow += 4; + } + break; + + default: + break; + } + } + } + } + + return 1; +} + +static int +png_image_read_colormapped(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_controlp control = image->opaque; + png_structrp png_ptr = control->png_ptr; + png_inforp info_ptr = control->info_ptr; + + int passes = 0; /* As a flag */ + + PNG_SKIP_CHUNKS(png_ptr); + + /* Update the 'info' structure and make sure the result is as required; first + * make sure to turn on the interlace handling if it will be required + * (because it can't be turned on *after* the call to png_read_update_info!) + */ + if (display->colormap_processing == PNG_CMAP_NONE) + passes = png_set_interlace_handling(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + /* The expected output can be deduced from the colormap_processing option. */ + switch (display->colormap_processing) + { + case PNG_CMAP_NONE: + /* Output must be one channel and one byte per pixel, the output + * encoding can be anything. + */ + if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY) && + info_ptr->bit_depth == 8) + break; + + goto bad_output; + + case PNG_CMAP_TRANS: + case PNG_CMAP_GA: + /* Output must be two channels and the 'G' one must be sRGB, the latter + * can be checked with an exact number because it should have been set + * to this number above! + */ + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 256) + break; + + goto bad_output; + + case PNG_CMAP_RGB: + /* Output must be 8-bit sRGB encoded RGB */ + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 216) + break; + + goto bad_output; + + case PNG_CMAP_RGB_ALPHA: + /* Output must be 8-bit sRGB encoded RGBA */ + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 244 /* 216 + 1 + 27 */) + break; + + /* goto bad_output; */ + /* FALL THROUGH */ + + default: + bad_output: + png_error(png_ptr, "bad color-map processing (internal error)"); + } + + /* Now read the rows. Do this here if it is possible to read directly into + * the output buffer, otherwise allocate a local row buffer of the maximum + * size libpng requires and call the relevant processing routine safely. + */ + { + png_voidp first_row = display->buffer; + ptrdiff_t row_bytes = display->row_stride; + + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. + */ + if (row_bytes < 0) + { + char *ptr = png_voidcast(char*, first_row); + ptr += (image->height-1) * (-row_bytes); + first_row = png_voidcast(png_voidp, ptr); + } + + display->first_row = first_row; + display->row_bytes = row_bytes; + } + + if (passes == 0) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_and_map, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else + { + png_alloc_size_t row_bytes = display->row_bytes; + + while (--passes >= 0) + { + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); + + while (y-- > 0) + { + png_read_row(png_ptr, row, NULL); + row += row_bytes; + } + } + + return 1; + } +} + +/* Just the row reading part of png_image_read. */ +static int +png_image_read_composite(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + int passes; + + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + passes = 0; + png_error(png_ptr, "unknown interlace type"); + } + + { + png_uint_32 height = image->height; + png_uint_32 width = image->width; + ptrdiff_t step_row = display->row_bytes; + unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; + int pass; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass) * channels; + stepx = PNG_PASS_COL_OFFSET(pass) * channels; + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = channels; + stepy = 1; + } + + for (; ylocal_row); + png_bytep outrow; + png_const_bytep end_row; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + outrow = png_voidcast(png_bytep, display->first_row); + outrow += y * step_row; + end_row = outrow + width * channels; + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[channels]; + + if (alpha > 0) /* else no change to the output */ + { + unsigned int c; + + for (c=0; cimage; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + png_uint_32 height = image->height; + png_uint_32 width = image->width; + int pass, passes; + + /* Double check the convoluted logic below. We expect to get here with + * libpng doing rgb to gray and gamma correction but background processing + * left to the png_image_read_background function. The rows libpng produce + * might be 8 or 16-bit but should always have two channels; gray plus alpha. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) + png_error(png_ptr, "lost rgb to gray"); + + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_error(png_ptr, "unexpected compose"); + + if (png_get_channels(png_ptr, info_ptr) != 2) + png_error(png_ptr, "lost/gained channels"); + + /* Expect the 8-bit case to always remove the alpha channel */ + if ((image->format & PNG_FORMAT_FLAG_LINEAR) == 0 && + (image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + png_error(png_ptr, "unexpected 8-bit transformation"); + + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + passes = 0; + png_error(png_ptr, "unknown interlace type"); + } + + switch (png_get_bit_depth(png_ptr, info_ptr)) + { + default: + png_error(png_ptr, "unexpected bit depth"); + break; + + case 8: + /* 8-bit sRGB gray values with an alpha channel; the alpha channel is + * to be removed by composing on a backgroundi: either the row if + * display->background is NULL or display->background->green if not. + * Unlike the code above ALPHA_OPTIMIZED has *not* been done. + */ + { + png_bytep first_row = png_voidcast(png_bytep, display->first_row); + ptrdiff_t step_row = display->row_bytes; + + for (pass = 0; pass < passes; ++pass) + { + png_bytep row = png_voidcast(png_bytep, + display->first_row); + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass); + stepx = PNG_PASS_COL_OFFSET(pass); + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = stepy = 1; + } + + if (display->background == NULL) + { + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[1]; + + if (alpha > 0) /* else no change to the output */ + { + png_uint_32 component = inrow[0]; + + if (alpha < 255) /* else just use component */ + { + /* Since PNG_OPTIMIZED_ALPHA was not set it is + * necessary to invert the sRGB transfer + * function and multiply the alpha out. + */ + component = png_sRGB_table[component] * alpha; + component += png_sRGB_table[outrow[0]] * + (255-alpha); + component = PNG_sRGB_FROM_LINEAR(component); + } + + outrow[0] = (png_byte)component; + } + + inrow += 2; /* gray and alpha channel */ + } + } + } + + else /* constant background value */ + { + png_byte background8 = display->background->green; + png_uint_16 background = png_sRGB_table[background8]; + + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[1]; + + if (alpha > 0) /* else use background */ + { + png_uint_32 component = inrow[0]; + + if (alpha < 255) /* else just use component */ + { + component = png_sRGB_table[component] * alpha; + component += background * (255-alpha); + component = PNG_sRGB_FROM_LINEAR(component); + } + + outrow[0] = (png_byte)component; + } + + else + outrow[0] = background8; + + inrow += 2; /* gray and alpha channel */ + } + + row += display->row_bytes; + } + } + } + } + break; + + case 16: + /* 16-bit linear with pre-multiplied alpha; the pre-multiplication must + * still be done and, maybe, the alpha channel removed. This code also + * handles the alpha-first option. + */ + { + png_uint_16p first_row = png_voidcast(png_uint_16p, + display->first_row); + /* The division by two is safe because the caller passed in a + * stride which was multiplied by 2 (below) to get row_bytes. + */ + ptrdiff_t step_row = display->row_bytes / 2; + int preserve_alpha = (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; + unsigned int outchannels = 1+preserve_alpha; + int swap_alpha = 0; + + if (preserve_alpha && (image->format & PNG_FORMAT_FLAG_AFIRST)) + swap_alpha = 1; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + /* The 'x' start and step are adjusted to output components here. + */ + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass) * outchannels; + stepx = PNG_PASS_COL_OFFSET(pass) * outchannels; + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = outchannels; + stepy = 1; + } + + for (; ylocal_row), NULL); + inrow = png_voidcast(png_const_uint_16p, display->local_row); + + /* Now do the pre-multiplication on each pixel in this row. + */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_uint_32 component = inrow[0]; + png_uint_16 alpha = inrow[1]; + + if (alpha > 0) /* else 0 */ + { + if (alpha < 65535) /* else just use component */ + { + component *= alpha; + component += 32767; + component /= 65535; + } + } + + else + component = 0; + + outrow[swap_alpha] = (png_uint_16)component; + if (preserve_alpha) + outrow[1 ^ swap_alpha] = alpha; + + inrow += 2; /* components and alpha channel */ + } + } + } + } + break; + } + + return 1; +} + +/* The guts of png_image_finish_read as a png_safe_execute callback. */ +static int +png_image_read_direct(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + + png_uint_32 format = image->format; + int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0; + int do_local_compose = 0; + int do_local_background = 0; /* to avoid double gamma correction bug */ + int passes = 0; + + /* Add transforms to ensure the correct output format is produced then check + * that the required implementation support is there. Always expand; always + * need 8 bits minimum, no palette and expanded tRNS. + */ + png_set_expand(png_ptr); + + /* Now check the format to see if it was modified. */ + { + png_uint_32 base_format = png_image_format(png_ptr) & + ~PNG_FORMAT_FLAG_COLORMAP /* removed by png_set_expand */; + png_uint_32 change = format ^ base_format; + png_fixed_point output_gamma; + int mode; /* alpha mode */ + + /* Do this first so that we have a record if rgb to gray is happening. */ + if (change & PNG_FORMAT_FLAG_COLOR) + { + /* gray<->color transformation required. */ + if (format & PNG_FORMAT_FLAG_COLOR) + png_set_gray_to_rgb(png_ptr); + + else + { + /* libpng can't do both rgb to gray and + * background/pre-multiplication if there is also significant gamma + * correction, because both operations require linear colors and + * the code only supports one transform doing the gamma correction. + * Handle this by doing the pre-multiplication or background + * operation in this code, if necessary. + * + * TODO: fix this by rewriting pngrtran.c (!) + * + * For the moment (given that fixing this in pngrtran.c is an + * enormous change) 'do_local_background' is used to indicate that + * the problem exists. + */ + if (base_format & PNG_FORMAT_FLAG_ALPHA) + do_local_background = 1/*maybe*/; + + png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, + PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); + } + + change &= ~PNG_FORMAT_FLAG_COLOR; + } + + /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise. + */ + { + png_fixed_point input_gamma_default; + + if ((base_format & PNG_FORMAT_FLAG_LINEAR) && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + input_gamma_default = PNG_GAMMA_LINEAR; + else + input_gamma_default = PNG_DEFAULT_sRGB; + + /* Call png_set_alpha_mode to set the default for the input gamma; the + * output gamma is set by a second call below. + */ + png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default); + } + + if (linear) + { + /* If there *is* an alpha channel in the input it must be multiplied + * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG. + */ + if (base_format & PNG_FORMAT_FLAG_ALPHA) + mode = PNG_ALPHA_STANDARD; /* associated alpha */ + + else + mode = PNG_ALPHA_PNG; + + output_gamma = PNG_GAMMA_LINEAR; + } + + else + { + mode = PNG_ALPHA_PNG; + output_gamma = PNG_DEFAULT_sRGB; + } + + /* If 'do_local_background' is set check for the presence of gamma + * correction; this is part of the work-round for the libpng bug + * described above. + * + * TODO: fix libpng and remove this. + */ + if (do_local_background) + { + png_fixed_point gtest; + + /* This is 'png_gamma_threshold' from pngrtran.c; the test used for + * gamma correction, the screen gamma hasn't been set on png_struct + * yet; it's set below. png_struct::gamma, however, is set to the + * final value. + */ + if (png_muldiv(>est, output_gamma, png_ptr->colorspace.gamma, + PNG_FP_1) && !png_gamma_significant(gtest)) + do_local_background = 0; + + else if (mode == PNG_ALPHA_STANDARD) + { + do_local_background = 2/*required*/; + mode = PNG_ALPHA_PNG; /* prevent libpng doing it */ + } + + /* else leave as 1 for the checks below */ + } + + /* If the bit-depth changes then handle that here. */ + if (change & PNG_FORMAT_FLAG_LINEAR) + { + if (linear /*16-bit output*/) + png_set_expand_16(png_ptr); + + else /* 8-bit output */ + png_set_scale_16(png_ptr); + + change &= ~PNG_FORMAT_FLAG_LINEAR; + } + + /* Now the background/alpha channel changes. */ + if (change & PNG_FORMAT_FLAG_ALPHA) + { + /* Removing an alpha channel requires composition for the 8-bit + * formats; for the 16-bit it is already done, above, by the + * pre-multiplication and the channel just needs to be stripped. + */ + if (base_format & PNG_FORMAT_FLAG_ALPHA) + { + /* If RGB->gray is happening the alpha channel must be left and the + * operation completed locally. + * + * TODO: fix libpng and remove this. + */ + if (do_local_background) + do_local_background = 2/*required*/; + + /* 16-bit output: just remove the channel */ + else if (linear) /* compose on black (well, pre-multiply) */ + png_set_strip_alpha(png_ptr); + + /* 8-bit output: do an appropriate compose */ + else if (display->background != NULL) + { + png_color_16 c; + + c.index = 0; /*unused*/ + c.red = display->background->red; + c.green = display->background->green; + c.blue = display->background->blue; + c.gray = display->background->green; + + /* This is always an 8-bit sRGB value, using the 'green' channel + * for gray is much better than calculating the luminance here; + * we can get off-by-one errors in that calculation relative to + * the app expectations and that will show up in transparent + * pixels. + */ + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + } + + else /* compose on row: implemented below. */ + { + do_local_compose = 1; + /* This leaves the alpha channel in the output, so it has to be + * removed by the code below. Set the encoding to the 'OPTIMIZE' + * one so the code only has to hack on the pixels that require + * composition. + */ + mode = PNG_ALPHA_OPTIMIZED; + } + } + + else /* output needs an alpha channel */ + { + /* This is tricky because it happens before the swap operation has + * been accomplished; however, the swap does *not* swap the added + * alpha channel (weird API), so it must be added in the correct + * place. + */ + png_uint_32 filler; /* opaque filler */ + int where; + + if (linear) + filler = 65535; + + else + filler = 255; + +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (format & PNG_FORMAT_FLAG_AFIRST) + { + where = PNG_FILLER_BEFORE; + change &= ~PNG_FORMAT_FLAG_AFIRST; + } + + else +# endif + where = PNG_FILLER_AFTER; + + png_set_add_alpha(png_ptr, filler, where); + } + + /* This stops the (irrelevant) call to swap_alpha below. */ + change &= ~PNG_FORMAT_FLAG_ALPHA; + } + + /* Now set the alpha mode correctly; this is always done, even if there is + * no alpha channel in either the input or the output because it correctly + * sets the output gamma. + */ + png_set_alpha_mode_fixed(png_ptr, mode, output_gamma); + +# ifdef PNG_FORMAT_BGR_SUPPORTED + if (change & PNG_FORMAT_FLAG_BGR) + { + /* Check only the output format; PNG is never BGR; don't do this if + * the output is gray, but fix up the 'format' value in that case. + */ + if (format & PNG_FORMAT_FLAG_COLOR) + png_set_bgr(png_ptr); + + else + format &= ~PNG_FORMAT_FLAG_BGR; + + change &= ~PNG_FORMAT_FLAG_BGR; + } +# endif + +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (change & PNG_FORMAT_FLAG_AFIRST) + { + /* Only relevant if there is an alpha channel - it's particularly + * important to handle this correctly because do_local_compose may + * be set above and then libpng will keep the alpha channel for this + * code to remove. + */ + if (format & PNG_FORMAT_FLAG_ALPHA) + { + /* Disable this if doing a local background, + * TODO: remove this when local background is no longer required. + */ + if (do_local_background != 2) + png_set_swap_alpha(png_ptr); + } + + else + format &= ~PNG_FORMAT_FLAG_AFIRST; + + change &= ~PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* If the *output* is 16-bit then we need to check for a byte-swap on this + * architecture. + */ + if (linear) + { + PNG_CONST png_uint_16 le = 0x0001; + + if (*(png_const_bytep)&le) + png_set_swap(png_ptr); + } + + /* If change is not now 0 some transformation is missing - error out. */ + if (change) + png_error(png_ptr, "png_read_image: unsupported transformation"); + } + + PNG_SKIP_CHUNKS(png_ptr); + + /* Update the 'info' structure and make sure the result is as required; first + * make sure to turn on the interlace handling if it will be required + * (because it can't be turned on *after* the call to png_read_update_info!) + * + * TODO: remove the do_local_background fixup below. + */ + if (!do_local_compose && do_local_background != 2) + passes = png_set_interlace_handling(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + { + png_uint_32 info_format = 0; + + if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_format |= PNG_FORMAT_FLAG_COLOR; + + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + { + /* do_local_compose removes this channel below. */ + if (!do_local_compose) + { + /* do_local_background does the same if required. */ + if (do_local_background != 2 || + (format & PNG_FORMAT_FLAG_ALPHA) != 0) + info_format |= PNG_FORMAT_FLAG_ALPHA; + } + } + + else if (do_local_compose) /* internal error */ + png_error(png_ptr, "png_image_read: alpha channel lost"); + + if (info_ptr->bit_depth == 16) + info_format |= PNG_FORMAT_FLAG_LINEAR; + +# ifdef PNG_FORMAT_BGR_SUPPORTED + if (png_ptr->transformations & PNG_BGR) + info_format |= PNG_FORMAT_FLAG_BGR; +# endif + +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (do_local_background == 2) + { + if (format & PNG_FORMAT_FLAG_AFIRST) + info_format |= PNG_FORMAT_FLAG_AFIRST; + } + + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0 || + ((png_ptr->transformations & PNG_ADD_ALPHA) != 0 && + (png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0)) + { + if (do_local_background == 2) + png_error(png_ptr, "unexpected alpha swap transformation"); + + info_format |= PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* This is actually an internal error. */ + if (info_format != format) + png_error(png_ptr, "png_read_image: invalid transformations"); + } + + /* Now read the rows. If do_local_compose is set then it is necessary to use + * a local row buffer. The output will be GA, RGBA or BGRA and must be + * converted to G, RGB or BGR as appropriate. The 'local_row' member of the + * display acts as a flag. + */ + { + png_voidp first_row = display->buffer; + ptrdiff_t row_bytes = display->row_stride; + + if (linear) + row_bytes *= 2; + + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. + */ + if (row_bytes < 0) + { + char *ptr = png_voidcast(char*, first_row); + ptr += (image->height-1) * (-row_bytes); + first_row = png_voidcast(png_voidp, ptr); + } + + display->first_row = first_row; + display->row_bytes = row_bytes; + } + + if (do_local_compose) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_composite, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else if (do_local_background == 2) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_background, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else + { + png_alloc_size_t row_bytes = display->row_bytes; + + while (--passes >= 0) + { + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); + + while (y-- > 0) + { + png_read_row(png_ptr, row, NULL); + row += row_bytes; + } + } + + return 1; + } +} + +int PNGAPI +png_image_finish_read(png_imagep image, png_const_colorp background, + void *buffer, png_int_32 row_stride, void *colormap) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + png_uint_32 check; + + if (row_stride == 0) + row_stride = PNG_IMAGE_ROW_STRIDE(*image); + + if (row_stride < 0) + check = -row_stride; + + else + check = row_stride; + + if (image->opaque != NULL && buffer != NULL && + check >= PNG_IMAGE_ROW_STRIDE(*image)) + { + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || + (image->colormap_entries > 0 && colormap != NULL)) + { + int result; + png_image_read_control display; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.background = background; + display.local_row = NULL; + + /* Choose the correct 'end' routine; for the color-map case all the + * setup has already been done. + */ + if (image->format & PNG_FORMAT_FLAG_COLORMAP) + result = + png_safe_execute(image, png_image_read_colormap, &display) && + png_safe_execute(image, png_image_read_colormapped, &display); + + else + result = + png_safe_execute(image, png_image_read_direct, &display); + + png_image_free(image); + return result; + } + + else + return png_image_error(image, + "png_image_finish_read[color-map]: no color-map"); + } + + else + return png_image_error(image, + "png_image_finish_read: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_finish_read: damaged PNG_IMAGE_VERSION"); + + return 0; +} + +#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED */ +#endif diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrio.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrio.c new file mode 100644 index 0000000000..5f927d127b --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrio.c @@ -0,0 +1,119 @@ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +/* pngrio.c - functions for data input + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all input. Users who need + * special handling are expected to write a function that has the same + * arguments as this and performs a similar function, but that possibly + * has a different input method. Note that you shouldn't change this + * function, but rather write a replacement function and then make + * libpng use it at run time with png_set_read_fn(...). + */ + +#include "pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +/* Read the data from whatever input you are using. The default routine + * reads from a file pointer. Note that this routine sometimes gets called + * with very small lengths, so you should implement some kind of simple + * buffering if you are using unbuffered reads. This should never be asked + * to read more then 64K on a 16 bit machine. + */ +void /* PRIVATE */ +png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length) +{ + png_debug1(4, "reading %d bytes", (int)length); + + if (png_ptr->read_data_fn != NULL) + (*(png_ptr->read_data_fn))(png_ptr, data, length); + + else + png_error(png_ptr, "Call to NULL read function"); +} + +#ifdef PNG_STDIO_SUPPORTED +/* This is the function that does the actual reading of data. If you are + * not reading from a standard C stream, you should create a replacement + * read_data function and use it at run time with png_set_read_fn(), rather + * than changing the library. + */ +void PNGCBAPI +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + if (png_ptr == NULL) + return; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr)); + + if (check != length) + png_error(png_ptr, "Read Error"); +} +#endif + +/* This function allows the application to supply a new input function + * for libpng if standard C streams aren't being used. + * + * This function takes as its arguments: + * + * png_ptr - pointer to a png input data structure + * + * io_ptr - pointer to user supplied structure containing info about + * the input functions. May be NULL. + * + * read_data_fn - pointer to a new input function that takes as its + * arguments a pointer to a png_struct, a pointer to + * a location where input data can be stored, and a 32-bit + * unsigned int that is the number of bytes to be read. + * To exit and output any fatal error messages the new write + * function should call png_error(png_ptr, "Error msg"). + * May be NULL, in which case libpng's default function will + * be used. + */ +void PNGAPI +png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = io_ptr; + +#ifdef PNG_STDIO_SUPPORTED + if (read_data_fn != NULL) + png_ptr->read_data_fn = read_data_fn; + + else + png_ptr->read_data_fn = png_default_read_data; +#else + png_ptr->read_data_fn = read_data_fn; +#endif + + /* It is an error to write to a read device */ + if (png_ptr->write_data_fn != NULL) + { + png_ptr->write_data_fn = NULL; + png_warning(png_ptr, + "Can't set both read_data_fn and write_data_fn in the" + " same structure"); + } + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_ptr->output_flush_fn = NULL; +#endif +} +#endif /* PNG_READ_SUPPORTED */ +#endif diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrtran.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrtran.c new file mode 100644 index 0000000000..4a279be3ff --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrtran.c @@ -0,0 +1,5104 @@ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +/* pngrtran.c - transforms the data in a row for PNG readers + * + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains functions optionally called by an application + * in order to tell libpng how to handle data when reading a PNG. + * Transformations that are used in both reading and writing are + * in pngtrans.c. + */ + +#include "pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +/* Set the action on getting a CRC error for an ancillary or critical chunk. */ +void PNGAPI +png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action) +{ + png_debug(1, "in png_set_crc_action"); + + if (png_ptr == NULL) + return; + + /* Tell libpng how we react to CRC errors in critical chunks */ + switch (crit_action) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | + PNG_FLAG_CRC_CRITICAL_IGNORE; + break; + + case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ + png_warning(png_ptr, + "Can't discard critical data on CRC error"); + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + break; + } + + /* Tell libpng how we react to CRC errors in ancillary chunks */ + switch (ancil_action) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | + PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + + case PNG_CRC_WARN_DISCARD: /* Warn/discard data */ + + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + break; + } +} + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* Is it OK to set a transformation now? Only if png_start_read_image or + * png_read_update_info have not been called. It is not necessary for the IHDR + * to have been read in all cases, the parameter allows for this check too. + */ +static int +png_rtran_ok(png_structrp png_ptr, int need_IHDR) +{ + if (png_ptr != NULL) + { + if (png_ptr->flags & PNG_FLAG_ROW_INIT) + png_app_error(png_ptr, + "invalid after png_start_read_image or png_read_update_info"); + + else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_app_error(png_ptr, "invalid before the PNG header has been read"); + + else + { + /* Turn on failure to initialize correctly for all transforms. */ + png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED; + + return 1; /* Ok */ + } + } + + return 0; /* no png_error possible! */ +} +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Handle alpha and tRNS via a background color */ +void PNGFAPI +png_set_background_fixed(png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, png_fixed_point background_gamma) +{ + png_debug(1, "in png_set_background_fixed"); + + if (!png_rtran_ok(png_ptr, 0) || background_color == NULL) + return; + + if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) + { + png_warning(png_ptr, "Application must supply a known background gamma"); + return; + } + + png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + png_ptr->background = *background_color; + png_ptr->background_gamma = background_gamma; + png_ptr->background_gamma_type = (png_byte)(background_gamma_code); + if (need_expand) + png_ptr->transformations |= PNG_BACKGROUND_EXPAND; + else + png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_background(png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma) +{ + png_set_background_fixed(png_ptr, background_color, background_gamma_code, + need_expand, png_fixed(png_ptr, background_gamma, "png_set_background")); +} +# endif /* FLOATING_POINT */ +#endif /* READ_BACKGROUND */ + +/* Scale 16-bit depth files to 8-bit depth. If both of these are set then the + * one that pngrtran does first (scale) happens. This is necessary to allow the + * TRANSFORM and API behavior to be somewhat consistent, and it's simpler. + */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +void PNGAPI +png_set_scale_16(png_structrp png_ptr) +{ + png_debug(1, "in png_set_scale_16"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + png_ptr->transformations |= PNG_SCALE_16_TO_8; +} +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +/* Chop 16-bit depth files to 8-bit depth */ +void PNGAPI +png_set_strip_16(png_structrp png_ptr) +{ + png_debug(1, "in png_set_strip_16"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + png_ptr->transformations |= PNG_16_TO_8; +} +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +void PNGAPI +png_set_strip_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_strip_alpha"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + png_ptr->transformations |= PNG_STRIP_ALPHA; +} +#endif + +#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED) +static png_fixed_point +translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma, + int is_screen) +{ + /* Check for flag values. The main reason for having the old Mac value as a + * flag is that it is pretty near impossible to work out what the correct + * value is from Apple documentation - a working Mac system is needed to + * discover the value! + */ + if (output_gamma == PNG_DEFAULT_sRGB || + output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB) + { + /* If there is no sRGB support this just sets the gamma to the standard + * sRGB value. (This is a side effect of using this function!) + */ +# ifdef PNG_READ_sRGB_SUPPORTED + png_ptr->flags |= PNG_FLAG_ASSUME_sRGB; +# else + PNG_UNUSED(png_ptr) +# endif + if (is_screen) + output_gamma = PNG_GAMMA_sRGB; + else + output_gamma = PNG_GAMMA_sRGB_INVERSE; + } + + else if (output_gamma == PNG_GAMMA_MAC_18 || + output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18) + { + if (is_screen) + output_gamma = PNG_GAMMA_MAC_OLD; + else + output_gamma = PNG_GAMMA_MAC_INVERSE; + } + + return output_gamma; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +static png_fixed_point +convert_gamma_value(png_structrp png_ptr, double output_gamma) +{ + /* The following silently ignores cases where fixed point (times 100,000) + * gamma values are passed to the floating point API. This is safe and it + * means the fixed point constants work just fine with the floating point + * API. The alternative would just lead to undetected errors and spurious + * bug reports. Negative values fail inside the _fixed API unless they + * correspond to the flag values. + */ + if (output_gamma > 0 && output_gamma < 128) + output_gamma *= PNG_FP_1; + + /* This preserves -1 and -2 exactly: */ + output_gamma = floor(output_gamma + .5); + + if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN) + png_fixed_error(png_ptr, "gamma value"); + + return (png_fixed_point)output_gamma; +} +# endif +#endif /* READ_ALPHA_MODE || READ_GAMMA */ + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +void PNGFAPI +png_set_alpha_mode_fixed(png_structrp png_ptr, int mode, + png_fixed_point output_gamma) +{ + int compose = 0; + png_fixed_point file_gamma; + + png_debug(1, "in png_set_alpha_mode"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/); + + /* Validate the value to ensure it is in a reasonable range. The value + * is expected to be 1 or greater, but this range test allows for some + * viewing correction values. The intent is to weed out users of this API + * who use the inverse of the gamma value accidentally! Since some of these + * values are reasonable this may have to be changed. + */ + if (output_gamma < 70000 || output_gamma > 300000) + png_error(png_ptr, "output gamma out of expected range"); + + /* The default file gamma is the inverse of the output gamma; the output + * gamma may be changed below so get the file value first: + */ + file_gamma = png_reciprocal(output_gamma); + + /* There are really 8 possibilities here, composed of any combination + * of: + * + * premultiply the color channels + * do not encode non-opaque pixels + * encode the alpha as well as the color channels + * + * The differences disappear if the input/output ('screen') gamma is 1.0, + * because then the encoding is a no-op and there is only the choice of + * premultiplying the color channels or not. + * + * png_set_alpha_mode and png_set_background interact because both use + * png_compose to do the work. Calling both is only useful when + * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along + * with a default gamma value. Otherwise PNG_COMPOSE must not be set. + */ + switch (mode) + { + case PNG_ALPHA_PNG: /* default: png standard */ + /* No compose, but it may be set by png_set_background! */ + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + break; + + case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */ + compose = 1; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + /* The output is linear: */ + output_gamma = PNG_FP_1; + break; + + case PNG_ALPHA_OPTIMIZED: /* associated, non-opaque pixels linear */ + compose = 1; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA; + /* output_gamma records the encoding of opaque pixels! */ + break; + + case PNG_ALPHA_BROKEN: /* associated, non-linear, alpha encoded */ + compose = 1; + png_ptr->transformations |= PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + break; + + default: + png_error(png_ptr, "invalid alpha mode"); + } + + /* Only set the default gamma if the file gamma has not been set (this has + * the side effect that the gamma in a second call to png_set_alpha_mode will + * be ignored.) + */ + if (png_ptr->colorspace.gamma == 0) + { + png_ptr->colorspace.gamma = file_gamma; + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + } + + /* But always set the output gamma: */ + png_ptr->screen_gamma = output_gamma; + + /* Finally, if pre-multiplying, set the background fields to achieve the + * desired result. + */ + if (compose) + { + /* And obtain alpha pre-multiplication by composing on black: */ + memset(&png_ptr->background, 0, (sizeof png_ptr->background)); + png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */ + png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE; + png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; + + if (png_ptr->transformations & PNG_COMPOSE) + png_error(png_ptr, + "conflicting calls to set alpha mode and background"); + + png_ptr->transformations |= PNG_COMPOSE; + } +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) +{ + png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr, + output_gamma)); +} +# endif +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* Dither file to 8-bit. Supply a palette, the current number + * of elements in the palette, the maximum number of elements + * allowed, and a histogram if possible. If the current number + * of colors is greater then the maximum number, the palette will be + * modified to fit in the maximum number. "full_quantize" indicates + * whether we need a quantizing cube set up for RGB images, or if we + * simply are reducing the number of colors in a paletted image. + */ + +typedef struct png_dsort_struct +{ + struct png_dsort_struct * next; + png_byte left; + png_byte right; +} png_dsort; +typedef png_dsort * png_dsortp; +typedef png_dsort * * png_dsortpp; + +void PNGAPI +png_set_quantize(png_structrp png_ptr, png_colorp palette, + int num_palette, int maximum_colors, png_const_uint_16p histogram, + int full_quantize) +{ + png_debug(1, "in png_set_quantize"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + png_ptr->transformations |= PNG_QUANTIZE; + + if (!full_quantize) + { + int i; + + png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * (sizeof (png_byte)))); + for (i = 0; i < num_palette; i++) + png_ptr->quantize_index[i] = (png_byte)i; + } + + if (num_palette > maximum_colors) + { + if (histogram != NULL) + { + /* This is easy enough, just throw out the least used colors. + * Perhaps not the best solution, but good enough. + */ + + int i; + + /* Initialize an array to sort colors */ + png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * (sizeof (png_byte)))); + + /* Initialize the quantize_sort array */ + for (i = 0; i < num_palette; i++) + png_ptr->quantize_sort[i] = (png_byte)i; + + /* Find the least used palette entries by starting a + * bubble sort, and running it until we have sorted + * out enough colors. Note that we don't care about + * sorting all the colors, just finding which are + * least used. + */ + + for (i = num_palette - 1; i >= maximum_colors; i--) + { + int done; /* To stop early if the list is pre-sorted */ + int j; + + done = 1; + for (j = 0; j < i; j++) + { + if (histogram[png_ptr->quantize_sort[j]] + < histogram[png_ptr->quantize_sort[j + 1]]) + { + png_byte t; + + t = png_ptr->quantize_sort[j]; + png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1]; + png_ptr->quantize_sort[j + 1] = t; + done = 0; + } + } + + if (done) + break; + } + + /* Swap the palette around, and set up a table, if necessary */ + if (full_quantize) + { + int j = num_palette; + + /* Put all the useful colors within the max, but don't + * move the others. + */ + for (i = 0; i < maximum_colors; i++) + { + if ((int)png_ptr->quantize_sort[i] >= maximum_colors) + { + do + j--; + while ((int)png_ptr->quantize_sort[j] >= maximum_colors); + + palette[i] = palette[j]; + } + } + } + else + { + int j = num_palette; + + /* Move all the used colors inside the max limit, and + * develop a translation table. + */ + for (i = 0; i < maximum_colors; i++) + { + /* Only move the colors we need to */ + if ((int)png_ptr->quantize_sort[i] >= maximum_colors) + { + png_color tmp_color; + + do + j--; + while ((int)png_ptr->quantize_sort[j] >= maximum_colors); + + tmp_color = palette[j]; + palette[j] = palette[i]; + palette[i] = tmp_color; + /* Indicate where the color went */ + png_ptr->quantize_index[j] = (png_byte)i; + png_ptr->quantize_index[i] = (png_byte)j; + } + } + + /* Find closest color for those colors we are not using */ + for (i = 0; i < num_palette; i++) + { + if ((int)png_ptr->quantize_index[i] >= maximum_colors) + { + int min_d, k, min_k, d_index; + + /* Find the closest color to one we threw out */ + d_index = png_ptr->quantize_index[i]; + min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); + for (k = 1, min_k = 0; k < maximum_colors; k++) + { + int d; + + d = PNG_COLOR_DIST(palette[d_index], palette[k]); + + if (d < min_d) + { + min_d = d; + min_k = k; + } + } + /* Point to closest color */ + png_ptr->quantize_index[i] = (png_byte)min_k; + } + } + } + png_free(png_ptr, png_ptr->quantize_sort); + png_ptr->quantize_sort = NULL; + } + else + { + /* This is much harder to do simply (and quickly). Perhaps + * we need to go through a median cut routine, but those + * don't always behave themselves with only a few colors + * as input. So we will just find the closest two colors, + * and throw out one of them (chosen somewhat randomly). + * [We don't understand this at all, so if someone wants to + * work on improving it, be our guest - AED, GRP] + */ + int i; + int max_d; + int num_new_palette; + png_dsortp t; + png_dsortpp hash; + + t = NULL; + + /* Initialize palette index arrays */ + png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * (sizeof (png_byte)))); + png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * (sizeof (png_byte)))); + + /* Initialize the sort array */ + for (i = 0; i < num_palette; i++) + { + png_ptr->index_to_palette[i] = (png_byte)i; + png_ptr->palette_to_index[i] = (png_byte)i; + } + + hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 * + (sizeof (png_dsortp)))); + + num_new_palette = num_palette; + + /* Initial wild guess at how far apart the farthest pixel + * pair we will be eliminating will be. Larger + * numbers mean more areas will be allocated, Smaller + * numbers run the risk of not saving enough data, and + * having to do this all over again. + * + * I have not done extensive checking on this number. + */ + max_d = 96; + + while (num_new_palette > maximum_colors) + { + for (i = 0; i < num_new_palette - 1; i++) + { + int j; + + for (j = i + 1; j < num_new_palette; j++) + { + int d; + + d = PNG_COLOR_DIST(palette[i], palette[j]); + + if (d <= max_d) + { + + t = (png_dsortp)png_malloc_warn(png_ptr, + (png_uint_32)(sizeof (png_dsort))); + + if (t == NULL) + break; + + t->next = hash[d]; + t->left = (png_byte)i; + t->right = (png_byte)j; + hash[d] = t; + } + } + if (t == NULL) + break; + } + + if (t != NULL) + for (i = 0; i <= max_d; i++) + { + if (hash[i] != NULL) + { + png_dsortp p; + + for (p = hash[i]; p; p = p->next) + { + if ((int)png_ptr->index_to_palette[p->left] + < num_new_palette && + (int)png_ptr->index_to_palette[p->right] + < num_new_palette) + { + int j, next_j; + + if (num_new_palette & 0x01) + { + j = p->left; + next_j = p->right; + } + else + { + j = p->right; + next_j = p->left; + } + + num_new_palette--; + palette[png_ptr->index_to_palette[j]] + = palette[num_new_palette]; + if (!full_quantize) + { + int k; + + for (k = 0; k < num_palette; k++) + { + if (png_ptr->quantize_index[k] == + png_ptr->index_to_palette[j]) + png_ptr->quantize_index[k] = + png_ptr->index_to_palette[next_j]; + + if ((int)png_ptr->quantize_index[k] == + num_new_palette) + png_ptr->quantize_index[k] = + png_ptr->index_to_palette[j]; + } + } + + png_ptr->index_to_palette[png_ptr->palette_to_index + [num_new_palette]] = png_ptr->index_to_palette[j]; + + png_ptr->palette_to_index[png_ptr->index_to_palette[j]] + = png_ptr->palette_to_index[num_new_palette]; + + png_ptr->index_to_palette[j] = + (png_byte)num_new_palette; + + png_ptr->palette_to_index[num_new_palette] = + (png_byte)j; + } + if (num_new_palette <= maximum_colors) + break; + } + if (num_new_palette <= maximum_colors) + break; + } + } + + for (i = 0; i < 769; i++) + { + if (hash[i] != NULL) + { + png_dsortp p = hash[i]; + while (p) + { + t = p->next; + png_free(png_ptr, p); + p = t; + } + } + hash[i] = 0; + } + max_d += 96; + } + png_free(png_ptr, hash); + png_free(png_ptr, png_ptr->palette_to_index); + png_free(png_ptr, png_ptr->index_to_palette); + png_ptr->palette_to_index = NULL; + png_ptr->index_to_palette = NULL; + } + num_palette = maximum_colors; + } + if (png_ptr->palette == NULL) + { + png_ptr->palette = palette; + } + png_ptr->num_palette = (png_uint_16)num_palette; + + if (full_quantize) + { + int i; + png_bytep distance; + int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS + + PNG_QUANTIZE_BLUE_BITS; + int num_red = (1 << PNG_QUANTIZE_RED_BITS); + int num_green = (1 << PNG_QUANTIZE_GREEN_BITS); + int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS); + png_size_t num_entries = ((png_size_t)1 << total_bits); + + png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr, + (png_uint_32)(num_entries * (sizeof (png_byte)))); + + distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * + (sizeof (png_byte)))); + + memset(distance, 0xff, num_entries * (sizeof (png_byte))); + + for (i = 0; i < num_palette; i++) + { + int ir, ig, ib; + int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS)); + int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS)); + int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS)); + + for (ir = 0; ir < num_red; ir++) + { + /* int dr = abs(ir - r); */ + int dr = ((ir > r) ? ir - r : r - ir); + int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS + + PNG_QUANTIZE_GREEN_BITS)); + + for (ig = 0; ig < num_green; ig++) + { + /* int dg = abs(ig - g); */ + int dg = ((ig > g) ? ig - g : g - ig); + int dt = dr + dg; + int dm = ((dr > dg) ? dr : dg); + int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS); + + for (ib = 0; ib < num_blue; ib++) + { + int d_index = index_g | ib; + /* int db = abs(ib - b); */ + int db = ((ib > b) ? ib - b : b - ib); + int dmax = ((dm > db) ? dm : db); + int d = dmax + dt + db; + + if (d < (int)distance[d_index]) + { + distance[d_index] = (png_byte)d; + png_ptr->palette_lookup[d_index] = (png_byte)i; + } + } + } + } + } + + png_free(png_ptr, distance); + } +} +#endif /* PNG_READ_QUANTIZE_SUPPORTED */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +void PNGFAPI +png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma, + png_fixed_point file_gamma) +{ + png_debug(1, "in png_set_gamma_fixed"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + /* New in libpng-1.5.4 - reserve particular negative values as flags. */ + scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/); + file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/); + + /* Checking the gamma values for being >0 was added in 1.5.4 along with the + * premultiplied alpha support; this actually hides an undocumented feature + * of the previous implementation which allowed gamma processing to be + * disabled in background handling. There is no evidence (so far) that this + * was being used; however, png_set_background itself accepted and must still + * accept '0' for the gamma value it takes, because it isn't always used. + * + * Since this is an API change (albeit a very minor one that removes an + * undocumented API feature) the following checks were only enabled in + * libpng-1.6.0. + */ + if (file_gamma <= 0) + png_error(png_ptr, "invalid file gamma in png_set_gamma"); + + if (scrn_gamma <= 0) + png_error(png_ptr, "invalid screen gamma in png_set_gamma"); + + /* Set the gamma values unconditionally - this overrides the value in the PNG + * file if a gAMA chunk was present. png_set_alpha_mode provides a + * different, easier, way to default the file gamma. + */ + png_ptr->colorspace.gamma = file_gamma; + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + png_ptr->screen_gamma = scrn_gamma; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma) +{ + png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma), + convert_gamma_value(png_ptr, file_gamma)); +} +# endif /* FLOATING_POINT_SUPPORTED */ +#endif /* READ_GAMMA */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand paletted images to RGB, expand grayscale images of + * less than 8-bit depth to 8-bit depth, and expand tRNS chunks + * to alpha channels. + */ +void PNGAPI +png_set_expand(png_structrp png_ptr) +{ + png_debug(1, "in png_set_expand"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); +} + +/* GRR 19990627: the following three functions currently are identical + * to png_set_expand(). However, it is entirely reasonable that someone + * might wish to expand an indexed image to RGB but *not* expand a single, + * fully transparent palette entry to a full alpha channel--perhaps instead + * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace + * the transparent color with a particular RGB value, or drop tRNS entirely. + * IOW, a future version of the library may make the transformations flag + * a bit more fine-grained, with separate bits for each of these three + * functions. + * + * More to the point, these functions make it obvious what libpng will be + * doing, whereas "expand" can (and does) mean any number of things. + * + * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified + * to expand only the sample depth but not to expand the tRNS to alpha + * and its name was changed to png_set_expand_gray_1_2_4_to_8(). + */ + +/* Expand paletted images to RGB. */ +void PNGAPI +png_set_palette_to_rgb(png_structrp png_ptr) +{ + png_debug(1, "in png_set_palette_to_rgb"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); +} + +/* Expand grayscale images of less than 8-bit depth to 8 bits. */ +void PNGAPI +png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr) +{ + png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + png_ptr->transformations |= PNG_EXPAND; +} + +/* Expand tRNS chunks to alpha channels. */ +void PNGAPI +png_set_tRNS_to_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_tRNS_to_alpha"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); +} +#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise + * it may not work correctly.) + */ +void PNGAPI +png_set_expand_16(png_structrp png_ptr) +{ + png_debug(1, "in png_set_expand_16"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS); +} +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +void PNGAPI +png_set_gray_to_rgb(png_structrp png_ptr) +{ + png_debug(1, "in png_set_gray_to_rgb"); + + if (!png_rtran_ok(png_ptr, 0)) + return; + + /* Because rgb must be 8 bits or more: */ + png_set_expand_gray_1_2_4_to_8(png_ptr); + png_ptr->transformations |= PNG_GRAY_TO_RGB; +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +void PNGFAPI +png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, + png_fixed_point red, png_fixed_point green) +{ + png_debug(1, "in png_set_rgb_to_gray"); + + /* Need the IHDR here because of the check on color_type below. */ + /* TODO: fix this */ + if (!png_rtran_ok(png_ptr, 1)) + return; + + switch(error_action) + { + case PNG_ERROR_ACTION_NONE: + png_ptr->transformations |= PNG_RGB_TO_GRAY; + break; + + case PNG_ERROR_ACTION_WARN: + png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; + break; + + case PNG_ERROR_ACTION_ERROR: + png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; + break; + + default: + png_error(png_ptr, "invalid error action to rgb_to_gray"); + break; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#ifdef PNG_READ_EXPAND_SUPPORTED + png_ptr->transformations |= PNG_EXPAND; +#else + { + /* Make this an error in 1.6 because otherwise the application may assume + * that it just worked and get a memory overwrite. + */ + png_error(png_ptr, + "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED"); + + /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */ + } +#endif + { + if (red >= 0 && green >= 0 && red + green <= PNG_FP_1) + { + png_uint_16 red_int, green_int; + + /* NOTE: this calculation does not round, but this behavior is retained + * for consistency, the inaccuracy is very small. The code here always + * overwrites the coefficients, regardless of whether they have been + * defaulted or set already. + */ + red_int = (png_uint_16)(((png_uint_32)red*32768)/100000); + green_int = (png_uint_16)(((png_uint_32)green*32768)/100000); + + png_ptr->rgb_to_gray_red_coeff = red_int; + png_ptr->rgb_to_gray_green_coeff = green_int; + png_ptr->rgb_to_gray_coefficients_set = 1; + } + + else + { + if (red >= 0 && green >= 0) + png_app_warning(png_ptr, + "ignoring out of range rgb_to_gray coefficients"); + + /* Use the defaults, from the cHRM chunk if set, else the historical + * values which are close to the sRGB/HDTV/ITU-Rec 709 values. See + * png_do_rgb_to_gray for more discussion of the values. In this case + * the coefficients are not marked as 'set' and are not overwritten if + * something has already provided a default. + */ + if (png_ptr->rgb_to_gray_red_coeff == 0 && + png_ptr->rgb_to_gray_green_coeff == 0) + { + png_ptr->rgb_to_gray_red_coeff = 6968; + png_ptr->rgb_to_gray_green_coeff = 23434; + /* png_ptr->rgb_to_gray_blue_coeff = 2366; */ + } + } + } +} + +#ifdef PNG_FLOATING_POINT_SUPPORTED +/* Convert a RGB image to a grayscale of the same width. This allows us, + * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. + */ + +void PNGAPI +png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red, + double green) +{ + png_set_rgb_to_gray_fixed(png_ptr, error_action, + png_fixed(png_ptr, red, "rgb to gray red coefficient"), + png_fixed(png_ptr, green, "rgb to gray green coefficient")); +} +#endif /* FLOATING POINT */ + +#endif /* RGB_TO_GRAY */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +void PNGAPI +png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr + read_user_transform_fn) +{ + png_debug(1, "in png_set_read_user_transform_fn"); + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->read_user_transform_fn = read_user_transform_fn; +#endif +} +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +#ifdef PNG_READ_GAMMA_SUPPORTED +/* In the case of gamma transformations only do transformations on images where + * the [file] gamma and screen_gamma are not close reciprocals, otherwise it + * slows things down slightly, and also needlessly introduces small errors. + */ +static int /* PRIVATE */ +png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma) +{ + /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma + * correction as a difference of the overall transform from 1.0 + * + * We want to compare the threshold with s*f - 1, if we get + * overflow here it is because of wacky gamma values so we + * turn on processing anyway. + */ + png_fixed_point gtest; + return !png_muldiv(>est, screen_gamma, file_gamma, PNG_FP_1) || + png_gamma_significant(gtest); +} +#endif + +/* Initialize everything needed for the read. This includes modifying + * the palette. + */ + +/*For the moment 'png_init_palette_transformations' and + * 'png_init_rgb_transformations' only do some flag canceling optimizations. + * The intent is that these two routines should have palette or rgb operations + * extracted from 'png_init_read_transformations'. + */ +static void /* PRIVATE */ +png_init_palette_transformations(png_structrp png_ptr) +{ + /* Called to handle the (input) palette case. In png_do_read_transformations + * the first step is to expand the palette if requested, so this code must + * take care to only make changes that are invariant with respect to the + * palette expansion, or only do them if there is no expansion. + * + * STRIP_ALPHA has already been handled in the caller (by setting num_trans + * to 0.) + */ + int input_has_alpha = 0; + int input_has_transparency = 0; + + if (png_ptr->num_trans > 0) + { + int i; + + /* Ignore if all the entries are opaque (unlikely!) */ + for (i=0; inum_trans; ++i) + if (png_ptr->trans_alpha[i] == 255) + continue; + else if (png_ptr->trans_alpha[i] == 0) + input_has_transparency = 1; + else + input_has_alpha = 1; + } + + /* If no alpha we can optimize. */ + if (!input_has_alpha) + { + /* Any alpha means background and associative alpha processing is + * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA + * and ENCODE_ALPHA are irrelevant. + */ + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + if (!input_has_transparency) + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); + } + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* png_set_background handling - deals with the complexity of whether the + * background color is in the file format or the screen format in the case + * where an 'expand' will happen. + */ + + /* The following code cannot be entered in the alpha pre-multiplication case + * because PNG_BACKGROUND_EXPAND is cancelled below. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + (png_ptr->transformations & PNG_EXPAND)) + { + { + png_ptr->background.red = + png_ptr->palette[png_ptr->background.index].red; + png_ptr->background.green = + png_ptr->palette[png_ptr->background.index].green; + png_ptr->background.blue = + png_ptr->palette[png_ptr->background.index].blue; + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + { + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + { + /* Invert the alpha channel (in tRNS) unless the pixels are + * going to be expanded, in which case leave it for later + */ + int i, istop = png_ptr->num_trans; + + for (i=0; itrans_alpha[i] = (png_byte)(255 - + png_ptr->trans_alpha[i]); + } + } +#endif /* PNG_READ_INVERT_ALPHA_SUPPORTED */ + } + } /* background expand and (therefore) no alpha association. */ +#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ +} + +static void /* PRIVATE */ +png_init_rgb_transformations(png_structrp png_ptr) +{ + /* Added to libpng-1.5.4: check the color type to determine whether there + * is any alpha or transparency in the image and simply cancel the + * background and alpha mode stuff if there isn't. + */ + int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0; + int input_has_transparency = png_ptr->num_trans > 0; + + /* If no alpha we can optimize. */ + if (!input_has_alpha) + { + /* Any alpha means background and associative alpha processing is + * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA + * and ENCODE_ALPHA are irrelevant. + */ +# ifdef PNG_READ_ALPHA_MODE_SUPPORTED + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; +# endif + + if (!input_has_transparency) + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); + } + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* png_set_background handling - deals with the complexity of whether the + * background color is in the file format or the screen format in the case + * where an 'expand' will happen. + */ + + /* The following code cannot be entered in the alpha pre-multiplication case + * because PNG_BACKGROUND_EXPAND is cancelled below. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + (png_ptr->transformations & PNG_EXPAND) && + !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) + /* i.e., GRAY or GRAY_ALPHA */ + { + { + /* Expand background and tRNS chunks */ + int gray = png_ptr->background.gray; + int trans_gray = png_ptr->trans_color.gray; + + switch (png_ptr->bit_depth) + { + case 1: + gray *= 0xff; + trans_gray *= 0xff; + break; + + case 2: + gray *= 0x55; + trans_gray *= 0x55; + break; + + case 4: + gray *= 0x11; + trans_gray *= 0x11; + break; + + default: + + case 8: + /* FALL THROUGH (Already 8 bits) */ + + case 16: + /* Already a full 16 bits */ + break; + } + + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = (png_uint_16)gray; + + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + { + png_ptr->trans_color.red = png_ptr->trans_color.green = + png_ptr->trans_color.blue = (png_uint_16)trans_gray; + } + } + } /* background expand and (therefore) no alpha association. */ +#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ +} + +void /* PRIVATE */ +png_init_read_transformations(png_structrp png_ptr) +{ + png_debug(1, "in png_init_read_transformations"); + + /* This internal function is called from png_read_start_row in pngrutil.c + * and it is called before the 'rowbytes' calculation is done, so the code + * in here can change or update the transformations flags. + * + * First do updates that do not depend on the details of the PNG image data + * being processed. + */ + +#ifdef PNG_READ_GAMMA_SUPPORTED + /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds + * png_set_alpha_mode and this is another source for a default file gamma so + * the test needs to be performed later - here. In addition prior to 1.5.4 + * the tests were repeated for the PALETTE color type here - this is no + * longer necessary (and doesn't seem to have been necessary before.) + */ + { + /* The following temporary indicates if overall gamma correction is + * required. + */ + int gamma_correction = 0; + + if (png_ptr->colorspace.gamma != 0) /* has been set */ + { + if (png_ptr->screen_gamma != 0) /* screen set too */ + gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); + + else + /* Assume the output matches the input; a long time default behavior + * of libpng, although the standard has nothing to say about this. + */ + png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma); + } + + else if (png_ptr->screen_gamma != 0) + /* The converse - assume the file matches the screen, note that this + * perhaps undesireable default can (from 1.5.4) be changed by calling + * png_set_alpha_mode (even if the alpha handling mode isn't required + * or isn't changed from the default.) + */ + png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma); + + else /* neither are set */ + /* Just in case the following prevents any processing - file and screen + * are both assumed to be linear and there is no way to introduce a + * third gamma value other than png_set_background with 'UNIQUE', and, + * prior to 1.5.4 + */ + png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1; + + /* We have a gamma value now. */ + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + + /* Now turn the gamma transformation on or off as appropriate. Notice + * that PNG_GAMMA just refers to the file->screen correction. Alpha + * composition may independently cause gamma correction because it needs + * linear data (e.g. if the file has a gAMA chunk but the screen gamma + * hasn't been specified.) In any case this flag may get turned off in + * the code immediately below if the transform can be handled outside the + * row loop. + */ + if (gamma_correction) + png_ptr->transformations |= PNG_GAMMA; + + else + png_ptr->transformations &= ~PNG_GAMMA; + } +#endif + + /* Certain transformations have the effect of preventing other + * transformations that happen afterward in png_do_read_transformations, + * resolve the interdependencies here. From the code of + * png_do_read_transformations the order is: + * + * 1) PNG_EXPAND (including PNG_EXPAND_tRNS) + * 2) PNG_STRIP_ALPHA (if no compose) + * 3) PNG_RGB_TO_GRAY + * 4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY + * 5) PNG_COMPOSE + * 6) PNG_GAMMA + * 7) PNG_STRIP_ALPHA (if compose) + * 8) PNG_ENCODE_ALPHA + * 9) PNG_SCALE_16_TO_8 + * 10) PNG_16_TO_8 + * 11) PNG_QUANTIZE (converts to palette) + * 12) PNG_EXPAND_16 + * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY + * 14) PNG_INVERT_MONO + * 15) PNG_SHIFT + * 16) PNG_PACK + * 17) PNG_BGR + * 18) PNG_PACKSWAP + * 19) PNG_FILLER (includes PNG_ADD_ALPHA) + * 20) PNG_INVERT_ALPHA + * 21) PNG_SWAP_ALPHA + * 22) PNG_SWAP_BYTES + * 23) PNG_USER_TRANSFORM [must be last] + */ +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) && + !(png_ptr->transformations & PNG_COMPOSE)) + { + /* Stripping the alpha channel happens immediately after the 'expand' + * transformations, before all other transformation, so it cancels out + * the alpha handling. It has the side effect negating the effect of + * PNG_EXPAND_tRNS too: + */ + png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA | + PNG_EXPAND_tRNS); + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + /* Kill the tRNS chunk itself too. Prior to 1.5.4 this did not happen + * so transparency information would remain just so long as it wasn't + * expanded. This produces unexpected API changes if the set of things + * that do PNG_EXPAND_tRNS changes (perfectly possible given the + * documentation - which says ask for what you want, accept what you + * get.) This makes the behavior consistent from 1.5.4: + */ + png_ptr->num_trans = 0; + } +#endif /* STRIP_ALPHA supported, no COMPOSE */ + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA + * settings will have no effect. + */ + if (!png_gamma_significant(png_ptr->screen_gamma)) + { + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + } +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Make sure the coefficients for the rgb to gray conversion are set + * appropriately. + */ + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + png_colorspace_set_rgb_coefficients(png_ptr); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* Detect gray background and attempt to enable optimization for + * gray --> RGB case. + * + * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or + * RGB_ALPHA (in which case need_expand is superfluous anyway), the + * background color might actually be gray yet not be flagged as such. + * This is not a problem for the current code, which uses + * PNG_BACKGROUND_IS_GRAY only to decide when to do the + * png_do_gray_to_rgb() transformation. + * + * TODO: this code needs to be revised to avoid the complexity and + * interdependencies. The color type of the background should be recorded in + * png_set_background, along with the bit depth, then the code has a record + * of exactly what color space the background is currently in. + */ + if (png_ptr->transformations & PNG_BACKGROUND_EXPAND) + { + /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if + * the file was grayscale the background value is gray. + */ + if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + } + + else if (png_ptr->transformations & PNG_COMPOSE) + { + /* PNG_COMPOSE: png_set_background was called with need_expand false, + * so the color is in the color space of the output or png_set_alpha_mode + * was called and the color is black. Ignore RGB_TO_GRAY because that + * happens before GRAY_TO_RGB. + */ + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + { + if (png_ptr->background.red == png_ptr->background.green && + png_ptr->background.red == png_ptr->background.blue) + { + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + png_ptr->background.gray = png_ptr->background.red; + } + } + } +#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ +#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */ + + /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations + * can be performed directly on the palette, and some (such as rgb to gray) + * can be optimized inside the palette. This is particularly true of the + * composite (background and alpha) stuff, which can be pretty much all done + * in the palette even if the result is expanded to RGB or gray afterward. + * + * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and + * earlier and the palette stuff is actually handled on the first row. This + * leads to the reported bug that the palette returned by png_get_PLTE is not + * updated. + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_init_palette_transformations(png_ptr); + + else + png_init_rgb_transformations(png_ptr); + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_READ_EXPAND_16_SUPPORTED) + if ((png_ptr->transformations & PNG_EXPAND_16) && + (png_ptr->transformations & PNG_COMPOSE) && + !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + png_ptr->bit_depth != 16) + { + /* TODO: fix this. Because the expand_16 operation is after the compose + * handling the background color must be 8, not 16, bits deep, but the + * application will supply a 16-bit value so reduce it here. + * + * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at + * present, so that case is ok (until do_expand_16 is moved.) + * + * NOTE: this discards the low 16 bits of the user supplied background + * color, but until expand_16 works properly there is no choice! + */ +# define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x)) + CHOP(png_ptr->background.red); + CHOP(png_ptr->background.green); + CHOP(png_ptr->background.blue); + CHOP(png_ptr->background.gray); +# undef CHOP + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED && PNG_READ_EXPAND_16_SUPPORTED */ + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \ + defined(PNG_READ_STRIP_16_TO_8_SUPPORTED)) + if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) && + (png_ptr->transformations & PNG_COMPOSE) && + !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + png_ptr->bit_depth == 16) + { + /* On the other hand, if a 16-bit file is to be reduced to 8-bits per + * component this will also happen after PNG_COMPOSE and so the background + * color must be pre-expanded here. + * + * TODO: fix this too. + */ + png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257); + png_ptr->background.green = + (png_uint_16)(png_ptr->background.green * 257); + png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257); + png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257); + } +#endif + + /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the + * background support (see the comments in scripts/pnglibconf.dfa), this + * allows pre-multiplication of the alpha channel to be implemented as + * compositing on black. This is probably sub-optimal and has been done in + * 1.5.4 betas simply to enable external critique and testing (i.e. to + * implement the new API quickly, without lots of internal changes.) + */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +# ifdef PNG_READ_BACKGROUND_SUPPORTED + /* Includes ALPHA_MODE */ + png_ptr->background_1 = png_ptr->background; +# endif + + /* This needs to change - in the palette image case a whole set of tables are + * built when it would be quicker to just calculate the correct value for + * each palette entry directly. Also, the test is too tricky - why check + * PNG_RGB_TO_GRAY if PNG_GAMMA is not set? The answer seems to be that + * PNG_GAMMA is cancelled even if the gamma is known? The test excludes the + * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction + * the gamma tables will not be built even if composition is required on a + * gamma encoded value. + * + * In 1.5.4 this is addressed below by an additional check on the individual + * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the + * tables. + */ + if ((png_ptr->transformations & PNG_GAMMA) + || ((png_ptr->transformations & PNG_RGB_TO_GRAY) + && (png_gamma_significant(png_ptr->colorspace.gamma) || + png_gamma_significant(png_ptr->screen_gamma))) + || ((png_ptr->transformations & PNG_COMPOSE) + && (png_gamma_significant(png_ptr->colorspace.gamma) + || png_gamma_significant(png_ptr->screen_gamma) +# ifdef PNG_READ_BACKGROUND_SUPPORTED + || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE + && png_gamma_significant(png_ptr->background_gamma)) +# endif + )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) + && png_gamma_significant(png_ptr->screen_gamma)) + ) + { + png_build_gamma_table(png_ptr, png_ptr->bit_depth); + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if (png_ptr->transformations & PNG_COMPOSE) + { + /* Issue a warning about this combination: because RGB_TO_GRAY is + * optimized to do the gamma transform if present yet do_background has + * to do the same thing if both options are set a + * double-gamma-correction happens. This is true in all versions of + * libpng to date. + */ + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + png_warning(png_ptr, + "libpng does not support gamma+background+rgb_to_gray"); + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + /* We don't get to here unless there is a tRNS chunk with non-opaque + * entries - see the checking code at the start of this function. + */ + png_color back, back_1; + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) + { + + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; + + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; + } + else + { + png_fixed_point g, gs; + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = (png_ptr->screen_gamma); + gs = PNG_FP_1; + break; + + case PNG_BACKGROUND_GAMMA_FILE: + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); + break; + + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = png_reciprocal(png_ptr->background_gamma); + gs = png_reciprocal2(png_ptr->background_gamma, + png_ptr->screen_gamma); + break; + default: + g = PNG_FP_1; /* back_1 */ + gs = PNG_FP_1; /* back */ + break; + } + + if (png_gamma_significant(gs)) + { + back.red = png_gamma_8bit_correct(png_ptr->background.red, + gs); + back.green = png_gamma_8bit_correct(png_ptr->background.green, + gs); + back.blue = png_gamma_8bit_correct(png_ptr->background.blue, + gs); + } + + else + { + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + } + + if (png_gamma_significant(g)) + { + back_1.red = png_gamma_8bit_correct(png_ptr->background.red, + g); + back_1.green = png_gamma_8bit_correct( + png_ptr->background.green, g); + back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue, + g); + } + + else + { + back_1.red = (png_byte)png_ptr->background.red; + back_1.green = (png_byte)png_ptr->background.green; + back_1.blue = (png_byte)png_ptr->background.blue; + } + } + + for (i = 0; i < num_palette; i++) + { + if (i < (int)png_ptr->num_trans && + png_ptr->trans_alpha[i] != 0xff) + { + if (png_ptr->trans_alpha[i] == 0) + { + palette[i] = back; + } + else /* if (png_ptr->trans_alpha[i] != 0xff) */ + { + png_byte v, w; + + v = png_ptr->gamma_to_1[palette[i].red]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.red); + palette[i].red = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].green]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.green); + palette[i].green = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].blue]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue); + palette[i].blue = png_ptr->gamma_from_1[w]; + } + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + + /* Prevent the transformations being done again. + * + * NOTE: this is highly dubious; it removes the transformations in + * place. This seems inconsistent with the general treatment of the + * transformations elsewhere. + */ + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA); + } /* color_type == PNG_COLOR_TYPE_PALETTE */ + + /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ + else /* color_type != PNG_COLOR_TYPE_PALETTE */ + { + int gs_sig, g_sig; + png_fixed_point g = PNG_FP_1; /* Correction to linear */ + png_fixed_point gs = PNG_FP_1; /* Correction to screen */ + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = png_ptr->screen_gamma; + /* gs = PNG_FP_1; */ + break; + + case PNG_BACKGROUND_GAMMA_FILE: + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); + break; + + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = png_reciprocal(png_ptr->background_gamma); + gs = png_reciprocal2(png_ptr->background_gamma, + png_ptr->screen_gamma); + break; + + default: + png_error(png_ptr, "invalid background gamma type"); + } + + g_sig = png_gamma_significant(g); + gs_sig = png_gamma_significant(gs); + + if (g_sig) + png_ptr->background_1.gray = png_gamma_correct(png_ptr, + png_ptr->background.gray, g); + + if (gs_sig) + png_ptr->background.gray = png_gamma_correct(png_ptr, + png_ptr->background.gray, gs); + + if ((png_ptr->background.red != png_ptr->background.green) || + (png_ptr->background.red != png_ptr->background.blue) || + (png_ptr->background.red != png_ptr->background.gray)) + { + /* RGB or RGBA with color background */ + if (g_sig) + { + png_ptr->background_1.red = png_gamma_correct(png_ptr, + png_ptr->background.red, g); + + png_ptr->background_1.green = png_gamma_correct(png_ptr, + png_ptr->background.green, g); + + png_ptr->background_1.blue = png_gamma_correct(png_ptr, + png_ptr->background.blue, g); + } + + if (gs_sig) + { + png_ptr->background.red = png_gamma_correct(png_ptr, + png_ptr->background.red, gs); + + png_ptr->background.green = png_gamma_correct(png_ptr, + png_ptr->background.green, gs); + + png_ptr->background.blue = png_gamma_correct(png_ptr, + png_ptr->background.blue, gs); + } + } + + else + { + /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */ + png_ptr->background_1.red = png_ptr->background_1.green + = png_ptr->background_1.blue = png_ptr->background_1.gray; + + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + } + + /* The background is now in screen gamma: */ + png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN; + } /* color_type != PNG_COLOR_TYPE_PALETTE */ + }/* png_ptr->transformations & PNG_BACKGROUND */ + + else + /* Transformation does not include PNG_BACKGROUND */ +#endif /* PNG_READ_BACKGROUND_SUPPORTED */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* RGB_TO_GRAY needs to have non-gamma-corrected values! */ + && ((png_ptr->transformations & PNG_EXPAND) == 0 || + (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) +#endif + ) + { + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + + /* NOTE: there are other transformations that should probably be in + * here too. + */ + for (i = 0; i < num_palette; i++) + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + + /* Done the gamma correction. */ + png_ptr->transformations &= ~PNG_GAMMA; + } /* color_type == PALETTE && !PNG_BACKGROUND transformation */ + } +#ifdef PNG_READ_BACKGROUND_SUPPORTED + else +#endif +#endif /* PNG_READ_GAMMA_SUPPORTED */ + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + /* No GAMMA transformation (see the hanging else 4 lines above) */ + if ((png_ptr->transformations & PNG_COMPOSE) && + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) + { + int i; + int istop = (int)png_ptr->num_trans; + png_color back; + png_colorp palette = png_ptr->palette; + + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + + for (i = 0; i < istop; i++) + { + if (png_ptr->trans_alpha[i] == 0) + { + palette[i] = back; + } + + else if (png_ptr->trans_alpha[i] != 0xff) + { + /* The png_composite() macro is defined in png.h */ + png_composite(palette[i].red, palette[i].red, + png_ptr->trans_alpha[i], back.red); + + png_composite(palette[i].green, palette[i].green, + png_ptr->trans_alpha[i], back.green); + + png_composite(palette[i].blue, palette[i].blue, + png_ptr->trans_alpha[i], back.blue); + } + } + + png_ptr->transformations &= ~PNG_COMPOSE; + + //png_ptr->flags |= PNG_FLAG_STRIP_ALPHA; /* Add by Sunliang.Liu */ + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED */ + +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) && + !(png_ptr->transformations & PNG_EXPAND) && + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) + { + int i; + int istop = png_ptr->num_palette; + int shift = 8 - png_ptr->sig_bit.red; + + png_ptr->transformations &= ~PNG_SHIFT; + + /* significant bits can be in the range 1 to 7 for a meaninful result, if + * the number of significant bits is 0 then no shift is done (this is an + * error condition which is silently ignored.) + */ + if (shift > 0 && shift < 8) for (i=0; ipalette[i].red; + + component >>= shift; + png_ptr->palette[i].red = (png_byte)component; + } + + shift = 8 - png_ptr->sig_bit.green; + if (shift > 0 && shift < 8) for (i=0; ipalette[i].green; + + component >>= shift; + png_ptr->palette[i].green = (png_byte)component; + } + + shift = 8 - png_ptr->sig_bit.blue; + if (shift > 0 && shift < 8) for (i=0; ipalette[i].blue; + + component >>= shift; + png_ptr->palette[i].blue = (png_byte)component; + } + } +#endif /* PNG_READ_SHIFT_SUPPORTED */ +} + +/* Modify the info structure to reflect the transformations. The + * info should be updated so a PNG file could be written with it, + * assuming the transformations result in valid PNG data. + */ +void /* PRIVATE */ +png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) +{ + png_debug(1, "in png_read_transform_info"); + +#ifdef PNG_READ_EXPAND_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + /* This check must match what actually happens in + * png_do_expand_palette; if it ever checks the tRNS chunk to see if + * it is all opaque we must do the same (at present it does not.) + */ + if (png_ptr->num_trans > 0) + info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + + else + info_ptr->color_type = PNG_COLOR_TYPE_RGB; + + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + } + else + { + if (png_ptr->num_trans) + { + if (png_ptr->transformations & PNG_EXPAND_tRNS) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + } + if (info_ptr->bit_depth < 8) + info_ptr->bit_depth = 8; + + info_ptr->num_trans = 0; + } + } +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* The following is almost certainly wrong unless the background value is in + * the screen space! + */ + if (png_ptr->transformations & PNG_COMPOSE) + info_ptr->background = png_ptr->background; +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4), + * however it seems that the code in png_init_read_transformations, which has + * been called before this from png_read_update_info->png_read_start_row + * sometimes does the gamma transform and cancels the flag. + * + * TODO: this looks wrong; the info_ptr should end up with a gamma equal to + * the screen_gamma value. The following probably results in weirdness if + * the info_ptr is used by the app after the rows have been read. + */ + info_ptr->colorspace.gamma = png_ptr->colorspace.gamma; +#endif + + if (info_ptr->bit_depth == 16) + { +# ifdef PNG_READ_16BIT_SUPPORTED +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if (png_ptr->transformations & PNG_SCALE_16_TO_8) + info_ptr->bit_depth = 8; +# endif + +# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + if (png_ptr->transformations & PNG_16_TO_8) + info_ptr->bit_depth = 8; +# endif + +# else + /* No 16 bit support: force chopping 16-bit input down to 8, in this case + * the app program can chose if both APIs are available by setting the + * correct scaling to use. + */ +# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* For compatibility with previous versions use the strip method by + * default. This code works because if PNG_SCALE_16_TO_8 is already + * set the code below will do that in preference to the chop. + */ + png_ptr->transformations |= PNG_16_TO_8; + info_ptr->bit_depth = 8; +# else + +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_ptr->transformations |= PNG_SCALE_16_TO_8; + info_ptr->bit_depth = 8; +# else + + CONFIGURATION ERROR: you must enable at least one 16 to 8 method +# endif +# endif +#endif /* !READ_16BIT_SUPPORTED */ + } + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + info_ptr->color_type = (png_byte)(info_ptr->color_type | + PNG_COLOR_MASK_COLOR); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + info_ptr->color_type = (png_byte)(info_ptr->color_type & + ~PNG_COLOR_MASK_COLOR); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if (png_ptr->transformations & PNG_QUANTIZE) + { + if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && + png_ptr->palette_lookup && info_ptr->bit_depth == 8) + { + info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; + } + } +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 && + info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + info_ptr->bit_depth = 16; + } +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) + info_ptr->bit_depth = 8; +#endif + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_ptr->channels = 3; + + else + info_ptr->channels = 1; + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_STRIP_ALPHA) + { + info_ptr->color_type = (png_byte)(info_ptr->color_type & + ~PNG_COLOR_MASK_ALPHA); + info_ptr->num_trans = 0; + } +#endif + + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + info_ptr->channels++; + +#ifdef PNG_READ_FILLER_SUPPORTED + /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ + if ((png_ptr->transformations & PNG_FILLER) && + ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) + { + info_ptr->channels++; + /* If adding a true alpha channel not just filler */ + if (png_ptr->transformations & PNG_ADD_ALPHA) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + } +#endif + +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ +defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + if (info_ptr->bit_depth < png_ptr->user_transform_depth) + info_ptr->bit_depth = png_ptr->user_transform_depth; + + if (info_ptr->channels < png_ptr->user_transform_channels) + info_ptr->channels = png_ptr->user_transform_channels; + } +#endif + + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * + info_ptr->bit_depth); + + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width); + + /* Adding in 1.5.4: cache the above value in png_struct so that we can later + * check in png_rowbytes that the user buffer won't get overwritten. Note + * that the field is not always set - if png_read_update_info isn't called + * the application has to either not do any transforms or get the calculation + * right itself. + */ + png_ptr->info_rowbytes = info_ptr->rowbytes; + +#ifndef PNG_READ_EXPAND_SUPPORTED + if (png_ptr) + return; +#endif +} + +/* Transform the row. The order of transformations is significant, + * and is very touchy. If you add a transformation, take care to + * decide how it fits in with the other transformations here. + */ +void /* PRIVATE */ +png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) +{ + png_debug(1, "in png_do_read_transformations"); + + if (png_ptr->row_buf == NULL) + { + /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this + * error is incredibly rare and incredibly easy to debug without this + * information. + */ + png_error(png_ptr, "NULL row buffer"); + } + + /* The following is debugging; prior to 1.5.4 the code was never compiled in; + * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro + * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for + * all transformations, however in practice the ROW_INIT always gets done on + * demand, if necessary. + */ + if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && + !(png_ptr->flags & PNG_FLAG_ROW_INIT)) + { + /* Application has failed to call either png_read_start_image() or + * png_read_update_info() after setting transforms that expand pixels. + * This check added to libpng-1.2.19 (but not enabled until 1.5.4). + */ + png_error(png_ptr, "Uninitialized row"); + } + +#ifdef PNG_READ_EXPAND_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND) + { + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_do_expand_palette(row_info, png_ptr->row_buf + 1, + png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); + } + + else + { + if (png_ptr->num_trans && + (png_ptr->transformations & PNG_EXPAND_tRNS)) + png_do_expand(row_info, png_ptr->row_buf + 1, + &(png_ptr->trans_color)); + + else + png_do_expand(row_info, png_ptr->row_buf + 1, + NULL); + } + } +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) && + !(png_ptr->transformations & PNG_COMPOSE) && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + { + int rgb_error = + png_do_rgb_to_gray(png_ptr, row_info, + png_ptr->row_buf + 1); + + if (rgb_error) + { + png_ptr->rgb_to_gray_status=1; + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_WARN) + png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_ERR) + png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + } + } +#endif + +/* From Andreas Dilger e-mail to png-implement, 26 March 1998: + * + * In most cases, the "simple transparency" should be done prior to doing + * gray-to-RGB, or you will have to test 3x as many bytes to check if a + * pixel is transparent. You would also need to make sure that the + * transparency information is upgraded to RGB. + * + * To summarize, the current flow is: + * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite + * with background "in place" if transparent, + * convert to RGB if necessary + * - Gray + alpha -> composite with gray background and remove alpha bytes, + * convert to RGB if necessary + * + * To support RGB backgrounds for gray images we need: + * - Gray + simple transparency -> convert to RGB + simple transparency, + * compare 3 or 6 bytes and composite with + * background "in place" if transparent + * (3x compare/pixel compared to doing + * composite with gray bkgrnd) + * - Gray + alpha -> convert to RGB + alpha, composite with background and + * remove alpha bytes (3x float + * operations/pixel compared with composite + * on gray background) + * + * Greg's change will do this. The reason it wasn't done before is for + * performance, as this increases the per-pixel operations. If we would check + * in advance if the background was gray or RGB, and position the gray-to-RGB + * transform appropriately, then it would save a lot of work/time. + */ + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* If gray -> RGB, do so now only if background is non-gray; else do later + * for performance reasons + */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + if (png_ptr->transformations & PNG_COMPOSE) + png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + if ((png_ptr->transformations & PNG_GAMMA) && +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Because RGB_TO_GRAY does the gamma transform. */ + !(png_ptr->transformations & PNG_RGB_TO_GRAY) && +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* Because PNG_COMPOSE does the gamma transform if there is something to + * do (if there is an alpha channel or transparency.) + */ + !((png_ptr->transformations & PNG_COMPOSE) && + ((png_ptr->num_trans != 0) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && +#endif + /* Because png_init_read_transformations transforms the palette, unless + * RGB_TO_GRAY will do the transform. + */ + (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) + png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) && + (png_ptr->transformations & PNG_COMPOSE) && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + if ((png_ptr->transformations & PNG_ENCODE_ALPHA) && + (row_info->color_type & PNG_COLOR_MASK_ALPHA)) + png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if (png_ptr->transformations & PNG_SCALE_16_TO_8) + png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* There is no harm in doing both of these because only one has any effect, + * by putting the 'scale' option first if the app asks for scale (either by + * calling the API or in a TRANSFORM flag) this is what happens. + */ + if (png_ptr->transformations & PNG_16_TO_8) + png_do_chop(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if (png_ptr->transformations & PNG_QUANTIZE) + { + png_do_quantize(row_info, png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->quantize_index); + + if (row_info->rowbytes == 0) + png_error(png_ptr, "png_do_quantize returned rowbytes=0"); + } +#endif /* PNG_READ_QUANTIZE_SUPPORTED */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + /* Do the expansion now, after all the arithmetic has been done. Notice + * that previous transformations can handle the PNG_EXPAND_16 flag if this + * is efficient (particularly true in the case of gamma correction, where + * better accuracy results faster!) + */ + if (png_ptr->transformations & PNG_EXPAND_16) + png_do_expand_16(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* NOTE: moved here in 1.5.4 (from much later in this list.) */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + if (png_ptr->transformations & PNG_SHIFT) + png_do_unshift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if (png_ptr->transformations & PNG_PACK) + png_do_unpack(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Added at libpng-1.5.10 */ + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, row_info); +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if (png_ptr->transformations & PNG_FILLER) + png_do_read_filler(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->filler, png_ptr->flags); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_16BIT_SUPPORTED +#ifdef PNG_READ_SWAP_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(row_info, png_ptr->row_buf + 1); +#endif +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + if (png_ptr->read_user_transform_fn != NULL) + (*(png_ptr->read_user_transform_fn)) /* User read transform function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + if (png_ptr->user_transform_depth) + row_info->bit_depth = png_ptr->user_transform_depth; + + if (png_ptr->user_transform_channels) + row_info->channels = png_ptr->user_transform_channels; +#endif + row_info->pixel_depth = (png_byte)(row_info->bit_depth * + row_info->channels); + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); + } +#endif +} + +#ifdef PNG_READ_PACK_SUPPORTED +/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, + * without changing the actual values. Thus, if you had a row with + * a bit depth of 1, you would end up with bytes that only contained + * the numbers 0 or 1. If you would rather they contain 0 and 255, use + * png_do_shift() after this. + */ +void /* PRIVATE */ +png_do_unpack(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_unpack"); + + if (row_info->bit_depth < 8) + { + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + switch (row_info->bit_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x01); + + if (shift == 7) + { + shift = 0; + sp--; + } + + else + shift++; + + dp--; + } + break; + } + + case 2: + { + + png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x03); + + if (shift == 6) + { + shift = 0; + sp--; + } + + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x0f); + + if (shift == 4) + { + shift = 0; + sp--; + } + + else + shift = 4; + + dp--; + } + break; + } + + default: + break; + } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED +/* Reverse the effects of png_do_shift. This routine merely shifts the + * pixels back to their significant bits values. Thus, if you have + * a row of bit depth 8, but only 5 are significant, this will shift + * the values back to 0 through 31. + */ +void /* PRIVATE */ +png_do_unshift(png_row_infop row_info, png_bytep row, + png_const_color_8p sig_bits) +{ + int color_type; + + png_debug(1, "in png_do_unshift"); + + /* The palette case has already been handled in the _init routine. */ + color_type = row_info->color_type; + + if (color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift[4]; + int channels = 0; + int bit_depth = row_info->bit_depth; + + if (color_type & PNG_COLOR_MASK_COLOR) + { + shift[channels++] = bit_depth - sig_bits->red; + shift[channels++] = bit_depth - sig_bits->green; + shift[channels++] = bit_depth - sig_bits->blue; + } + + else + { + shift[channels++] = bit_depth - sig_bits->gray; + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + { + shift[channels++] = bit_depth - sig_bits->alpha; + } + + { + int c, have_shift; + + for (c = have_shift = 0; c < channels; ++c) + { + /* A shift of more than the bit depth is an error condition but it + * gets ignored here. + */ + if (shift[c] <= 0 || shift[c] >= bit_depth) + shift[c] = 0; + + else + have_shift = 1; + } + + if (!have_shift) + return; + } + + switch (bit_depth) + { + default: + /* Must be 1bpp gray: should not be here! */ + /* NOTREACHED */ + break; + + case 2: + /* Must be 2bpp gray */ + /* assert(channels == 1 && shift[0] == 1) */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + + while (bp < bp_end) + { + int b = (*bp >> 1) & 0x55; + *bp++ = (png_byte)b; + } + break; + } + + case 4: + /* Must be 4bpp gray */ + /* assert(channels == 1) */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + int gray_shift = shift[0]; + int mask = 0xf >> gray_shift; + + mask |= mask << 4; + + while (bp < bp_end) + { + int b = (*bp >> gray_shift) & mask; + *bp++ = (png_byte)b; + } + break; + } + + case 8: + /* Single byte components, G, GA, RGB, RGBA */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + int channel = 0; + + while (bp < bp_end) + { + int b = *bp >> shift[channel]; + if (++channel >= channels) + channel = 0; + *bp++ = (png_byte)b; + } + break; + } + +#ifdef PNG_READ_16BIT_SUPPORTED + case 16: + /* Double byte components, G, GA, RGB, RGBA */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + int channel = 0; + + while (bp < bp_end) + { + int value = (bp[0] << 8) + bp[1]; + + value >>= shift[channel]; + if (++channel >= channels) + channel = 0; + *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)(value & 0xff); + } + break; + } +#endif + } + } +} +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale rows of bit depth 16 down to 8 accurately */ +void /* PRIVATE */ +png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_scale_16_to_8"); + + if (row_info->bit_depth == 16) + { + png_bytep sp = row; /* source */ + png_bytep dp = row; /* destination */ + png_bytep ep = sp + row_info->rowbytes; /* end+1 */ + + while (sp < ep) + { + /* The input is an array of 16 bit components, these must be scaled to + * 8 bits each. For a 16 bit value V the required value (from the PNG + * specification) is: + * + * (V * 255) / 65535 + * + * This reduces to round(V / 257), or floor((V + 128.5)/257) + * + * Represent V as the two byte value vhi.vlo. Make a guess that the + * result is the top byte of V, vhi, then the correction to this value + * is: + * + * error = floor(((V-vhi.vhi) + 128.5) / 257) + * = floor(((vlo-vhi) + 128.5) / 257) + * + * This can be approximated using integer arithmetic (and a signed + * shift): + * + * error = (vlo-vhi+128) >> 8; + * + * The approximate differs from the exact answer only when (vlo-vhi) is + * 128; it then gives a correction of +1 when the exact correction is + * 0. This gives 128 errors. The exact answer (correct for all 16 bit + * input values) is: + * + * error = (vlo-vhi+128)*65535 >> 24; + * + * An alternative arithmetic calculation which also gives no errors is: + * + * (V * 255 + 32895) >> 16 + */ + + png_int_32 tmp = *sp++; /* must be signed! */ + tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24; + *dp++ = (png_byte)tmp; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_info->width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +void /* PRIVATE */ +/* Simply discard the low byte. This was the default behavior prior + * to libpng-1.5.4. + */ +png_do_chop(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_chop"); + + if (row_info->bit_depth == 16) + { + png_bytep sp = row; /* source */ + png_bytep dp = row; /* destination */ + png_bytep ep = sp + row_info->rowbytes; /* end+1 */ + + while (sp < ep) + { + *dp++ = *sp; + sp += 2; /* skip low byte */ + } + + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_info->width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_swap_alpha"); + + { + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This converts from RGBA to ARGB */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + /* This converts from RRGGBBAA to AARRGGBB */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } +#endif + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from GA to AG */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + /* This converts from GGAA to AAGG */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } +#endif + } + } +} +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_uint_32 row_width; + png_debug(1, "in png_do_read_invert_alpha"); + + row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in RGBA */ + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=3; + dp=sp; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + /* This inverts the alpha channel in RRGGBBAA */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=6; + dp=sp; + } + } +#endif + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in GA */ + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = *(--sp); + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + else + { + /* This inverts the alpha channel in GGAA */ + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); +/* + *(--dp) = *(--sp); + *(--dp) = *(--sp); +*/ + sp-=2; + dp=sp; + } + } +#endif + } +} +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED +/* Add filler channel if we have RGB color */ +void /* PRIVATE */ +png_do_read_filler(png_row_infop row_info, png_bytep row, + png_uint_32 filler, png_uint_32 flags) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + +#ifdef PNG_READ_16BIT_SUPPORTED + png_byte hi_filler = (png_byte)((filler>>8) & 0xff); +#endif + png_byte lo_filler = (png_byte)(filler & 0xff); + + png_debug(1, "in png_do_read_filler"); + + if ( + row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This changes the data from G to GX */ + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + + else + { + /* This changes the data from G to XG */ + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This changes the data from GG to GGXX */ + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = hi_filler; + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = hi_filler; + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + + else + { + /* This changes the data from GG to XXGG */ + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = hi_filler; + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } +#endif + } /* COLOR_TYPE == GRAY */ + else if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + if (row_info->bit_depth == 8) + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This changes the data from RGB to RGBX */ + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + + else + { + /* This changes the data from RGB to XRGB */ + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This changes the data from RRGGBB to RRGGBBXX */ + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = hi_filler; + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = hi_filler; + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + + else + { + /* This changes the data from RRGGBB to XXRRGGBB */ + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = hi_filler; + *(--dp) = lo_filler; + } + + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + } +#endif + } /* COLOR_TYPE == RGB */ +} +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand grayscale files to RGB, with or without alpha */ +void /* PRIVATE */ +png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_gray_to_rgb"); + + if (row_info->bit_depth >= 8 && + !(row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + /* This changes G to RGB */ + png_bytep sp = row + (png_size_t)row_width - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + + else + { + /* This changes GG to RRGGBB */ + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This changes GA to RGBA */ + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + + else + { + /* This changes GGAA to RRGGBBAA */ + png_bytep sp = row + (png_size_t)row_width * 4 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + row_info->channels = (png_byte)(row_info->channels + 2); + row_info->color_type |= PNG_COLOR_MASK_COLOR; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB files to grayscale, with or without alpha + * using the equation given in Poynton's ColorFAQ of 1998-01-04 at + * (THIS LINK IS DEAD June 2008 but + * versions dated 1998 through November 2002 have been archived at + * http://web.archive.org/web/20000816232553/http://www.inforamp.net/ + * ~poynton/notes/colour_and_gamma/ColorFAQ.txt ) + * Charles Poynton poynton at poynton.com + * + * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + * + * which can be expressed with integers as + * + * Y = (6969 * R + 23434 * G + 2365 * B)/32768 + * + * Poynton's current link (as of January 2003 through July 2011): + * + * has changed the numbers slightly: + * + * Y = 0.2126*R + 0.7152*G + 0.0722*B + * + * which can be expressed with integers as + * + * Y = (6966 * R + 23436 * G + 2366 * B)/32768 + * + * Historically, however, libpng uses numbers derived from the ITU-R Rec 709 + * end point chromaticities and the D65 white point. Depending on the + * precision used for the D65 white point this produces a variety of different + * numbers, however if the four decimal place value used in ITU-R Rec 709 is + * used (0.3127,0.3290) the Y calculation would be: + * + * Y = (6968 * R + 23435 * G + 2366 * B)/32768 + * + * While this is correct the rounding results in an overflow for white, because + * the sum of the rounded coefficients is 32769, not 32768. Consequently + * libpng uses, instead, the closest non-overflowing approximation: + * + * Y = (6968 * R + 23434 * G + 2366 * B)/32768 + * + * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk + * (including an sRGB chunk) then the chromaticities are used to calculate the + * coefficients. See the chunk handling in pngrutil.c for more information. + * + * In all cases the calculation is to be done in a linear colorspace. If no + * gamma information is available to correct the encoding of the original RGB + * values this results in an implicit assumption that the original PNG RGB + * values were linear. + * + * Other integer coefficents can be used via png_set_rgb_to_gray(). Because + * the API takes just red and green coefficients the blue coefficient is + * calculated to make the sum 32768. This will result in different rounding + * to that used above. + */ +int /* PRIVATE */ +png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) + +{ + int rgb_error = 0; + + png_debug(1, "in png_do_rgb_to_gray"); + + if (!(row_info->color_type & PNG_COLOR_MASK_PALETTE) && + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; + PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; + PNG_CONST png_uint_32 bc = 32768 - rc - gc; + PNG_CONST png_uint_32 row_width = row_info->width; + PNG_CONST int have_alpha = + (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0; + + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + /* Notice that gamma to/from 1 are not necessarily inverses (if + * there is an overall gamma correction). Prior to 1.5.5 this code + * checked the linearized values for equality; this doesn't match + * the documentation, the original values must be checked. + */ + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + + if (red != green || red != blue) + { + red = png_ptr->gamma_to_1[red]; + green = png_ptr->gamma_to_1[green]; + blue = png_ptr->gamma_to_1[blue]; + + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1[ + (rc*red + gc*green + bc*blue + 16384)>>15]; + } + + else + { + /* If there is no overall correction the table will not be + * set. + */ + if (png_ptr->gamma_table != NULL) + red = png_ptr->gamma_table[red]; + + *(dp++) = red; + } + + if (have_alpha) + *(dp++) = *(sp++); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + + if (red != green || red != blue) + { + rgb_error |= 1; + /* NOTE: this is the historical approach which simply + * truncates the results. + */ + *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); + } + + else + *(dp++) = red; + + if (have_alpha) + *(dp++) = *(sp++); + } + } + } + + else /* RGB bit_depth == 16 */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + + red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + + if (red == green && red == blue) + { + if (png_ptr->gamma_16_table != NULL) + w = png_ptr->gamma_16_table[(red&0xff) + >> png_ptr->gamma_shift][red>>8]; + + else + w = red; + } + + else + { + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) + >> png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = + png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) + >> png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + + bc*blue_1 + 16384)>>15); + w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + + if (have_alpha) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + } + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, gray16; + + red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + + if (red != green || red != blue) + rgb_error |= 1; + + /* From 1.5.5 in the 16 bit case do the accurate conversion even + * in the 'fast' case - this is because this is where the code + * ends up when handling linear 16 bit data. + */ + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >> + 15); + *(dp++) = (png_byte)((gray16>>8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + + if (have_alpha) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + } + } + } + } + + row_info->channels = (png_byte)(row_info->channels - 2); + row_info->color_type = (png_byte)(row_info->color_type & + ~PNG_COLOR_MASK_COLOR); + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + return rgb_error; +} +#endif +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth + * large of png_color. This lets grayscale images be treated as + * paletted. Most useful for gamma correction and simplification + * of code. This API is not used internally. + */ +void PNGAPI +png_build_grayscale_palette(int bit_depth, png_colorp palette) +{ + int num_palette; + int color_inc; + int i; + int v; + + png_debug(1, "in png_do_build_grayscale_palette"); + + if (palette == NULL) + return; + + switch (bit_depth) + { + case 1: + num_palette = 2; + color_inc = 0xff; + break; + + case 2: + num_palette = 4; + color_inc = 0x55; + break; + + case 4: + num_palette = 16; + color_inc = 0x11; + break; + + case 8: + num_palette = 256; + color_inc = 1; + break; + + default: + num_palette = 0; + color_inc = 0; + break; + } + + for (i = 0, v = 0; i < num_palette; i++, v += color_inc) + { + palette[i].red = (png_byte)v; + palette[i].green = (png_byte)v; + palette[i].blue = (png_byte)v; + } +} +#endif + + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) +/* Replace any alpha or transparency with the supplied background color. + * "background" is already in the screen gamma, while "background_1" is + * at a gamma of 1.0. Paletted files have already been taken care of. + */ +void /* PRIVATE */ +png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) +{ +#ifdef PNG_READ_GAMMA_SUPPORTED + png_const_bytep gamma_table = png_ptr->gamma_table; + png_const_bytep gamma_from_1 = png_ptr->gamma_from_1; + png_const_bytep gamma_to_1 = png_ptr->gamma_to_1; + png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table; + png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1; + png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1; + int gamma_shift = png_ptr->gamma_shift; + int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; +#endif + + png_bytep sp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + int shift; + + png_debug(1, "in png_do_compose"); + + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_GRAY: + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row; + shift = 7; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x01) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x7f7f >> (7 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (!shift) + { + shift = 7; + sp++; + } + + else + shift--; + } + break; + } + + case 2: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + else + { + unsigned int p = (*sp >> shift) & 0x03; + unsigned int g = (gamma_table [p | (p << 2) | + (p << 4) | (p << 6)] >> 6) & 0x03; + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (!shift) + { + shift = 6; + sp++; + } + + else + shift -= 2; + } + } + + else +#endif + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (!shift) + { + shift = 6; + sp++; + } + + else + shift -= 2; + } + } + break; + } + + case 4: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + else + { + unsigned int p = (*sp >> shift) & 0x0f; + unsigned int g = (gamma_table[p | (p << 4)] >> 4) & + 0x0f; + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (!shift) + { + shift = 4; + sp++; + } + + else + shift -= 4; + } + } + + else +#endif + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (!shift) + { + shift = 4; + sp++; + } + + else + shift -= 4; + } + } + break; + } + + case 8: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; + + else + *sp = gamma_table[*sp]; + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; + } + } + break; + } + + case 16: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + if (v == png_ptr->trans_color.gray) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); + } + + else + { + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + if (v == png_ptr->trans_color.gray) + { + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); + } + } + } + break; + } + + default: + break; + } + break; + } + + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + + else + { + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + if (r == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.blue) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + + else + { + png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + if (r == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.blue) + { + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + } + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 a = *(sp + 1); + + if (a == 0xff) + *sp = gamma_table[*sp]; + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)png_ptr->background.gray; + } + + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, png_ptr->background_1.gray); + if (!optimize) + w = gamma_from_1[w]; + *sp = w; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_byte a = *(sp + 1); + + if (a == 0) + *sp = (png_byte)png_ptr->background.gray; + + else if (a < 0xff) + png_composite(*sp, *sp, a, png_ptr->background.gray); + } + } + } + else /* if (png_ptr->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + } + + else + { + png_uint_16 g, v, w; + + g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(v, g, a, png_ptr->background_1.gray); + if (optimize) + w = v; + else + w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + if (a == 0) + { + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + } + + else if (a < 0xffff) + { + png_uint_16 g, v; + + g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_composite_16(v, g, a, png_ptr->background.gray); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, png_ptr->background_1.red); + if (!optimize) w = gamma_from_1[w]; + *sp = w; + + v = gamma_to_1[*(sp + 1)]; + png_composite(w, v, a, png_ptr->background_1.green); + if (!optimize) w = gamma_from_1[w]; + *(sp + 1) = w; + + v = gamma_to_1[*(sp + 2)]; + png_composite(w, v, a, png_ptr->background_1.blue); + if (!optimize) w = gamma_from_1[w]; + *(sp + 2) = w; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_byte a = *(sp + 3); + + if (a == 0) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + + else if (a < 0xff) + { + png_composite(*sp, *sp, a, png_ptr->background.red); + + png_composite(*(sp + 1), *(sp + 1), a, + png_ptr->background.green); + + png_composite(*(sp + 2), *(sp + 2), a, + png_ptr->background.blue); + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 8) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + + else + { + png_uint_16 v, w; + + v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(w, v, a, png_ptr->background_1.red); + if (!optimize) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); + + v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; + png_composite_16(w, v, a, png_ptr->background_1.green); + if (!optimize) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + 8]; + + *(sp + 2) = (png_byte)((w >> 8) & 0xff); + *(sp + 3) = (png_byte)(w & 0xff); + + v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; + png_composite_16(w, v, a, png_ptr->background_1.blue); + if (!optimize) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + 8]; + + *(sp + 4) = (png_byte)((w >> 8) & 0xff); + *(sp + 5) = (png_byte)(w & 0xff); + } + } + } + + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 8) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + + if (a == 0) + { + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + + else if (a < 0xffff) + { + png_uint_16 v; + + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + png_composite_16(v, r, a, png_ptr->background.red); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + png_composite_16(v, g, a, png_ptr->background.green); + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + png_composite_16(v, b, a, png_ptr->background.blue); + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + + default: + break; + } + } +} +#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_READ_ALPHA_MODE_SUPPORTED */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Gamma correct the image, avoiding the alpha channel. Make sure + * you do this after you deal with the transparency issue on grayscale + * or RGB images. If your bit depth is 8, use gamma_table, if it + * is 16, use gamma_16_table and gamma_shift. Build these with + * build_gamma_table(). + */ +void /* PRIVATE */ +png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr) +{ + png_const_bytep gamma_table = png_ptr->gamma_table; + png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table; + int gamma_shift = png_ptr->gamma_shift; + + png_bytep sp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_gamma"); + + if (((row_info->bit_depth <= 8 && gamma_table != NULL) || + (row_info->bit_depth == 16 && gamma_16_table != NULL))) + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + } + } + + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + + *sp = gamma_table[*sp]; + sp++; + + *sp = gamma_table[*sp]; + sp++; + + sp++; + } + } + + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp += 2; + } + } + + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY: + { + if (row_info->bit_depth == 2) + { + sp = row; + for (i = 0; i < row_width; i += 4) + { + int a = *sp & 0xc0; + int b = *sp & 0x30; + int c = *sp & 0x0c; + int d = *sp & 0x03; + + *sp = (png_byte)( + ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)| + ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)| + ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)| + ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) )); + sp++; + } + } + + if (row_info->bit_depth == 4) + { + sp = row; + for (i = 0; i < row_width; i += 2) + { + int msb = *sp & 0xf0; + int lsb = *sp & 0x0f; + + *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0) + | (((int)gamma_table[(lsb << 4) | lsb]) >> 4)); + sp++; + } + } + + else if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + } + } + + else if (row_info->bit_depth == 16) + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + + default: + break; + } + } +} +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* Encode the alpha channel to the output gamma (the input channel is always + * linear.) Called only with color types that have an alpha channel. Needs the + * from_1 tables. + */ +void /* PRIVATE */ +png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) +{ + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_encode_alpha"); + + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + if (row_info->bit_depth == 8) + { + PNG_CONST png_bytep table = png_ptr->gamma_from_1; + + if (table != NULL) + { + PNG_CONST int step = + (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2; + + /* The alpha channel is the last component: */ + row += step - 1; + + for (; row_width > 0; --row_width, row += step) + *row = table[*row]; + + return; + } + } + + else if (row_info->bit_depth == 16) + { + PNG_CONST png_uint_16pp table = png_ptr->gamma_16_from_1; + PNG_CONST int gamma_shift = png_ptr->gamma_shift; + + if (table != NULL) + { + PNG_CONST int step = + (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4; + + /* The alpha channel is the last component: */ + row += step - 2; + + for (; row_width > 0; --row_width, row += step) + { + png_uint_16 v; + + v = table[*(row + 1) >> gamma_shift][*row]; + *row = (png_byte)((v >> 8) & 0xff); + *(row + 1) = (png_byte)(v & 0xff); + } + + return; + } + } + } + + /* Only get to here if called with a weird row_info; no harm has been done, + * so just issue a warning. + */ + png_warning(png_ptr, "png_do_encode_alpha: unexpected call"); +} +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expands a palette row to an RGB or RGBA row depending + * upon whether you supply trans and num_trans. + */ +void /* PRIVATE */ +png_do_expand_palette(png_row_infop row_info, png_bytep row, + png_const_colorp palette, png_const_bytep trans_alpha, int num_trans) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand_palette"); + + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 1; + + else + *dp = 0; + + if (shift == 7) + { + shift = 0; + sp--; + } + + else + shift++; + + dp--; + } + break; + } + + case 2: + { + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)value; + if (shift == 6) + { + shift = 0; + sp--; + } + + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((row_width & 0x01) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)value; + if (shift == 4) + { + shift = 0; + sp--; + } + + else + shift += 4; + + dp--; + } + break; + } + + default: + break; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + + if (row_info->bit_depth == 8) + { + { + if (num_trans > 0) + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + + for (i = 0; i < row_width; i++) + { + if ((int)(*sp) >= num_trans) + *dp-- = 0xff; + + else + *dp-- = trans_alpha[*sp]; + + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + row_info->color_type = 6; + row_info->channels = 4; + } + + else + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width * 3) - 1; + + for (i = 0; i < row_width; i++) + { + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = 24; + row_info->rowbytes = row_width * 3; + row_info->color_type = 2; + row_info->channels = 3; + } + } + } + } +} + +/* If the bit depth < 8, it is expanded to 8. Also, if the already + * expanded transparency value is supplied, an alpha channel is built. + */ +void /* PRIVATE */ +png_do_expand(png_row_infop row_info, png_bytep row, + png_const_color_16p trans_color) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + unsigned int gray = trans_color ? trans_color->gray : 0; + + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + gray = (gray & 0x01) * 0xff; + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 0xff; + + else + *dp = 0; + + if (shift == 7) + { + shift = 0; + sp--; + } + + else + shift++; + + dp--; + } + break; + } + + case 2: + { + gray = (gray & 0x03) * 0x55; + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)(value | (value << 2) | (value << 4) | + (value << 6)); + if (shift == 6) + { + shift = 0; + sp--; + } + + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + gray = (gray & 0x0f) * 0x11; + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)(value | (value << 4)); + if (shift == 4) + { + shift = 0; + sp--; + } + + else + shift = 4; + + dp--; + } + break; + } + + default: + break; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + + if (trans_color != NULL) + { + if (row_info->bit_depth == 8) + { + gray = gray & 0xff; + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 1) - 1; + + for (i = 0; i < row_width; i++) + { + if (*sp == gray) + *dp-- = 0; + + else + *dp-- = 0xff; + + *dp-- = *sp--; + } + } + + else if (row_info->bit_depth == 16) + { + unsigned int gray_high = (gray >> 8) & 0xff; + unsigned int gray_low = gray & 0xff; + sp = row + row_info->rowbytes - 1; + dp = row + (row_info->rowbytes << 1) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 1) == gray_high && *(sp) == gray_low) + { + *dp-- = 0; + *dp-- = 0; + } + + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + + *dp-- = *sp--; + *dp-- = *sp--; + } + } + + row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + row_info->channels = 2; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_width); + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_color) + { + if (row_info->bit_depth == 8) + { + png_byte red = (png_byte)(trans_color->red & 0xff); + png_byte green = (png_byte)(trans_color->green & 0xff); + png_byte blue = (png_byte)(trans_color->blue & 0xff); + sp = row + (png_size_t)row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue) + *dp-- = 0; + + else + *dp-- = 0xff; + + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + else if (row_info->bit_depth == 16) + { + png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff); + png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff); + png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff); + png_byte red_low = (png_byte)(trans_color->red & 0xff); + png_byte green_low = (png_byte)(trans_color->green & 0xff); + png_byte blue_low = (png_byte)(trans_color->blue & 0xff); + sp = row + row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 3) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 5) == red_high && + *(sp - 4) == red_low && + *(sp - 3) == green_high && + *(sp - 2) == green_low && + *(sp - 1) == blue_high && + *(sp ) == blue_low) + { + *dp-- = 0; + *dp-- = 0; + } + + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + row_info->channels = 4; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + } +} +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* If the bit depth is 8 and the color type is not a palette type expand the + * whole row to 16 bits. Has no effect otherwise. + */ +void /* PRIVATE */ +png_do_expand_16(png_row_infop row_info, png_bytep row) +{ + if (row_info->bit_depth == 8 && + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + /* The row have a sequence of bytes containing [0..255] and we need + * to turn it into another row containing [0..65535], to do this we + * calculate: + * + * (input / 255) * 65535 + * + * Which happens to be exactly input * 257 and this can be achieved + * simply by byte replication in place (copying backwards). + */ + png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */ + png_byte *dp = sp + row_info->rowbytes; /* destination, end + 1 */ + while (dp > sp) + dp[-2] = dp[-1] = *--sp, dp -= 2; + + row_info->rowbytes *= 2; + row_info->bit_depth = 16; + row_info->pixel_depth = (png_byte)(row_info->channels * 16); + } +} +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +void /* PRIVATE */ +png_do_quantize(png_row_infop row_info, png_bytep row, + png_const_bytep palette_lookup, png_const_bytep quantize_lookup) +{ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_quantize"); + + if (row_info->bit_depth == 8) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + + /* This looks real messy, but the compiler will reduce + * it down to a reasonable formula. For example, with + * 5 bits per color, we get: + * p = (((r >> 3) & 0x1f) << 10) | + * (((g >> 3) & 0x1f) << 5) | + * ((b >> 3) & 0x1f); + */ + p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & + ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << + (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | + (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & + ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << + (PNG_QUANTIZE_BLUE_BITS)) | + ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & + ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + palette_lookup != NULL) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + sp++; + + p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & + ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << + (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | + (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & + ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << + (PNG_QUANTIZE_BLUE_BITS)) | + ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & + ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + + else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + quantize_lookup) + { + sp = row; + + for (i = 0; i < row_width; i++, sp++) + { + *sp = quantize_lookup[*sp]; + } + } + } +} +#endif /* PNG_READ_QUANTIZE_SUPPORTED */ +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing */ +void /* PRIVATE */ +png_do_read_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_intrapixel"); + + if ( + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff); + *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (s0 + s1 + 65536) & 0xffff; + png_uint_32 blue = (s2 + s1 + 65536) & 0xffff; + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp + 1) = (png_byte)(red & 0xff); + *(rp + 4) = (png_byte)((blue >> 8) & 0xff); + *(rp + 5) = (png_byte)(blue & 0xff); + } + } + } +} +#endif /* PNG_MNG_FEATURES_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED */ +#endif diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrutil.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrutil.c new file mode 100644 index 0000000000..d12395a18d --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngrutil.c @@ -0,0 +1,4473 @@ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +/* pngrutil.c - utilities to read a PNG file + * + * Last changed in libpng 1.6.3 [July 18, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains routines that are only called from within + * libpng itself during the course of reading an image. + */ + +#include "pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +png_uint_32 PNGAPI +png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf) +{ + png_uint_32 uval = png_get_uint_32(buf); + + if (uval > PNG_UINT_31_MAX) + png_error(png_ptr, "PNG unsigned integer out of range"); + + return (uval); +} + +#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED) +/* The following is a variation on the above for use with the fixed + * point values used for gAMA and cHRM. Instead of png_error it + * issues a warning and returns (-1) - an invalid value because both + * gAMA and cHRM use *unsigned* integers for fixed point values. + */ +#define PNG_FIXED_ERROR (-1) + +static png_fixed_point /* PRIVATE */ +png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf) +{ + png_uint_32 uval = png_get_uint_32(buf); + + if (uval <= PNG_UINT_31_MAX) + return (png_fixed_point)uval; /* known to be in range */ + + /* The caller can turn off the warning by passing NULL. */ + if (png_ptr != NULL) + png_warning(png_ptr, "PNG fixed point integer out of range"); + + return PNG_FIXED_ERROR; +} +#endif + +#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED +/* NOTE: the read macros will obscure these definitions, so that if + * PNG_USE_READ_MACROS is set the library will not use them internally, + * but the APIs will still be available externally. + * + * The parentheses around "PNGAPI function_name" in the following three + * functions are necessary because they allow the macros to co-exist with + * these (unused but exported) functions. + */ + +/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ +png_uint_32 (PNGAPI +png_get_uint_32)(png_const_bytep buf) +{ + png_uint_32 uval = + ((png_uint_32)(*(buf )) << 24) + + ((png_uint_32)(*(buf + 1)) << 16) + + ((png_uint_32)(*(buf + 2)) << 8) + + ((png_uint_32)(*(buf + 3)) ) ; + + return uval; +} + +/* Grab a signed 32-bit integer from a buffer in big-endian format. The + * data is stored in the PNG file in two's complement format and there + * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore + * the following code does a two's complement to native conversion. + */ +png_int_32 (PNGAPI +png_get_int_32)(png_const_bytep buf) +{ + png_uint_32 uval = png_get_uint_32(buf); + if ((uval & 0x80000000) == 0) /* non-negative */ + return uval; + + uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ + return -(png_int_32)uval; +} + +/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ +png_uint_16 (PNGAPI +png_get_uint_16)(png_const_bytep buf) +{ + /* ANSI-C requires an int value to accomodate at least 16 bits so this + * works and allows the compiler not to worry about possible narrowing + * on 32 bit systems. (Pre-ANSI systems did not make integers smaller + * than 16 bits either.) + */ + unsigned int val = + ((unsigned int)(*buf) << 8) + + ((unsigned int)(*(buf + 1))); + + return (png_uint_16)val; +} + +#endif /* PNG_READ_INT_FUNCTIONS_SUPPORTED */ + +/* Read and check the PNG file signature */ +void /* PRIVATE */ +png_read_sig(png_structrp png_ptr, png_inforp info_ptr) +{ + png_size_t num_checked, num_to_check; + + /* Exit if the user application does not expect a signature. */ + if (png_ptr->sig_bytes >= 8) + return; + + num_checked = png_ptr->sig_bytes; + num_to_check = 8 - num_checked; + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE; +#endif + + /* The signature must be serialized in a single I/O call. */ + png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); + png_ptr->sig_bytes = 8; + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + if (num_checked < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; +} + +/* Read the chunk header (length + type name). + * Put the type name into png_ptr->chunk_name, and return the length. + */ +png_uint_32 /* PRIVATE */ +png_read_chunk_header(png_structrp png_ptr) +{ + png_byte buf[8]; + png_uint_32 length; + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR; +#endif + + /* Read the length and the chunk name. + * This must be performed in a single I/O call. + */ + png_read_data(png_ptr, buf, 8); + length = png_get_uint_31(png_ptr, buf); + + /* Put the chunk name into png_ptr->chunk_name. */ + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4); + + png_debug2(0, "Reading %lx chunk, length = %lu", + (unsigned long)png_ptr->chunk_name, (unsigned long)length); + + /* Reset the crc and run it over the chunk name. */ + png_reset_crc(png_ptr); + png_calculate_crc(png_ptr, buf + 4, 4); + + /* Check to see if chunk name is valid. */ + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA; +#endif + + return length; +} + +/* Read data, and (optionally) run it through the CRC. */ +void /* PRIVATE */ +png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length) +{ + if (png_ptr == NULL) + return; + + png_read_data(png_ptr, buf, length); + png_calculate_crc(png_ptr, buf, length); +} + +/* Optionally skip data and then check the CRC. Depending on whether we + * are reading an ancillary or critical chunk, and how the program has set + * things up, we may calculate the CRC on the data and print a message. + * Returns '1' if there was a CRC error, '0' otherwise. + */ +int /* PRIVATE */ +png_crc_finish(png_structrp png_ptr, png_uint_32 skip) +{ + /* The size of the local buffer for inflate is a good guess as to a + * reasonable size to use for buffering reads from the application. + */ + while (skip > 0) + { + png_uint_32 len; + png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; + + len = (sizeof tmpbuf); + if (len > skip) + len = skip; + skip -= len; + + png_crc_read(png_ptr, tmpbuf, len); + } + + if (png_crc_error(png_ptr)) + { + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) ? + !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) : + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)) + { + png_chunk_warning(png_ptr, "CRC error"); + } + + else + { + png_chunk_benign_error(png_ptr, "CRC error"); + return (0); + } + + return (1); + } + + return (0); +} + +/* Compare the CRC stored in the PNG file with that calculated by libpng from + * the data it has read thus far. + */ +int /* PRIVATE */ +png_crc_error(png_structrp png_ptr) +{ + png_byte crc_bytes[4]; + png_uint_32 crc; + int need_crc = 1; + + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)) + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; +#endif + + /* The chunk CRC must be serialized in a single I/O call. */ + png_read_data(png_ptr, crc_bytes, 4); + + if (need_crc) + { + crc = png_get_uint_32(crc_bytes); + return ((int)(crc != png_ptr->crc)); + } + + else + return (0); +} + +/* Manage the read buffer; this simply reallocates the buffer if it is not small + * enough (or if it is not allocated). The routine returns a pointer to the + * buffer; if an error occurs and 'warn' is set the routine returns NULL, else + * it will call png_error (via png_malloc) on failure. (warn == 2 means + * 'silent'). + */ +static png_bytep +png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn) +{ + png_bytep buffer = png_ptr->read_buffer; + + if (buffer != NULL && new_size > png_ptr->read_buffer_size) + { + png_ptr->read_buffer = NULL; + png_ptr->read_buffer = NULL; + png_ptr->read_buffer_size = 0; + png_free(png_ptr, buffer); + buffer = NULL; + } + + if (buffer == NULL) + { + buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size)); + + if (buffer != NULL) + { + png_ptr->read_buffer = buffer; + png_ptr->read_buffer_size = new_size; + } + + else if (warn < 2) /* else silent */ + { +#ifdef PNG_WARNINGS_SUPPORTED + if (warn) + png_chunk_warning(png_ptr, "insufficient memory to read chunk"); + else +#endif + { +#ifdef PNG_ERROR_TEXT_SUPPORTED + png_chunk_error(png_ptr, "insufficient memory to read chunk"); +#endif + } + } + } + + return buffer; +} + +/* png_inflate_claim: claim the zstream for some nefarious purpose that involves + * decompression. Returns Z_OK on success, else a zlib error code. It checks + * the owner but, in final release builds, just issues a warning if some other + * chunk apparently owns the stream. Prior to release it does a png_error. + */ +static int +png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) +{ + if (png_ptr->zowner != 0) + { + char msg[64]; + + PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. + */ + (void)png_safecat(msg, (sizeof msg), 4, " using zstream"); +# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_chunk_warning(png_ptr, msg); + png_ptr->zowner = 0; +# else + png_chunk_error(png_ptr, msg); +# endif + } + + /* Implementation note: unlike 'png_deflate_claim' this internal function + * does not take the size of the data as an argument. Some efficiency could + * be gained by using this when it is known *if* the zlib stream itself does + * not record the number; however, this is an illusion: the original writer + * of the PNG may have selected a lower window size, and we really must + * follow that because, for systems with with limited capabilities, we + * would otherwise reject the application's attempts to use a smaller window + * size (zlib doesn't have an interface to say "this or lower"!). + * + * inflateReset2 was added to zlib 1.2.4; before this the window could not be + * reset, therefore it is necessary to always allocate the maximum window + * size with earlier zlibs just in case later compressed chunks need it. + */ + { + int ret; /* zlib return code */ +# if PNG_ZLIB_VERNUM >= 0x1240 + +# if defined(PNG_SET_OPTION_SUPPORTED) && \ + defined(PNG_MAXIMUM_INFLATE_WINDOW) + int window_bits; + + if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == + PNG_OPTION_ON) + window_bits = 15; + + else + window_bits = 0; +# else +# define window_bits 0 +# endif +# endif + + /* Set this for safety, just in case the previous owner left pointers to + * memory allocations. + */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; + + if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) + { +# if PNG_ZLIB_VERNUM < 0x1240 + ret = inflateReset(&png_ptr->zstream); +# else + ret = inflateReset2(&png_ptr->zstream, window_bits); +# endif + } + + else + { +# if PNG_ZLIB_VERNUM < 0x1240 + ret = inflateInit(&png_ptr->zstream); +# else + ret = inflateInit2(&png_ptr->zstream, window_bits); +# endif + + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; + } + + if (ret == Z_OK) + png_ptr->zowner = owner; + + else + png_zstream_error(png_ptr, ret); + + return ret; + } + +# ifdef window_bits +# undef window_bits +# endif +} + +#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED +/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to + * allow the caller to do multiple calls if required. If the 'finish' flag is + * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must + * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and + * Z_OK or Z_STREAM_END will be returned on success. + * + * The input and output sizes are updated to the actual amounts of data consumed + * or written, not the amount available (as in a z_stream). The data pointers + * are not changed, so the next input is (data+input_size) and the next + * available output is (output+output_size). + */ +static int +png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish, + /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr, + /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr) +{ + if (png_ptr->zowner == owner) /* Else not claimed */ + { + int ret; + png_alloc_size_t avail_out = *output_size_ptr; + png_uint_32 avail_in = *input_size_ptr; + + /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it + * can't even necessarily handle 65536 bytes) because the type uInt is + * "16 bits or more". Consequently it is necessary to chunk the input to + * zlib. This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the + * maximum value that can be stored in a uInt.) It is possible to set + * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have + * a performance advantage, because it reduces the amount of data accessed + * at each step and that may give the OS more time to page it in. + */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + /* avail_in and avail_out are set below from 'size' */ + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.avail_out = 0; + + /* Read directly into the output if it is available (this is set to + * a local buffer below if output is NULL). + */ + if (output != NULL) + png_ptr->zstream.next_out = output; + + do + { + uInt avail; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + + /* zlib INPUT BUFFER */ + /* The setting of 'avail_in' used to be outside the loop; by setting it + * inside it is possible to chunk the input to zlib and simply rely on + * zlib to advance the 'next_in' pointer. This allows arbitrary + * amounts of data to be passed through zlib at the unavoidable cost of + * requiring a window save (memcpy of up to 32768 output bytes) + * every ZLIB_IO_MAX input bytes. + */ + avail_in += png_ptr->zstream.avail_in; /* not consumed last time */ + + avail = ZLIB_IO_MAX; + + if (avail_in < avail) + avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */ + + avail_in -= avail; + png_ptr->zstream.avail_in = avail; + + /* zlib OUTPUT BUFFER */ + avail_out += png_ptr->zstream.avail_out; /* not written last time */ + + avail = ZLIB_IO_MAX; /* maximum zlib can process */ + + if (output == NULL) + { + /* Reset the output buffer each time round if output is NULL and + * make available the full buffer, up to 'remaining_space' + */ + png_ptr->zstream.next_out = local_buffer; + if ((sizeof local_buffer) < avail) + avail = (sizeof local_buffer); + } + + if (avail_out < avail) + avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */ + + png_ptr->zstream.avail_out = avail; + avail_out -= avail; + + /* zlib inflate call */ + /* In fact 'avail_out' may be 0 at this point, that happens at the end + * of the read when the final LZ end code was not passed at the end of + * the previous chunk of input data. Tell zlib if we have reached the + * end of the output buffer. + */ + ret = inflate(&png_ptr->zstream, avail_out > 0 ? Z_NO_FLUSH : + (finish ? Z_FINISH : Z_SYNC_FLUSH)); + } while (ret == Z_OK); + + /* For safety kill the local buffer pointer now */ + if (output == NULL) + png_ptr->zstream.next_out = NULL; + + /* Claw back the 'size' and 'remaining_space' byte counts. */ + avail_in += png_ptr->zstream.avail_in; + avail_out += png_ptr->zstream.avail_out; + + /* Update the input and output sizes; the updated values are the amount + * consumed or written, effectively the inverse of what zlib uses. + */ + if (avail_out > 0) + *output_size_ptr -= avail_out; + + if (avail_in > 0) + *input_size_ptr -= avail_in; + + /* Ensure png_ptr->zstream.msg is set (even in the success case!) */ + png_zstream_error(png_ptr, ret); + return ret; + } + + else + { + /* This is a bad internal error. The recovery assigns to the zstream msg + * pointer, which is not owned by the caller, but this is safe; it's only + * used on errors! + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; + } +} + +/* + * Decompress trailing data in a chunk. The assumption is that read_buffer + * points at an allocated area holding the contents of a chunk with a + * trailing compressed part. What we get back is an allocated area + * holding the original prefix part and an uncompressed version of the + * trailing part (the malloc area passed in is freed). + */ +static int +png_decompress_chunk(png_structrp png_ptr, + png_uint_32 chunklength, png_uint_32 prefix_size, + png_alloc_size_t *newlength /* must be initialized to the maximum! */, + int terminate /*add a '\0' to the end of the uncompressed data*/) +{ + /* TODO: implement different limits for different types of chunk. + * + * The caller supplies *newlength set to the maximum length of the + * uncompressed data, but this routine allocates space for the prefix and + * maybe a '\0' terminator too. We have to assume that 'prefix_size' is + * limited only by the maximum chunk size. + */ + png_alloc_size_t limit = PNG_SIZE_MAX; + +# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif + + if (limit >= prefix_size + (terminate != 0)) + { + int ret; + + limit -= prefix_size + (terminate != 0); + + if (limit < *newlength) + *newlength = limit; + + /* Now try to claim the stream. */ + ret = png_inflate_claim(png_ptr, png_ptr->chunk_name); + + if (ret == Z_OK) + { + png_uint_32 lzsize = chunklength - prefix_size; + + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + /* input: */ png_ptr->read_buffer + prefix_size, &lzsize, + /* output: */ NULL, newlength); + + if (ret == Z_STREAM_END) + { + /* Use 'inflateReset' here, not 'inflateReset2' because this + * preserves the previously decided window size (otherwise it would + * be necessary to store the previous window size.) In practice + * this doesn't matter anyway, because png_inflate will call inflate + * with Z_FINISH in almost all cases, so the window will not be + * maintained. + */ + if (inflateReset(&png_ptr->zstream) == Z_OK) + { + /* Because of the limit checks above we know that the new, + * expanded, size will fit in a size_t (let alone an + * png_alloc_size_t). Use png_malloc_base here to avoid an + * extra OOM message. + */ + png_alloc_size_t new_size = *newlength; + png_alloc_size_t buffer_size = prefix_size + new_size + + (terminate != 0); + png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr, + buffer_size)); + + if (text != NULL) + { + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + png_ptr->read_buffer + prefix_size, &lzsize, + text + prefix_size, newlength); + + if (ret == Z_STREAM_END) + { + if (new_size == *newlength) + { + if (terminate) + text[prefix_size + *newlength] = 0; + + if (prefix_size > 0) + memcpy(text, png_ptr->read_buffer, prefix_size); + + { + png_bytep old_ptr = png_ptr->read_buffer; + + png_ptr->read_buffer = text; + png_ptr->read_buffer_size = buffer_size; + text = old_ptr; /* freed below */ + } + } + + else + { + /* The size changed on the second read, there can be no + * guarantee that anything is correct at this point. + * The 'msg' pointer has been set to "unexpected end of + * LZ stream", which is fine, but return an error code + * that the caller won't accept. + */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } + } + + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */ + + /* Free the text pointer (this is the old read_buffer on + * success) + */ + png_free(png_ptr, text); + + /* This really is very benign, but it's still an error because + * the extra space may otherwise be used as a Trojan Horse. + */ + if (ret == Z_STREAM_END && + chunklength - prefix_size != lzsize) + png_chunk_benign_error(png_ptr, "extra compressed data"); + } + + else + { + /* Out of memory allocating the buffer */ + ret = Z_MEM_ERROR; + png_zstream_error(png_ptr, Z_MEM_ERROR); + } + } + + else + { + /* inflateReset failed, store the error message */ + png_zstream_error(png_ptr, ret); + + if (ret == Z_STREAM_END) + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } + } + + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + /* Release the claimed stream */ + png_ptr->zowner = 0; + } + + else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + return ret; + } + + else + { + /* Application/configuration limits exceeded */ + png_zstream_error(png_ptr, Z_MEM_ERROR); + return Z_MEM_ERROR; + } +} +#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */ + +#ifdef PNG_READ_iCCP_SUPPORTED +/* Perform a partial read and decompress, producing 'avail_out' bytes and + * reading from the current chunk as required. + */ +static int +png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, + png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size, + int finish) +{ + if (png_ptr->zowner == png_ptr->chunk_name) + { + int ret; + + /* next_in and avail_in must have been initialized by the caller. */ + png_ptr->zstream.next_out = next_out; + png_ptr->zstream.avail_out = 0; /* set in the loop */ + + do + { + if (png_ptr->zstream.avail_in == 0) + { + if (read_size > *chunk_bytes) + read_size = (uInt)*chunk_bytes; + *chunk_bytes -= read_size; + + if (read_size > 0) + png_crc_read(png_ptr, read_buffer, read_size); + + png_ptr->zstream.next_in = read_buffer; + png_ptr->zstream.avail_in = read_size; + } + + if (png_ptr->zstream.avail_out == 0) + { + uInt avail = ZLIB_IO_MAX; + if (avail > *out_size) + avail = (uInt)*out_size; + *out_size -= avail; + + png_ptr->zstream.avail_out = avail; + } + + /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all + * the available output is produced; this allows reading of truncated + * streams. + */ + ret = inflate(&png_ptr->zstream, + *chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); + } + while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0)); + + *out_size += png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */ + + /* Ensure the error message pointer is always set: */ + png_zstream_error(png_ptr, ret); + return ret; + } + + else + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; + } +} +#endif + +/* Read and check the IDHR chunk */ +void /* PRIVATE */ +png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[13]; + png_uint_32 width, height; + int bit_depth, color_type, compression_type, filter_type; + int interlace_type; + + png_debug(1, "in png_handle_IHDR"); + + if (png_ptr->mode & PNG_HAVE_IHDR) + png_chunk_error(png_ptr, "out of place"); + + /* Check the length */ + if (length != 13) + png_chunk_error(png_ptr, "invalid"); + + png_ptr->mode |= PNG_HAVE_IHDR; + + png_crc_read(png_ptr, buf, 13); + png_crc_finish(png_ptr, 0); + + width = png_get_uint_31(png_ptr, buf); + height = png_get_uint_31(png_ptr, buf + 4); + bit_depth = buf[8]; + color_type = buf[9]; + compression_type = buf[10]; + filter_type = buf[11]; + interlace_type = buf[12]; + + /* Set internal variables */ + png_ptr->width = width; + png_ptr->height = height; + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->interlaced = (png_byte)interlace_type; + png_ptr->color_type = (png_byte)color_type; +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + + /* Find number of channels */ + switch (png_ptr->color_type) + { + default: /* invalid, png_set_IHDR calls png_error */ + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_PALETTE: + png_ptr->channels = 1; + break; + + case PNG_COLOR_TYPE_RGB: + png_ptr->channels = 3; + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + png_ptr->channels = 2; + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: + png_ptr->channels = 4; + break; + } + + /* Set up other useful info */ + png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * + png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); + png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); + png_debug1(3, "channels = %d", png_ptr->channels); + png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes); + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + color_type, interlace_type, compression_type, filter_type); +} + +/* Read and check the palette */ +void /* PRIVATE */ +png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_color palette[PNG_MAX_PALETTE_LENGTH]; + int num, i; +#ifdef PNG_POINTER_INDEXING_SUPPORTED + png_colorp pal_ptr; +#endif + + png_debug(1, "in png_handle_PLTE"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + /* Moved to before the 'after IDAT' check below because otherwise duplicate + * PLTE chunks are potentially ignored (the spec says there shall not be more + * than one PLTE, the error is not treated as benign, so this check trumps + * the requirement that PLTE appears before IDAT.) + */ + else if (png_ptr->mode & PNG_HAVE_PLTE) + png_chunk_error(png_ptr, "duplicate"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + /* This is benign because the non-benign error happened before, when an + * IDAT was encountered in a color-mapped image with no PLTE. + */ + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + png_ptr->mode |= PNG_HAVE_PLTE; + + if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "ignored in grayscale PNG"); + return; + } + +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_crc_finish(png_ptr, length); + return; + } +#endif + + if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) + { + png_crc_finish(png_ptr, length); + + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + png_chunk_benign_error(png_ptr, "invalid"); + + else + png_chunk_error(png_ptr, "invalid"); + + return; + } + + /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */ + num = (int)length / 3; + +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + pal_ptr->red = buf[0]; + pal_ptr->green = buf[1]; + pal_ptr->blue = buf[2]; + } +#else + for (i = 0; i < num; i++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + /* Don't depend upon png_color being any order */ + palette[i].red = buf[0]; + palette[i].green = buf[1]; + palette[i].blue = buf[2]; + } +#endif + + /* If we actually need the PLTE chunk (ie for a paletted image), we do + * whatever the normal CRC configuration tells us. However, if we + * have an RGB image, the PLTE can be considered ancillary, so + * we will act as though it is. + */ +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#endif + { + png_crc_finish(png_ptr, 0); + } + +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ + { + /* If we don't want to use the data from an ancillary chunk, + * we have two options: an error abort, or a warning and we + * ignore the data in this chunk (which should be OK, since + * it's considered ancillary for a RGB or RGBA image). + * + * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the + * chunk type to determine whether to check the ancillary or the critical + * flags. + */ + if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) + { + if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) + { + png_chunk_benign_error(png_ptr, "CRC error"); + } + + else + { + png_chunk_warning(png_ptr, "CRC error"); + return; + } + } + + /* Otherwise, we (optionally) emit a warning and use the chunk. */ + else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) + { + png_chunk_warning(png_ptr, "CRC error"); + } + } +#endif + + /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its + * own copy of the palette. This has the side effect that when png_start_row + * is called (this happens after any call to png_read_update_info) the + * info_ptr palette gets changed. This is extremely unexpected and + * confusing. + * + * Fix this by not sharing the palette in this way. + */ + png_set_PLTE(png_ptr, info_ptr, palette, num); + + /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before + * IDAT. Prior to 1.6.0 this was not checked; instead the code merely + * checked the apparent validity of a tRNS chunk inserted before PLTE on a + * palette PNG. 1.6.0 attempts to rigorously follow the standard and + * therefore does a benign error if the erroneous condition is detected *and* + * cancels the tRNS if the benign error returns. The alternative is to + * amend the standard since it would be rather hypocritical of the standards + * maintainers to ignore it. + */ +#ifdef PNG_READ_tRNS_SUPPORTED + if (png_ptr->num_trans > 0 || + (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)) + { + /* Cancel this because otherwise it would be used if the transforms + * require it. Don't cancel the 'valid' flag because this would prevent + * detection of duplicate chunks. + */ + png_ptr->num_trans = 0; + + if (info_ptr != NULL) + info_ptr->num_trans = 0; + + png_chunk_benign_error(png_ptr, "tRNS must be after"); + } +#endif + +#ifdef PNG_READ_hIST_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) + png_chunk_benign_error(png_ptr, "hIST must be after"); +#endif + +#ifdef PNG_READ_bKGD_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) + png_chunk_benign_error(png_ptr, "bKGD must be after"); +#endif +} + +void /* PRIVATE */ +png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_debug(1, "in png_handle_IEND"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) + png_chunk_error(png_ptr, "out of place"); + + png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); + + png_crc_finish(png_ptr, length); + + if (length != 0) + png_chunk_benign_error(png_ptr, "invalid"); + + PNG_UNUSED(info_ptr) +} + +#ifdef PNG_READ_gAMA_SUPPORTED +void /* PRIVATE */ +png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_fixed_point igamma; + png_byte buf[4]; + + png_debug(1, "in png_handle_gAMA"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + if (length != 4) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 4); + + if (png_crc_finish(png_ptr, 0)) + return; + + igamma = png_get_fixed_point(NULL, buf); + + png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma); + png_colorspace_sync(png_ptr, info_ptr); +} +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED +void /* PRIVATE */ +png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + unsigned int truelen; + png_byte buf[4]; + + png_debug(1, "in png_handle_sBIT"); + + buf[0] = buf[1] = buf[2] = buf[3] = 0; + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 3; + + else + truelen = png_ptr->channels; + + if (length != truelen || length > 4) + { + png_chunk_benign_error(png_ptr, "invalid"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, truelen); + + if (png_crc_finish(png_ptr, 0)) + return; + + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + { + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[1]; + png_ptr->sig_bit.blue = buf[2]; + png_ptr->sig_bit.alpha = buf[3]; + } + + else + { + png_ptr->sig_bit.gray = buf[0]; + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[0]; + png_ptr->sig_bit.blue = buf[0]; + png_ptr->sig_bit.alpha = buf[1]; + } + + png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); +} +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED +void /* PRIVATE */ +png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[32]; + png_xy xy; + + png_debug(1, "in png_handle_cHRM"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + if (length != 32) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 32); + + if (png_crc_finish(png_ptr, 0)) + return; + + xy.whitex = png_get_fixed_point(NULL, buf); + xy.whitey = png_get_fixed_point(NULL, buf + 4); + xy.redx = png_get_fixed_point(NULL, buf + 8); + xy.redy = png_get_fixed_point(NULL, buf + 12); + xy.greenx = png_get_fixed_point(NULL, buf + 16); + xy.greeny = png_get_fixed_point(NULL, buf + 20); + xy.bluex = png_get_fixed_point(NULL, buf + 24); + xy.bluey = png_get_fixed_point(NULL, buf + 28); + + if (xy.whitex == PNG_FIXED_ERROR || + xy.whitey == PNG_FIXED_ERROR || + xy.redx == PNG_FIXED_ERROR || + xy.redy == PNG_FIXED_ERROR || + xy.greenx == PNG_FIXED_ERROR || + xy.greeny == PNG_FIXED_ERROR || + xy.bluex == PNG_FIXED_ERROR || + xy.bluey == PNG_FIXED_ERROR) + { + png_chunk_benign_error(png_ptr, "invalid values"); + return; + } + + /* If a colorspace error has already been output skip this chunk */ + if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) + return; + + if (png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) + { + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy, + 1/*prefer cHRM values*/); + png_colorspace_sync(png_ptr, info_ptr); +} +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED +void /* PRIVATE */ +png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte intent; + + png_debug(1, "in png_handle_sRGB"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + if (length != 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, &intent, 1); + + if (png_crc_finish(png_ptr, 0)) + return; + + /* If a colorspace error has already been output skip this chunk */ + if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) + return; + + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. + */ + if (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) + { + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "too many profiles"); + return; + } + + (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent); + png_colorspace_sync(png_ptr, info_ptr); +} +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#ifdef PNG_READ_iCCP_SUPPORTED +void /* PRIVATE */ +png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +/* Note: this does not properly handle profiles that are > 64K under DOS */ +{ + png_const_charp errmsg = NULL; /* error message output, or no error */ + int finished = 0; /* crc checked */ + + png_debug(1, "in png_handle_iCCP"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + /* Consistent with all the above colorspace handling an obviously *invalid* + * chunk is just ignored, so does not invalidate the color space. An + * alternative is to set the 'invalid' flags at the start of this routine + * and only clear them in they were not set before and all the tests pass. + * The minimum 'deflate' stream is assumed to be just the 2 byte header and 4 + * byte checksum. The keyword must be one character and there is a + * terminator (0) byte and the compression method. + */ + if (length < 9) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too short"); + return; + } + + /* If a colorspace error has already been output skip this chunk */ + if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) + { + png_crc_finish(png_ptr, length); + return; + } + + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0) + { + uInt read_length, keyword_length; + char keyword[81]; + + /* Find the keyword; the keyword plus separator and compression method + * bytes can be at most 81 characters long. + */ + read_length = 81; /* maximum */ + if (read_length > length) + read_length = (uInt)length; + + png_crc_read(png_ptr, (png_bytep)keyword, read_length); + length -= read_length; + + keyword_length = 0; + while (keyword_length < 80 && keyword_length < read_length && + keyword[keyword_length] != 0) + ++keyword_length; + + /* TODO: make the keyword checking common */ + if (keyword_length >= 1 && keyword_length <= 79) + { + /* We only understand '0' compression - deflate - so if we get a + * different value we can't safely decode the chunk. + */ + if (keyword_length+1 < read_length && + keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE) + { + read_length -= keyword_length+2; + + if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK) + { + Byte profile_header[132]; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + png_alloc_size_t size = (sizeof profile_header); + + png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2); + png_ptr->zstream.avail_in = read_length; + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, profile_header, &size, + 0/*finish: don't, because the output is too small*/); + + if (size == 0) + { + /* We have the ICC profile header; do the basic header checks. + */ + const png_uint_32 profile_length = + png_get_uint_32(profile_header); + + if (png_icc_check_length(png_ptr, &png_ptr->colorspace, + keyword, profile_length)) + { + /* The length is apparently ok, so we can check the 132 + * byte header. + */ + if (png_icc_check_header(png_ptr, &png_ptr->colorspace, + keyword, profile_length, profile_header, + png_ptr->color_type)) + { + /* Now read the tag table; a variable size buffer is + * needed at this point, allocate one for the whole + * profile. The header check has already validated + * that none of these stuff will overflow. + */ + const png_uint_32 tag_count = png_get_uint_32( + profile_header+128); + png_bytep profile = png_read_buffer(png_ptr, + profile_length, 2/*silent*/); + + if (profile != NULL) + { + memcpy(profile, profile_header, + (sizeof profile_header)); + + size = 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header), &size, 0); + + /* Still expect a a buffer error because we expect + * there to be some tag data! + */ + if (size == 0) + { + if (png_icc_check_tag_table(png_ptr, + &png_ptr->colorspace, keyword, profile_length, + profile)) + { + /* The profile has been validated for basic + * security issues, so read the whole thing in. + */ + size = profile_length - (sizeof profile_header) + - 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header) + + 12 * tag_count, &size, 1/*finish*/); + + if (length > 0 && !(png_ptr->flags & + PNG_FLAG_BENIGN_ERRORS_WARN)) + errmsg = "extra compressed data"; + + /* But otherwise allow extra data: */ + else if (size == 0) + { + if (length > 0) + { + /* This can be handled completely, so + * keep going. + */ + png_chunk_warning(png_ptr, + "extra compressed data"); + } + + png_crc_finish(png_ptr, length); + finished = 1; + +# ifdef PNG_sRGB_SUPPORTED + /* Check for a match against sRGB */ + png_icc_set_sRGB(png_ptr, + &png_ptr->colorspace, profile, + png_ptr->zstream.adler); +# endif + + /* Steal the profile for info_ptr. */ + if (info_ptr != NULL) + { + png_free_data(png_ptr, info_ptr, + PNG_FREE_ICCP, 0); + + info_ptr->iccp_name = png_voidcast(char*, + png_malloc_base(png_ptr, + keyword_length+1)); + if (info_ptr->iccp_name != NULL) + { + memcpy(info_ptr->iccp_name, keyword, + keyword_length+1); + info_ptr->iccp_proflen = + profile_length; + info_ptr->iccp_profile = profile; + png_ptr->read_buffer = NULL; /*steal*/ + info_ptr->free_me |= PNG_FREE_ICCP; + info_ptr->valid |= PNG_INFO_iCCP; + } + + else + { + png_ptr->colorspace.flags |= + PNG_COLORSPACE_INVALID; + errmsg = "out of memory"; + } + } + + /* else the profile remains in the read + * buffer which gets reused for subsequent + * chunks. + */ + + if (info_ptr != NULL) + png_colorspace_sync(png_ptr, info_ptr); + + if (errmsg == NULL) + { + png_ptr->zowner = 0; + return; + } + } + + else if (size > 0) + errmsg = "truncated"; + + else + errmsg = png_ptr->zstream.msg; + } + + /* else png_icc_check_tag_table output an error */ + } + + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "out of memory"; + } + + /* else png_icc_check_header output an error */ + } + + /* else png_icc_check_length output an error */ + } + + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; + + /* Release the stream */ + png_ptr->zowner = 0; + } + + else /* png_inflate_claim failed */ + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "bad compression method"; /* or missing */ + } + + else + errmsg = "bad keyword"; + } + + else + errmsg = "too many profiles"; + + /* Failure: the reason is in 'errmsg' */ + if (!finished) + png_crc_finish(png_ptr, length); + + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + if (errmsg != NULL) /* else already output */ + png_chunk_benign_error(png_ptr, errmsg); +} +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#ifdef PNG_READ_sPLT_SUPPORTED +void /* PRIVATE */ +png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +{ + png_bytep entry_start, buffer; + png_sPLT_t new_palette; + png_sPLT_entryp pp; + png_uint_32 data_length; + int entry_size, i; + png_uint_32 skip = 0; + png_uint_32 dl; + png_size_t max_dl; + + png_debug(1, "in png_handle_sPLT"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for sPLT"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + +#ifdef PNG_MAX_MALLOC_64K + if (length > 65535U) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; + } +#endif + + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + + /* WARNING: this may break if size_t is less than 32 bits; it is assumed + * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a + * potential breakage point if the types in pngconf.h aren't exactly right. + */ + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, skip)) + return; + + buffer[length] = 0; + + for (entry_start = buffer; *entry_start; entry_start++) + /* Empty loop to find end of name */ ; + + ++entry_start; + + /* A sample depth should follow the separator, and we should be on it */ + if (entry_start > buffer + length - 2) + { + png_warning(png_ptr, "malformed sPLT chunk"); + return; + } + + new_palette.depth = *entry_start++; + entry_size = (new_palette.depth == 8 ? 6 : 10); + /* This must fit in a png_uint_32 because it is derived from the original + * chunk data length. + */ + data_length = length - (png_uint_32)(entry_start - buffer); + + /* Integrity-check the data length */ + if (data_length % entry_size) + { + png_warning(png_ptr, "sPLT chunk has bad length"); + return; + } + + dl = (png_int_32)(data_length / entry_size); + max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry)); + + if (dl > max_dl) + { + png_warning(png_ptr, "sPLT chunk too long"); + return; + } + + new_palette.nentries = (png_int_32)(data_length / entry_size); + + new_palette.entries = (png_sPLT_entryp)png_malloc_warn( + png_ptr, new_palette.nentries * (sizeof (png_sPLT_entry))); + + if (new_palette.entries == NULL) + { + png_warning(png_ptr, "sPLT chunk requires too much memory"); + return; + } + +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0; i < new_palette.nentries; i++) + { + pp = new_palette.entries + i; + + if (new_palette.depth == 8) + { + pp->red = *entry_start++; + pp->green = *entry_start++; + pp->blue = *entry_start++; + pp->alpha = *entry_start++; + } + + else + { + pp->red = png_get_uint_16(entry_start); entry_start += 2; + pp->green = png_get_uint_16(entry_start); entry_start += 2; + pp->blue = png_get_uint_16(entry_start); entry_start += 2; + pp->alpha = png_get_uint_16(entry_start); entry_start += 2; + } + + pp->frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#else + pp = new_palette.entries; + + for (i = 0; i < new_palette.nentries; i++) + { + + if (new_palette.depth == 8) + { + pp[i].red = *entry_start++; + pp[i].green = *entry_start++; + pp[i].blue = *entry_start++; + pp[i].alpha = *entry_start++; + } + + else + { + pp[i].red = png_get_uint_16(entry_start); entry_start += 2; + pp[i].green = png_get_uint_16(entry_start); entry_start += 2; + pp[i].blue = png_get_uint_16(entry_start); entry_start += 2; + pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2; + } + + pp[i].frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#endif + + /* Discard all chunk data except the name and stash that */ + new_palette.name = (png_charp)buffer; + + png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); + + png_free(png_ptr, new_palette.entries); +} +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#ifdef PNG_READ_tRNS_SUPPORTED +void /* PRIVATE */ +png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_tRNS"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + png_byte buf[2]; + + if (length != 2) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 2); + png_ptr->num_trans = 1; + png_ptr->trans_color.gray = png_get_uint_16(buf); + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_byte buf[6]; + + if (length != 6) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, length); + png_ptr->num_trans = 1; + png_ptr->trans_color.red = png_get_uint_16(buf); + png_ptr->trans_color.green = png_get_uint_16(buf + 2); + png_ptr->trans_color.blue = png_get_uint_16(buf + 4); + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + /* TODO: is this actually an error in the ISO spec? */ + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + if (length > png_ptr->num_palette || length > PNG_MAX_PALETTE_LENGTH || + length == 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, readbuf, length); + png_ptr->num_trans = (png_uint_16)length; + } + + else + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid with alpha channel"); + return; + } + + if (png_crc_finish(png_ptr, 0)) + { + png_ptr->num_trans = 0; + return; + } + + /* TODO: this is a horrible side effect in the palette case because the + * png_struct ends up with a pointer to the tRNS buffer owned by the + * png_info. Fix this. + */ + png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, + &(png_ptr->trans_color)); +} +#endif + +#ifdef PNG_READ_bKGD_SUPPORTED +void /* PRIVATE */ +png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + unsigned int truelen; + png_byte buf[6]; + png_color_16 background; + + png_debug(1, "in png_handle_bKGD"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE))) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 1; + + else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + truelen = 6; + + else + truelen = 2; + + if (length != truelen) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, truelen); + + if (png_crc_finish(png_ptr, 0)) + return; + + /* We convert the index value into RGB components so that we can allow + * arbitrary RGB values for background when we have transparency, and + * so it is easy to determine the RGB values of the background color + * from the info_ptr struct. + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + background.index = buf[0]; + + if (info_ptr && info_ptr->num_palette) + { + if (buf[0] >= info_ptr->num_palette) + { + png_chunk_benign_error(png_ptr, "invalid index"); + return; + } + + background.red = (png_uint_16)png_ptr->palette[buf[0]].red; + background.green = (png_uint_16)png_ptr->palette[buf[0]].green; + background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue; + } + + else + background.red = background.green = background.blue = 0; + + background.gray = 0; + } + + else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ + { + background.index = 0; + background.red = + background.green = + background.blue = + background.gray = png_get_uint_16(buf); + } + + else + { + background.index = 0; + background.red = png_get_uint_16(buf); + background.green = png_get_uint_16(buf + 2); + background.blue = png_get_uint_16(buf + 4); + background.gray = 0; + } + + png_set_bKGD(png_ptr, info_ptr, &background); +} +#endif + +#ifdef PNG_READ_hIST_SUPPORTED +void /* PRIVATE */ +png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + unsigned int num, i; + png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_hIST"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) || !(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + num = length / 2 ; + + if (num != png_ptr->num_palette || num > PNG_MAX_PALETTE_LENGTH) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + for (i = 0; i < num; i++) + { + png_byte buf[2]; + + png_crc_read(png_ptr, buf, 2); + readbuf[i] = png_get_uint_16(buf); + } + + if (png_crc_finish(png_ptr, 0)) + return; + + png_set_hIST(png_ptr, info_ptr, readbuf); +} +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED +void /* PRIVATE */ +png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_uint_32 res_x, res_y; + int unit_type; + + png_debug(1, "in png_handle_pHYs"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (length != 9) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 9); + + if (png_crc_finish(png_ptr, 0)) + return; + + res_x = png_get_uint_32(buf); + res_y = png_get_uint_32(buf + 4); + unit_type = buf[8]; + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); +} +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED +void /* PRIVATE */ +png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_int_32 offset_x, offset_y; + int unit_type; + + png_debug(1, "in png_handle_oFFs"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (length != 9) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 9); + + if (png_crc_finish(png_ptr, 0)) + return; + + offset_x = png_get_int_32(buf); + offset_y = png_get_int_32(buf + 4); + unit_type = buf[8]; + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); +} +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED +/* Read the pCAL chunk (described in the PNG Extensions document) */ +void /* PRIVATE */ +png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_int_32 X0, X1; + png_byte type, nparams; + png_bytep buffer, buf, units, endptr; + png_charpp params; + int i; + + png_debug(1, "in png_handle_pCAL"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)", + length + 1); + + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0)) + return; + + buffer[length] = 0; /* Null terminate the last string */ + + png_debug(3, "Finding end of pCAL purpose string"); + for (buf = buffer; *buf; buf++) + /* Empty loop */ ; + + endptr = buffer + length; + + /* We need to have at least 12 bytes after the purpose string + * in order to get the parameter information. + */ + if (endptr <= buf + 12) + { + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_debug(3, "Reading pCAL X0, X1, type, nparams, and units"); + X0 = png_get_int_32((png_bytep)buf+1); + X1 = png_get_int_32((png_bytep)buf+5); + type = buf[9]; + nparams = buf[10]; + units = buf + 11; + + png_debug(3, "Checking pCAL equation type and number of parameters"); + /* Check that we have the right number of parameters for known + * equation types. + */ + if ((type == PNG_EQUATION_LINEAR && nparams != 2) || + (type == PNG_EQUATION_BASE_E && nparams != 3) || + (type == PNG_EQUATION_ARBITRARY && nparams != 3) || + (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) + { + png_chunk_benign_error(png_ptr, "invalid parameter count"); + return; + } + + else if (type >= PNG_EQUATION_LAST) + { + png_chunk_benign_error(png_ptr, "unrecognized equation type"); + } + + for (buf = units; *buf; buf++) + /* Empty loop to move past the units string. */ ; + + png_debug(3, "Allocating pCAL parameters array"); + + params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + nparams * (sizeof (png_charp)))); + + if (params == NULL) + { + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + /* Get pointers to the start of each parameter string. */ + for (i = 0; i < nparams; i++) + { + buf++; /* Skip the null string terminator from previous parameter. */ + + png_debug1(3, "Reading pCAL parameter %d", i); + + for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; buf++) + /* Empty loop to move past each parameter string */ ; + + /* Make sure we haven't run out of data yet */ + if (buf > endptr) + { + png_free(png_ptr, params); + png_chunk_benign_error(png_ptr, "invalid data"); + return; + } + } + + png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams, + (png_charp)units, params); + + png_free(png_ptr, params); +} +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED +/* Read the sCAL chunk */ +void /* PRIVATE */ +png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_bytep buffer; + png_size_t i; + int state; + + png_debug(1, "in png_handle_sCAL"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + /* Need unit type, width, \0, height: minimum 4 bytes */ + else if (length < 4) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)", + length + 1); + + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + + if (buffer == NULL) + { + png_chunk_benign_error(png_ptr, "out of memory"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buffer, length); + buffer[length] = 0; /* Null terminate the last string */ + + if (png_crc_finish(png_ptr, 0)) + return; + + /* Validate the unit. */ + if (buffer[0] != 1 && buffer[0] != 2) + { + png_chunk_benign_error(png_ptr, "invalid unit"); + return; + } + + /* Validate the ASCII numbers, need two ASCII numbers separated by + * a '\0' and they need to fit exactly in the chunk data. + */ + i = 1; + state = 0; + + if (!png_check_fp_number((png_const_charp)buffer, length, &state, &i) || + i >= length || buffer[i++] != 0) + png_chunk_benign_error(png_ptr, "bad width format"); + + else if (!PNG_FP_IS_POSITIVE(state)) + png_chunk_benign_error(png_ptr, "non-positive width"); + + else + { + png_size_t heighti = i; + + state = 0; + if (!png_check_fp_number((png_const_charp)buffer, length, &state, &i) || + i != length) + png_chunk_benign_error(png_ptr, "bad height format"); + + else if (!PNG_FP_IS_POSITIVE(state)) + png_chunk_benign_error(png_ptr, "non-positive height"); + + else + /* This is the (only) success case. */ + png_set_sCAL_s(png_ptr, info_ptr, buffer[0], + (png_charp)buffer+1, (png_charp)buffer+heighti); + } +} +#endif + +#ifdef PNG_READ_tIME_SUPPORTED +void /* PRIVATE */ +png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[7]; + png_time mod_time; + + png_debug(1, "in png_handle_tIME"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + + if (length != 7) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 7); + + if (png_crc_finish(png_ptr, 0)) + return; + + mod_time.second = buf[6]; + mod_time.minute = buf[5]; + mod_time.hour = buf[4]; + mod_time.day = buf[3]; + mod_time.month = buf[2]; + mod_time.year = png_get_uint_16(buf); + + png_set_tIME(png_ptr, info_ptr, &mod_time); +} +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED +/* Note: this does not properly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_text text_info; + png_bytep buffer; + png_charp key; + png_charp text; + png_uint_32 skip = 0; + + png_debug(1, "in png_handle_tEXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + if (length > 65535U) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; + } +#endif + + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); + + if (buffer == NULL) + { + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, skip)) + return; + + key = (png_charp)buffer; + key[length] = 0; + + for (text = key; *text; text++) + /* Empty loop to find end of key */ ; + + if (text != key + length) + text++; + + text_info.compression = PNG_TEXT_COMPRESSION_NONE; + text_info.key = key; + text_info.lang = NULL; + text_info.lang_key = NULL; + text_info.itxt_length = 0; + text_info.text = text; + text_info.text_length = strlen(text); + + if (png_set_text_2(png_ptr, info_ptr, &text_info, 1)) + png_warning(png_ptr, "Insufficient memory to process text chunk"); +} +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 keyword_length; + + png_debug(1, "in png_handle_zTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + + buffer = png_read_buffer(png_ptr, length, 2/*silent*/); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0)) + return; + + /* TODO: also check that the keyword contents match the spec! */ + for (keyword_length = 0; + keyword_length < length && buffer[keyword_length] != 0; + ++keyword_length) + /* Empty loop to find end of name */ ; + + if (keyword_length > 79 || keyword_length < 1) + errmsg = "bad keyword"; + + /* zTXt must have some LZ data after the keyword, although it may expand to + * zero bytes; we need a '\0' at the end of the keyword, the compression type + * then the LZ data: + */ + else if (keyword_length + 3 > length) + errmsg = "truncated"; + + else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE) + errmsg = "unknown compression type"; + + else + { + png_alloc_size_t uncompressed_length = PNG_SIZE_MAX; + + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for iCCP + * and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, keyword_length+2, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + { + png_text text; + + /* It worked; png_ptr->read_buffer now looks like a tEXt chunk except + * for the extra compression type byte and the fact that it isn't + * necessarily '\0' terminated. + */ + buffer = png_ptr->read_buffer; + buffer[uncompressed_length+(keyword_length+2)] = 0; + + text.compression = PNG_TEXT_COMPRESSION_zTXt; + text.key = (png_charp)buffer; + text.text = (png_charp)(buffer + keyword_length+2); + text.text_length = uncompressed_length; + text.itxt_length = 0; + text.lang = NULL; + text.lang_key = NULL; + + if (png_set_text_2(png_ptr, info_ptr, &text, 1)) + errmsg = "insufficient memory"; + } + + else + errmsg = png_ptr->zstream.msg; + } + + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); +} +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 prefix_length; + + png_debug(1, "in png_handle_iTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + return; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0)) + return; + + /* First the keyword. */ + for (prefix_length=0; + prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* Perform a basic check on the keyword length here. */ + if (prefix_length > 79 || prefix_length < 1) + errmsg = "bad keyword"; + + /* Expect keyword, compression flag, compression type, language, translated + * keyword (both may be empty but are 0 terminated) then the text, which may + * be empty. + */ + else if (prefix_length + 5 > length) + errmsg = "truncated"; + + else if (buffer[prefix_length+1] == 0 || + (buffer[prefix_length+1] == 1 && + buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE)) + { + int compressed = buffer[prefix_length+1] != 0; + png_uint_32 language_offset, translated_keyword_offset; + png_alloc_size_t uncompressed_length = 0; + + /* Now the language tag */ + prefix_length += 3; + language_offset = prefix_length; + + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* WARNING: the length may be invalid here, this is checked below. */ + translated_keyword_offset = ++prefix_length; + + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* prefix_length should now be at the trailing '\0' of the translated + * keyword, but it may already be over the end. None of this arithmetic + * can overflow because chunks are at most 2^31 bytes long, but on 16-bit + * systems the available allocaton may overflow. + */ + ++prefix_length; + + if (!compressed && prefix_length <= length) + uncompressed_length = length - prefix_length; + + else if (compressed && prefix_length < length) + { + uncompressed_length = PNG_SIZE_MAX; + + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for + * iCCP and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, prefix_length, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + buffer = png_ptr->read_buffer; + + else + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "truncated"; + + if (errmsg == NULL) + { + png_text text; + + buffer[uncompressed_length+prefix_length] = 0; + + if (compressed) + text.compression = PNG_ITXT_COMPRESSION_NONE; + + else + text.compression = PNG_ITXT_COMPRESSION_zTXt; + + text.key = (png_charp)buffer; + text.lang = (png_charp)buffer + language_offset; + text.lang_key = (png_charp)buffer + translated_keyword_offset; + text.text = (png_charp)buffer + prefix_length; + text.text_length = 0; + text.itxt_length = uncompressed_length; + + if (png_set_text_2(png_ptr, info_ptr, &text, 1)) + errmsg = "insufficient memory"; + } + } + + else + errmsg = "bad compression info"; + + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); +} +#endif + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */ +static int +png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) +{ + png_alloc_size_t limit = PNG_SIZE_MAX; + + if (png_ptr->unknown_chunk.data != NULL) + { + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + } + +# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; + +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif + + if (length <= limit) + { + PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name); + /* The following is safe because of the PNG_SIZE_MAX init above */ + png_ptr->unknown_chunk.size = (png_size_t)length/*SAFE*/; + /* 'mode' is a flag array, only the bottom four bits matter here */ + png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/; + + if (length == 0) + png_ptr->unknown_chunk.data = NULL; + + else + { + /* Do a 'warn' here - it is handled below. */ + png_ptr->unknown_chunk.data = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, length)); + } + } + + if (png_ptr->unknown_chunk.data == NULL && length > 0) + { + /* This is benign because we clean up correctly */ + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "unknown chunk exceeds memory limits"); + return 0; + } + + else + { + if (length > 0) + png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length); + png_crc_finish(png_ptr, 0); + return 1; + } +} +#endif /* PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ + +/* Handle an unknown, or known but disabled, chunk */ +void /* PRIVATE */ +png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, + png_uint_32 length, int keep) +{ + int handled = 0; /* the chunk was handled */ + + png_debug(1, "in png_handle_unknown"); + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing + * the bug which meant that setting a non-default behavior for a specific + * chunk would be ignored (the default was always used unless a user + * callback was installed). + * + * 'keep' is the value from the png_chunk_unknown_handling, the setting for + * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it + * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here. + * This is just an optimization to avoid multiple calls to the lookup + * function. + */ +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); +# endif +# endif + + /* One of the following methods will read the chunk or skip it (at least one + * of these is always defined because this is the only way to switch on + * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + */ +# ifdef PNG_READ_USER_CHUNKS_SUPPORTED + /* The user callback takes precedence over the chunk keep value, but the + * keep value is still required to validate a save of a critical chunk. + */ + if (png_ptr->read_user_chunk_fn != NULL) + { + if (png_cache_unknown_chunk(png_ptr, length)) + { + /* Callback to user unknown chunk handler */ + int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr, + &png_ptr->unknown_chunk); + + /* ret is: + * negative: An error occured, png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be discarded + * unless png_set_keep_unknown_chunks has been used to set + * a 'keep' behavior for this particular chunk, in which + * case that will be used. A critical chunk will cause an + * error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + */ + if (ret < 0) + png_chunk_error(png_ptr, "error in user chunk"); + + else if (ret == 0) + { + /* If the keep value is 'default' or 'never' override it, but + * still error out on critical chunks unless the keep value is + * 'always' While this is weird it is the behavior in 1.4.12. + * A possible improvement would be to obey the value set for the + * chunk, but this would be an API change that would probably + * damage some applications. + * + * The png_app_warning below catches the case that matters, where + * the application has not set specific save or ignore for this + * chunk or global save or ignore. + */ + if (keep < PNG_HANDLE_CHUNK_IF_SAFE) + { +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE) + { + png_chunk_warning(png_ptr, "Saving unknown chunk:"); + png_app_warning(png_ptr, + "forcing save of an unhandled chunk;" + " please call png_set_keep_unknown_chunks"); + /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */ + } +# endif + keep = PNG_HANDLE_CHUNK_IF_SAFE; + } + } + + else /* chunk was handled */ + { + handled = 1; + /* Critical chunks can be safely discarded at this point. */ + keep = PNG_HANDLE_CHUNK_NEVER; + } + } + + else + keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */ + } + + else + /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */ +# endif /* PNG_READ_USER_CHUNKS_SUPPORTED */ + +# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + { + /* keep is currently just the per-chunk setting, if there was no + * setting change it to the global default now (not that this may + * still be AS_DEFAULT) then obtain the cache of the chunk if required, + * if not simply skip the chunk. + */ + if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + keep = png_ptr->unknown_default; + + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { + if (!png_cache_unknown_chunk(png_ptr, length)) + keep = PNG_HANDLE_CHUNK_NEVER; + } + + else + png_crc_finish(png_ptr, length); + } +# else +# ifndef PNG_READ_USER_CHUNKS_SUPPORTED +# error no method to support READ_UNKNOWN_CHUNKS +# endif + + { + /* If here there is no read callback pointer set and no support is + * compiled in to just save the unknown chunks, so simply skip this + * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then + * the app has erroneously asked for unknown chunk saving when there + * is no support. + */ + if (keep > PNG_HANDLE_CHUNK_NEVER) + png_app_error(png_ptr, "no unknown chunk support available"); + + png_crc_finish(png_ptr, length); + } +# endif + +# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + /* Now store the chunk in the chunk list if appropriate, and if the limits + * permit it. + */ + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { +# ifdef PNG_USER_LIMITS_SUPPORTED + switch (png_ptr->user_chunk_cache_max) + { + case 2: + png_ptr->user_chunk_cache_max = 1; + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + /* FALL THROUGH */ + case 1: + /* NOTE: prior to 1.6.0 this case resulted in an unknown critical + * chunk being skipped, now there will be a hard error below. + */ + break; + + default: /* not at limit */ + --(png_ptr->user_chunk_cache_max); + /* FALL THROUGH */ + case 0: /* no limit */ +# endif /* PNG_USER_LIMITS_SUPPORTED */ + /* Here when the limit isn't reached or when limits are compiled + * out; store the chunk. + */ + png_set_unknown_chunks(png_ptr, info_ptr, + &png_ptr->unknown_chunk, 1); + handled = 1; +# ifdef PNG_USER_LIMITS_SUPPORTED + break; + } +# endif + } +# else /* no store support! */ + PNG_UNUSED(info_ptr) +# error untested code (reading unknown chunks with no store support) +# endif + + /* Regardless of the error handling below the cached data (if any) can be + * freed now. Notice that the data is not freed if there is a png_error, but + * it will be freed by destroy_read_struct. + */ + if (png_ptr->unknown_chunk.data != NULL) + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + +#else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ + /* There is no support to read an unknown chunk, so just skip it. */ + png_crc_finish(png_ptr, length); + PNG_UNUSED(info_ptr) + PNG_UNUSED(keep) +#endif /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ + + /* Check for unhandled critical chunks */ + if (!handled && PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) + png_chunk_error(png_ptr, "unhandled critical chunk"); +} + +/* This function is called to verify that a chunk name is valid. + * This function can't have the "critical chunk check" incorporated + * into it, since in the future we will need to be able to call user + * functions to handle unknown critical chunks after we check that + * the chunk name itself is valid. + */ + +/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is: + * + * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) + */ + +void /* PRIVATE */ +png_check_chunk_name(png_structrp png_ptr, png_uint_32 chunk_name) +{ + int i; + + png_debug(1, "in png_check_chunk_name"); + + for (i=1; i<=4; ++i) + { + int c = chunk_name & 0xff; + + if (c < 65 || c > 122 || (c > 90 && c < 97)) + png_chunk_error(png_ptr, "invalid chunk type"); + + chunk_name >>= 8; + } +} + +/* Combines the row recently read in with the existing pixels in the row. This + * routine takes care of alpha and transparency if requested. This routine also + * handles the two methods of progressive display of interlaced images, + * depending on the 'display' value; if 'display' is true then the whole row + * (dp) is filled from the start by replicating the available pixels. If + * 'display' is false only those pixels present in the pass are filled in. + */ +void /* PRIVATE */ +png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) +{ + unsigned int pixel_depth = png_ptr->transformed_pixel_depth; + png_const_bytep sp = png_ptr->row_buf + 1; + png_uint_32 row_width = png_ptr->width; + unsigned int pass = png_ptr->pass; + png_bytep end_ptr = 0; + png_byte end_byte = 0; + unsigned int end_mask; + + png_debug(1, "in png_combine_row"); + + /* Added in 1.5.6: it should not be possible to enter this routine until at + * least one row has been read from the PNG data and transformed. + */ + if (pixel_depth == 0) + png_error(png_ptr, "internal row logic error"); + + /* Added in 1.5.4: the pixel depth should match the information returned by + * any call to png_read_update_info at this point. Do not continue if we got + * this wrong. + */ + if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes != + PNG_ROWBYTES(pixel_depth, row_width)) + png_error(png_ptr, "internal row size calculation error"); + + /* Don't expect this to ever happen: */ + if (row_width == 0) + png_error(png_ptr, "internal row width error"); + + /* Preserve the last byte in cases where only part of it will be overwritten, + * the multiply below may overflow, we don't care because ANSI-C guarantees + * we get the low bits. + */ + end_mask = (pixel_depth * row_width) & 7; + if (end_mask != 0) + { + /* end_ptr == NULL is a flag to say do nothing */ + end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1; + end_byte = *end_ptr; +# ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) /* little-endian byte */ + end_mask = 0xff << end_mask; + + else /* big-endian byte */ +# endif + end_mask = 0xff >> end_mask; + /* end_mask is now the bits to *keep* from the destination row */ + } + + /* For non-interlaced images this reduces to a memcpy(). A memcpy() + * will also happen if interlacing isn't supported or if the application + * does not call png_set_interlace_handling(). In the latter cases the + * caller just gets a sequence of the unexpanded rows from each interlace + * pass. + */ +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE) && + pass < 6 && (display == 0 || + /* The following copies everything for 'display' on passes 0, 2 and 4. */ + (display == 1 && (pass & 1) != 0))) + { + /* Narrow images may have no bits in a pass; the caller should handle + * this, but this test is cheap: + */ + if (row_width <= PNG_PASS_START_COL(pass)) + return; + + if (pixel_depth < 8) + { + /* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit + * into 32 bits, then a single loop over the bytes using the four byte + * values in the 32-bit mask can be used. For the 'display' option the + * expanded mask may also not require any masking within a byte. To + * make this work the PACKSWAP option must be taken into account - it + * simply requires the pixels to be reversed in each byte. + * + * The 'regular' case requires a mask for each of the first 6 passes, + * the 'display' case does a copy for the even passes in the range + * 0..6. This has already been handled in the test above. + * + * The masks are arranged as four bytes with the first byte to use in + * the lowest bits (little-endian) regardless of the order (PACKSWAP or + * not) of the pixels in each byte. + * + * NOTE: the whole of this logic depends on the caller of this function + * only calling it on rows appropriate to the pass. This function only + * understands the 'x' logic; the 'y' logic is handled by the caller. + * + * The following defines allow generation of compile time constant bit + * masks for each pixel depth and each possibility of swapped or not + * swapped bytes. Pass 'p' is in the range 0..6; 'x', a pixel index, + * is in the range 0..7; and the result is 1 if the pixel is to be + * copied in the pass, 0 if not. 'S' is for the sparkle method, 'B' + * for the block method. + * + * With some compilers a compile time expression of the general form: + * + * (shift >= 32) ? (a >> (shift-32)) : (b >> shift) + * + * Produces warnings with values of 'shift' in the range 33 to 63 + * because the right hand side of the ?: expression is evaluated by + * the compiler even though it isn't used. Microsoft Visual C (various + * versions) and the Intel C compiler are known to do this. To avoid + * this the following macros are used in 1.5.6. This is a temporary + * solution to avoid destabilizing the code during the release process. + */ +# if PNG_USE_COMPILE_TIME_MASKS +# define PNG_LSR(x,s) ((x)>>((s) & 0x1f)) +# define PNG_LSL(x,s) ((x)<<((s) & 0x1f)) +# else +# define PNG_LSR(x,s) ((x)>>(s)) +# define PNG_LSL(x,s) ((x)<<(s)) +# endif +# define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\ + PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1) +# define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\ + PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1) + + /* Return a mask for pass 'p' pixel 'x' at depth 'd'. The mask is + * little endian - the first pixel is at bit 0 - however the extra + * parameter 's' can be set to cause the mask position to be swapped + * within each byte, to match the PNG format. This is done by XOR of + * the shift with 7, 6 or 4 for bit depths 1, 2 and 4. + */ +# define PIXEL_MASK(p,x,d,s) \ + (PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0)))) + + /* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask. + */ +# define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) +# define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) + + /* Combine 8 of these to get the full mask. For the 1-bpp and 2-bpp + * cases the result needs replicating, for the 4-bpp case the above + * generates a full 32 bits. + */ +# define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1))) + +# define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\ + S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\ + S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d) + +# define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\ + B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\ + B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d) + +#if PNG_USE_COMPILE_TIME_MASKS + /* Utility macros to construct all the masks for a depth/swap + * combination. The 's' parameter says whether the format is PNG + * (big endian bytes) or not. Only the three odd-numbered passes are + * required for the display/block algorithm. + */ +# define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\ + S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) } + +# define B_MASKS(d,s) { B_MASK(1,d,s), S_MASK(3,d,s), S_MASK(5,d,s) } + +# define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2)) + + /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and + * then pass: + */ + static PNG_CONST png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] = + { + /* Little-endian byte masks for PACKSWAP */ + { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) }, + /* Normal (big-endian byte) masks - PNG format */ + { S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) } + }; + + /* display_mask has only three entries for the odd passes, so index by + * pass>>1. + */ + static PNG_CONST png_uint_32 display_mask[2][3][3] = + { + /* Little-endian byte masks for PACKSWAP */ + { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) }, + /* Normal (big-endian byte) masks - PNG format */ + { B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) } + }; + +# define MASK(pass,depth,display,png)\ + ((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\ + row_mask[png][DEPTH_INDEX(depth)][pass]) + +#else /* !PNG_USE_COMPILE_TIME_MASKS */ + /* This is the runtime alternative: it seems unlikely that this will + * ever be either smaller or faster than the compile time approach. + */ +# define MASK(pass,depth,display,png)\ + ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png)) +#endif /* !PNG_USE_COMPILE_TIME_MASKS */ + + /* Use the appropriate mask to copy the required bits. In some cases + * the byte mask will be 0 or 0xff, optimize these cases. row_width is + * the number of pixels, but the code copies bytes, so it is necessary + * to special case the end. + */ + png_uint_32 pixels_per_byte = 8 / pixel_depth; + png_uint_32 mask; + +# ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + mask = MASK(pass, pixel_depth, display, 0); + + else +# endif + mask = MASK(pass, pixel_depth, display, 1); + + for (;;) + { + png_uint_32 m; + + /* It doesn't matter in the following if png_uint_32 has more than + * 32 bits because the high bits always match those in m<<24; it is, + * however, essential to use OR here, not +, because of this. + */ + m = mask; + mask = (m >> 8) | (m << 24); /* rotate right to good compilers */ + m &= 0xff; + + if (m != 0) /* something to copy */ + { + if (m != 0xff) + *dp = (png_byte)((*dp & ~m) | (*sp & m)); + else + *dp = *sp; + } + + /* NOTE: this may overwrite the last byte with garbage if the image + * is not an exact number of bytes wide; libpng has always done + * this. + */ + if (row_width <= pixels_per_byte) + break; /* May need to restore part of the last byte */ + + row_width -= pixels_per_byte; + ++dp; + ++sp; + } + } + + else /* pixel_depth >= 8 */ + { + unsigned int bytes_to_copy, bytes_to_jump; + + /* Validate the depth - it must be a multiple of 8 */ + if (pixel_depth & 7) + png_error(png_ptr, "invalid user transform pixel depth"); + + pixel_depth >>= 3; /* now in bytes */ + row_width *= pixel_depth; + + /* Regardless of pass number the Adam 7 interlace always results in a + * fixed number of pixels to copy then to skip. There may be a + * different number of pixels to skip at the start though. + */ + { + unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth; + + row_width -= offset; + dp += offset; + sp += offset; + } + + /* Work out the bytes to copy. */ + if (display) + { + /* When doing the 'block' algorithm the pixel in the pass gets + * replicated to adjacent pixels. This is why the even (0,2,4,6) + * passes are skipped above - the entire expanded row is copied. + */ + bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth; + + /* But don't allow this number to exceed the actual row width. */ + if (bytes_to_copy > row_width) + bytes_to_copy = row_width; + } + + else /* normal row; Adam7 only ever gives us one pixel to copy. */ + bytes_to_copy = pixel_depth; + + /* In Adam7 there is a constant offset between where the pixels go. */ + bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth; + + /* And simply copy these bytes. Some optimization is possible here, + * depending on the value of 'bytes_to_copy'. Special case the low + * byte counts, which we know to be frequent. + * + * Notice that these cases all 'return' rather than 'break' - this + * avoids an unnecessary test on whether to restore the last byte + * below. + */ + switch (bytes_to_copy) + { + case 1: + for (;;) + { + *dp = *sp; + + if (row_width <= bytes_to_jump) + return; + + dp += bytes_to_jump; + sp += bytes_to_jump; + row_width -= bytes_to_jump; + } + + case 2: + /* There is a possibility of a partial copy at the end here; this + * slows the code down somewhat. + */ + do + { + dp[0] = sp[0], dp[1] = sp[1]; + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + } + while (row_width > 1); + + /* And there can only be one byte left at this point: */ + *dp = *sp; + return; + + case 3: + /* This can only be the RGB case, so each copy is exactly one + * pixel and it is not necessary to check for a partial copy. + */ + for(;;) + { + dp[0] = sp[0], dp[1] = sp[1], dp[2] = sp[2]; + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + } + + default: +#if PNG_ALIGN_TYPE != PNG_ALIGN_NONE + /* Check for double byte alignment and, if possible, use a + * 16-bit copy. Don't attempt this for narrow images - ones that + * are less than an interlace panel wide. Don't attempt it for + * wide bytes_to_copy either - use the memcpy there. + */ + if (bytes_to_copy < 16 /*else use memcpy*/ && + png_isaligned(dp, png_uint_16) && + png_isaligned(sp, png_uint_16) && + bytes_to_copy % (sizeof (png_uint_16)) == 0 && + bytes_to_jump % (sizeof (png_uint_16)) == 0) + { + /* Everything is aligned for png_uint_16 copies, but try for + * png_uint_32 first. + */ + if (png_isaligned(dp, png_uint_32) && + png_isaligned(sp, png_uint_32) && + bytes_to_copy % (sizeof (png_uint_32)) == 0 && + bytes_to_jump % (sizeof (png_uint_32)) == 0) + { + png_uint_32p dp32 = png_aligncast(png_uint_32p,dp); + png_const_uint_32p sp32 = png_aligncastconst( + png_const_uint_32p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_32)); + + do + { + size_t c = bytes_to_copy; + do + { + *dp32++ = *sp32++; + c -= (sizeof (png_uint_32)); + } + while (c > 0); + + if (row_width <= bytes_to_jump) + return; + + dp32 += skip; + sp32 += skip; + row_width -= bytes_to_jump; + } + while (bytes_to_copy <= row_width); + + /* Get to here when the row_width truncates the final copy. + * There will be 1-3 bytes left to copy, so don't try the + * 16-bit loop below. + */ + dp = (png_bytep)dp32; + sp = (png_const_bytep)sp32; + do + *dp++ = *sp++; + while (--row_width > 0); + return; + } + + /* Else do it in 16-bit quantities, but only if the size is + * not too large. + */ + else + { + png_uint_16p dp16 = png_aligncast(png_uint_16p, dp); + png_const_uint_16p sp16 = png_aligncastconst( + png_const_uint_16p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_16)); + + do + { + size_t c = bytes_to_copy; + do + { + *dp16++ = *sp16++; + c -= (sizeof (png_uint_16)); + } + while (c > 0); + + if (row_width <= bytes_to_jump) + return; + + dp16 += skip; + sp16 += skip; + row_width -= bytes_to_jump; + } + while (bytes_to_copy <= row_width); + + /* End of row - 1 byte left, bytes_to_copy > row_width: */ + dp = (png_bytep)dp16; + sp = (png_const_bytep)sp16; + do + *dp++ = *sp++; + while (--row_width > 0); + return; + } + } +#endif /* PNG_ALIGN_ code */ + + /* The true default - use a memcpy: */ + for (;;) + { + memcpy(dp, sp, bytes_to_copy); + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + if (bytes_to_copy > row_width) + bytes_to_copy = row_width; + } + } + + /* NOT REACHED*/ + } /* pixel_depth >= 8 */ + + /* Here if pixel_depth < 8 to check 'end_ptr' below. */ + } + else +#endif + + /* If here then the switch above wasn't used so just memcpy the whole row + * from the temporary row buffer (notice that this overwrites the end of the + * destination row if it is a partial byte.) + */ + memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width)); + + /* Restore the overwritten bits from the last byte if necessary. */ + if (end_ptr != NULL) + *end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask)); +} + +#ifdef PNG_READ_INTERLACING_SUPPORTED +void /* PRIVATE */ +png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, + png_uint_32 transformations /* Because these may affect the byte layout */) +{ + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + /* Offset to next interlace block */ + static PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + png_debug(1, "in png_do_read_interlace"); + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 3); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_byte v; + png_uint_32 i; + int j; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (transformations & PNG_PACKSWAP) + { + sshift = (int)((row_info->width + 7) & 0x07); + dshift = (int)((final_width + 7) & 0x07); + s_start = 7; + s_end = 0; + s_inc = -1; + } + + else +#endif + { + sshift = 7 - (int)((row_info->width + 7) & 0x07); + dshift = 7 - (int)((final_width + 7) & 0x07); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = 0; i < row_info->width; i++) + { + v = (png_byte)((*sp >> sshift) & 0x01); + for (j = 0; j < jstop; j++) + { + unsigned int tmp = *dp & (0x7f7f >> (7 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); + + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + + else + dshift += s_inc; + } + + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + + else + sshift += s_inc; + } + break; + } + + case 2: + { + png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); + png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_uint_32 i; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (transformations & PNG_PACKSWAP) + { + sshift = (int)(((row_info->width + 3) & 0x03) << 1); + dshift = (int)(((final_width + 3) & 0x03) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + + else +#endif + { + sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1); + dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x03); + for (j = 0; j < jstop; j++) + { + unsigned int tmp = *dp & (0x3f3f >> (6 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); + + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + + else + dshift += s_inc; + } + + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + + else + sshift += s_inc; + } + break; + } + + case 4: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 1); + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + int jstop = png_pass_inc[pass]; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (transformations & PNG_PACKSWAP) + { + sshift = (int)(((row_info->width + 1) & 0x01) << 2); + dshift = (int)(((final_width + 1) & 0x01) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + + else +#endif + { + sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2); + dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v = (png_byte)((*sp >> sshift) & 0x0f); + int j; + + for (j = 0; j < jstop; j++) + { + unsigned int tmp = *dp & (0xf0f >> (4 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); + + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + + else + dshift += s_inc; + } + + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + + else + sshift += s_inc; + } + break; + } + + default: + { + png_size_t pixel_bytes = (row_info->pixel_depth >> 3); + + png_bytep sp = row + (png_size_t)(row_info->width - 1) + * pixel_bytes; + + png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; + + int jstop = png_pass_inc[pass]; + png_uint_32 i; + + for (i = 0; i < row_info->width; i++) + { + png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */ + int j; + + memcpy(v, sp, pixel_bytes); + + for (j = 0; j < jstop; j++) + { + memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + + sp -= pixel_bytes; + } + break; + } + } + + row_info->width = final_width; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); + } +#ifndef PNG_READ_PACKSWAP_SUPPORTED + PNG_UNUSED(transformations) /* Silence compiler warning */ +#endif +} +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + +static void +png_read_filter_row_sub(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_size_t istop = row_info->rowbytes; + unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + + PNG_UNUSED(prev_row) + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); + rp++; + } +} + +static void +png_read_filter_row_up(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_size_t istop = row_info->rowbytes; + png_bytep rp = row; + png_const_bytep pp = prev_row; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } +} + +static void +png_read_filter_row_avg(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_bytep rp = row; + png_const_bytep pp = prev_row; + unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + png_size_t istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) / 2 )) & 0xff); + + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); + + rp++; + } +} + +static void +png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp_end = row + row_info->rowbytes; + int a, c; + + /* First pixel/byte */ + c = *prev_row++; + a = *row + c; + *row++ = (png_byte)a; + + /* Remainder */ + while (row < rp_end) + { + int b, pa, pb, pc, p; + + a &= 0xff; /* From previous iteration or start */ + b = *prev_row++; + + p = b - c; + pc = a - c; + +# ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +# else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +# endif + + /* Find the best predictor, the least of pa, pb, pc favoring the earlier + * ones in the case of a tie. + */ + if (pb < pa) pa = pb, a = b; + if (pc < pa) a = c; + + /* Calculate the current pixel in a, and move the previous row pixel to c + * for the next time round the loop + */ + c = b; + a += *row; + *row++ = (png_byte)a; + } +} + +static void +png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + int bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp_end = row + bpp; + + /* Process the first pixel in the row completely (this is the same as 'up' + * because there is only one candidate predictor for the first row). + */ + while (row < rp_end) + { + int a = *row + *prev_row++; + *row++ = (png_byte)a; + } + + /* Remainder */ + rp_end += row_info->rowbytes - bpp; + + while (row < rp_end) + { + int a, b, c, pa, pb, pc, p; + + c = *(prev_row - bpp); + a = *(row - bpp); + b = *prev_row++; + + p = b - c; + pc = a - c; + +# ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +# else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +# endif + + if (pb < pa) pa = pb, a = b; + if (pc < pa) a = c; + + c = b; + a += *row; + *row++ = (png_byte)a; + } +} + +static void +png_init_filter_functions(png_structrp pp) + /* This function is called once for every PNG image to set the + * implementations required to reverse the filtering of PNG rows. Reversing + * the filter is the first transformation performed on the row data. It is + * performed in place, therefore an implementation can be selected based on + * the image pixel format. If the implementation depends on image width then + * take care to ensure that it works correctly if the image is interlaced - + * interlacing causes the actual row width to vary. + */ +{ + unsigned int bpp = (pp->pixel_depth + 7) >> 3; + + pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub; + pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up; + pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg; + if (bpp == 1) + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth_1byte_pixel; + else + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth_multibyte_pixel; + +#ifdef PNG_FILTER_OPTIMIZATIONS + /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to + * call to install hardware optimizations for the above functions; simply + * replace whatever elements of the pp->read_filter[] array with a hardware + * specific (or, for that matter, generic) optimization. + * + * To see an example of this examine what configure.ac does when + * --enable-arm-neon is specified on the command line. + */ + PNG_FILTER_OPTIMIZATIONS(pp, bpp); +#endif +} + +void /* PRIVATE */ +png_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row, + png_const_bytep prev_row, int filter) +{ + /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define + * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic + * implementations. See png_init_filter_functions above. + */ + if (pp->read_filter[0] == NULL) + png_init_filter_functions(pp); + if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST) + pp->read_filter[filter-1](row_info, row, prev_row); +} + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +void /* PRIVATE */ +png_read_IDAT_data(png_structrp png_ptr, png_bytep output, + png_alloc_size_t avail_out) +{ + /* Loop reading IDATs and decompressing the result into output[avail_out] */ + png_ptr->zstream.next_out = output; + png_ptr->zstream.avail_out = 0; /* safety: set below */ + + if (output == NULL) + avail_out = 0; + + do + { + int ret; + png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; + + if (png_ptr->zstream.avail_in == 0) + { + uInt avail_in; + png_bytep buffer; + + while (png_ptr->idat_size == 0) + { + png_crc_finish(png_ptr, 0); + + png_ptr->idat_size = png_read_chunk_header(png_ptr); + /* This is an error even in the 'check' case because the code just + * consumed a non-IDAT header. + */ + if (png_ptr->chunk_name != png_IDAT) + png_error(png_ptr, "Not enough image data"); + } + + avail_in = png_ptr->IDAT_read_size; + + if (avail_in > png_ptr->idat_size) + avail_in = (uInt)png_ptr->idat_size; + + /* A PNG with a gradually increasing IDAT size will defeat this attempt + * to minimize memory usage by causing lots of re-allocs, but + * realistically doing IDAT_read_size re-allocs is not likely to be a + * big problem. + */ + buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/); + + png_crc_read(png_ptr, buffer, avail_in); + png_ptr->idat_size -= avail_in; + + png_ptr->zstream.next_in = buffer; + png_ptr->zstream.avail_in = avail_in; + } + + /* And set up the output side. */ + if (output != NULL) /* standard read */ + { + uInt out = ZLIB_IO_MAX; + + if (out > avail_out) + out = (uInt)avail_out; + + avail_out -= out; + png_ptr->zstream.avail_out = out; + } + + else /* after last row, checking for end */ + { + png_ptr->zstream.next_out = tmpbuf; + png_ptr->zstream.avail_out = (sizeof tmpbuf); + } + + /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the + * process. If the LZ stream is truncated the sequential reader will + * terminally damage the stream, above, by reading the chunk header of the + * following chunk (it then exits with png_error). + * + * TODO: deal more elegantly with truncated IDAT lists. + */ + ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); + + /* Take the unconsumed output back. */ + if (output != NULL) + avail_out += png_ptr->zstream.avail_out; + + else /* avail_out counts the extra bytes */ + avail_out += (sizeof tmpbuf) - png_ptr->zstream.avail_out; + + png_ptr->zstream.avail_out = 0; + + if (ret == Z_STREAM_END) + { + /* Do this for safety; we won't read any more into this row. */ + png_ptr->zstream.next_out = NULL; + + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + + if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0) + png_chunk_benign_error(png_ptr, "Extra compressed data"); + break; + } + + if (ret != Z_OK) + { + png_zstream_error(png_ptr, ret); + + if (output != NULL) + png_chunk_error(png_ptr, png_ptr->zstream.msg); + + else /* checking */ + { + png_chunk_benign_error(png_ptr, png_ptr->zstream.msg); + return; + } + } + } while (avail_out > 0); + + if (avail_out > 0) + { + /* The stream ended before the image; this is the same as too few IDATs so + * should be handled the same way. + */ + if (output != NULL) + png_error(png_ptr, "Not enough image data"); + + else /* the deflate stream contained extra data */ + png_chunk_benign_error(png_ptr, "Too much image data"); + } +} + +void /* PRIVATE */ +png_read_finish_IDAT(png_structrp png_ptr) +{ + /* We don't need any more data and the stream should have ended, however the + * LZ end code may actually not have been processed. In this case we must + * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk + * may still remain to be consumed. + */ + if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) + { + /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in + * the compressed stream, but the stream may be damaged too, so even after + * this call we may need to terminate the zstream ownership. + */ + png_read_IDAT_data(png_ptr, NULL, 0); + png_ptr->zstream.next_out = NULL; /* safety */ + + /* Now clear everything out for safety; the following may not have been + * done. + */ + if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) + { + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + } + } + + /* If the zstream has not been released do it now *and* terminate the reading + * of the final IDAT chunk. + */ + if (png_ptr->zowner == png_IDAT) + { + /* Always do this; the pointers otherwise point into the read buffer. */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + + /* Now we no longer own the zstream. */ + png_ptr->zowner = 0; + + /* The slightly weird semantics of the sequential IDAT reading is that we + * are always in or at the end of an IDAT chunk, so we always need to do a + * crc_finish here. If idat_size is non-zero we also need to read the + * spurious bytes at the end of the chunk now. + */ + (void)png_crc_finish(png_ptr, png_ptr->idat_size); + } +} + +void /* PRIVATE */ +png_read_finish_row(png_structrp png_ptr) +{ +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + + png_debug(1, "in png_read_finish_row"); + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + + /* TO DO: don't do this if prev_row isn't needed (requires + * read-ahead of the next row's filter byte. + */ + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + do + { + png_ptr->pass++; + + if (png_ptr->pass >= 7) + break; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + if (!(png_ptr->transformations & PNG_INTERLACE)) + { + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + } + + else /* if (png_ptr->transformations & PNG_INTERLACE) */ + break; /* libpng deinterlacing sees every row */ + + } while (png_ptr->num_rows == 0 || png_ptr->iwidth == 0); + + if (png_ptr->pass < 7) + return; + } +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + + /* Here after at the end of the last row of the last pass. */ + png_read_finish_IDAT(png_ptr); +} +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ + +void /* PRIVATE */ +png_read_start_row(png_structrp png_ptr) +{ +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + int max_pixel_depth; + png_size_t row_bytes; + + png_debug(1, "in png_read_start_row"); + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + png_init_read_transformations(png_ptr); +#endif +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced) + { + if (!(png_ptr->transformations & PNG_INTERLACE)) + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + + else + png_ptr->num_rows = png_ptr->height; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + } + + else +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + { + png_ptr->num_rows = png_ptr->height; + png_ptr->iwidth = png_ptr->width; + } + + max_pixel_depth = png_ptr->pixel_depth; + + /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpliar set of + * calculations to calculate the final pixel depth, then + * png_do_read_transforms actually does the transforms. This means that the + * code which effectively calculates this value is actually repeated in three + * separate places. They must all match. Innocent changes to the order of + * transformations can and will break libpng in a way that causes memory + * overwrites. + * + * TODO: fix this. + */ +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) + max_pixel_depth = 8; +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans) + max_pixel_depth = 32; + + else + max_pixel_depth = 24; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth < 8) + max_pixel_depth = 8; + + if (png_ptr->num_trans) + max_pixel_depth *= 2; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + if (png_ptr->num_trans) + { + max_pixel_depth *= 4; + max_pixel_depth /= 3; + } + } + } +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND_16) + { +# ifdef PNG_READ_EXPAND_SUPPORTED + /* In fact it is an error if it isn't supported, but checking is + * the safe way. + */ + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->bit_depth < 16) + max_pixel_depth *= 2; + } + else +# endif + png_ptr->transformations &= ~PNG_EXPAND_16; + } +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if (png_ptr->transformations & (PNG_FILLER)) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth <= 8) + max_pixel_depth = 16; + + else + max_pixel_depth = 32; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB || + png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (max_pixel_depth <= 32) + max_pixel_depth = 32; + + else + max_pixel_depth = 64; + } + } +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + { + if ( +#ifdef PNG_READ_EXPAND_SUPPORTED + (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || +#endif +#ifdef PNG_READ_FILLER_SUPPORTED + (png_ptr->transformations & (PNG_FILLER)) || +#endif + png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (max_pixel_depth <= 16) + max_pixel_depth = 32; + + else + max_pixel_depth = 64; + } + + else + { + if (max_pixel_depth <= 8) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 32; + + else + max_pixel_depth = 24; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 64; + + else + max_pixel_depth = 48; + } + } +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ +defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + int user_pixel_depth = png_ptr->user_transform_depth * + png_ptr->user_transform_channels; + + if (user_pixel_depth > max_pixel_depth) + max_pixel_depth = user_pixel_depth; + } +#endif + + /* This value is stored in png_struct and double checked in the row read + * code. + */ + png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth; + png_ptr->transformed_pixel_depth = 0; /* calculated on demand */ + + /* Align the width on the next larger 8 pixels. Mainly used + * for interlacing + */ + row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); + /* Calculate the maximum bytes needed, adding a byte and a pixel + * for safety's sake + */ + row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + + 1 + ((max_pixel_depth + 7) >> 3); + +#ifdef PNG_MAX_MALLOC_64K + if (row_bytes > (png_uint_32)65536L) + png_error(png_ptr, "This image requires a row greater than 64KB"); +#endif + + if (row_bytes + 48 > png_ptr->old_big_row_buf_size) + { + png_free(png_ptr, png_ptr->big_row_buf); + png_free(png_ptr, png_ptr->big_prev_row); + + if (png_ptr->interlaced) + png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, + row_bytes + 48); + + else + png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48); + + png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48); + +#ifdef PNG_ALIGNED_MEMORY_SUPPORTED + /* Use 16-byte aligned memory for row_buf with at least 16 bytes + * of padding before and after row_buf; treat prev_row similarly. + * NOTE: the alignment is to the start of the pixels, one beyond the start + * of the buffer, because of the filter byte. Prior to libpng 1.5.6 this + * was incorrect; the filter byte was aligned, which had the exact + * opposite effect of that intended. + */ + { + png_bytep temp = png_ptr->big_row_buf + 32; + int extra = (int)((temp - (png_bytep)0) & 0x0f); + png_ptr->row_buf = temp - extra - 1/*filter byte*/; + + temp = png_ptr->big_prev_row + 32; + extra = (int)((temp - (png_bytep)0) & 0x0f); + png_ptr->prev_row = temp - extra - 1/*filter byte*/; + } + +#else + /* Use 31 bytes of padding before and 17 bytes after row_buf. */ + png_ptr->row_buf = png_ptr->big_row_buf + 31; + png_ptr->prev_row = png_ptr->big_prev_row + 31; +#endif + png_ptr->old_big_row_buf_size = row_bytes + 48; + } + +#ifdef PNG_MAX_MALLOC_64K + if (png_ptr->rowbytes > 65535) + png_error(png_ptr, "This image requires a row greater than 64KB"); + +#endif + if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1)) + png_error(png_ptr, "Row has too many bytes to allocate in memory"); + + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + png_debug1(3, "width = %u,", png_ptr->width); + png_debug1(3, "height = %u,", png_ptr->height); + png_debug1(3, "iwidth = %u,", png_ptr->iwidth); + png_debug1(3, "num_rows = %u,", png_ptr->num_rows); + png_debug1(3, "rowbytes = %lu,", (unsigned long)png_ptr->rowbytes); + png_debug1(3, "irowbytes = %lu", + (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); + + /* The sequential reader needs a buffer for IDAT, but the progressive reader + * does not, so free the read buffer now regardless; the sequential reader + * reallocates it on demand. + */ + if (png_ptr->read_buffer) + { + png_bytep buffer = png_ptr->read_buffer; + + png_ptr->read_buffer_size = 0; + png_ptr->read_buffer = NULL; + png_free(png_ptr, buffer); + } + + /* Finally claim the zstream for the inflate of the IDAT data, use the bits + * value from the stream (note that this will result in a fatal error if the + * IDAT stream has a bogus deflate header window_bits value, but this should + * not be happening any longer!) + */ + if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + png_ptr->flags |= PNG_FLAG_ROW_INIT; +} +#endif /* PNG_READ_SUPPORTED */ +#endif diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngset.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngset.c new file mode 100644 index 0000000000..8fd7445f2f --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngset.c @@ -0,0 +1,1598 @@ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +/* pngset.c - storage of image information into info struct + * + * Last changed in libpng 1.6.3 [July 18, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * The functions here are used during reads to store data from the file + * into the info struct, and during writes to store application data + * into the info struct for writing into the file. This abstracts the + * info struct and allows us to change the structure in the future. + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +#ifdef PNG_bKGD_SUPPORTED +void PNGAPI +png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_color_16p background) +{ + png_debug1(1, "in %s storage function", "bKGD"); + + if (png_ptr == NULL || info_ptr == NULL || background == NULL) + return; + + info_ptr->background = *background; + info_ptr->valid |= PNG_INFO_bKGD; +} +#endif + +#ifdef PNG_cHRM_SUPPORTED +void PNGFAPI +png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, + png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, + png_fixed_point blue_x, png_fixed_point blue_y) +{ + png_xy xy; + + png_debug1(1, "in %s storage function", "cHRM fixed"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + xy.redx = red_x; + xy.redy = red_y; + xy.greenx = green_x; + xy.greeny = green_y; + xy.bluex = blue_x; + xy.bluey = blue_y; + xy.whitex = white_x; + xy.whitey = white_y; + + if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy, + 2/* override with app values*/)) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + + png_colorspace_sync_info(png_ptr, info_ptr); +} + +void PNGFAPI +png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z) +{ + png_XYZ XYZ; + + png_debug1(1, "in %s storage function", "cHRM XYZ fixed"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + XYZ.red_X = int_red_X; + XYZ.red_Y = int_red_Y; + XYZ.red_Z = int_red_Z; + XYZ.green_X = int_green_X; + XYZ.green_Y = int_green_Y; + XYZ.green_Z = int_green_Z; + XYZ.blue_X = int_blue_X; + XYZ.blue_Y = int_blue_Y; + XYZ.blue_Z = int_blue_Z; + + if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, &XYZ, 2)) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + + png_colorspace_sync_info(png_ptr, info_ptr); +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, + double white_x, double white_y, double red_x, double red_y, + double green_x, double green_y, double blue_x, double blue_y) +{ + png_set_cHRM_fixed(png_ptr, info_ptr, + png_fixed(png_ptr, white_x, "cHRM White X"), + png_fixed(png_ptr, white_y, "cHRM White Y"), + png_fixed(png_ptr, red_x, "cHRM Red X"), + png_fixed(png_ptr, red_y, "cHRM Red Y"), + png_fixed(png_ptr, green_x, "cHRM Green X"), + png_fixed(png_ptr, green_y, "cHRM Green Y"), + png_fixed(png_ptr, blue_x, "cHRM Blue X"), + png_fixed(png_ptr, blue_y, "cHRM Blue Y")); +} + +void PNGAPI +png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, + double red_Y, double red_Z, double green_X, double green_Y, double green_Z, + double blue_X, double blue_Y, double blue_Z) +{ + png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, + png_fixed(png_ptr, red_X, "cHRM Red X"), + png_fixed(png_ptr, red_Y, "cHRM Red Y"), + png_fixed(png_ptr, red_Z, "cHRM Red Z"), + png_fixed(png_ptr, green_X, "cHRM Red X"), + png_fixed(png_ptr, green_Y, "cHRM Red Y"), + png_fixed(png_ptr, green_Z, "cHRM Red Z"), + png_fixed(png_ptr, blue_X, "cHRM Red X"), + png_fixed(png_ptr, blue_Y, "cHRM Red Y"), + png_fixed(png_ptr, blue_Z, "cHRM Red Z")); +} +# endif /* PNG_FLOATING_POINT_SUPPORTED */ + +#endif /* PNG_cHRM_SUPPORTED */ + +#ifdef PNG_gAMA_SUPPORTED +void PNGFAPI +png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point file_gamma) +{ + png_debug1(1, "in %s storage function", "gAMA"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma); + png_colorspace_sync_info(png_ptr, info_ptr); +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma) +{ + png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma, + "png_set_gAMA")); +} +# endif +#endif + +#ifdef PNG_hIST_SUPPORTED +void PNGAPI +png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_uint_16p hist) +{ + int i; + + png_debug1(1, "in %s storage function", "hIST"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (info_ptr->num_palette == 0 || info_ptr->num_palette + > PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, + "Invalid palette size, hIST allocation skipped"); + + return; + } + + png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); + + /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in + * version 1.2.1 + */ + info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16)))); + + if (info_ptr->hist == NULL) + { + png_warning(png_ptr, "Insufficient memory for hIST chunk data"); + return; + } + + info_ptr->free_me |= PNG_FREE_HIST; + + for (i = 0; i < info_ptr->num_palette; i++) + info_ptr->hist[i] = hist[i]; + + info_ptr->valid |= PNG_INFO_hIST; +} +#endif + +void PNGAPI +png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + png_debug1(1, "in %s storage function", "IHDR"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->width = width; + info_ptr->height = height; + info_ptr->bit_depth = (png_byte)bit_depth; + info_ptr->color_type = (png_byte)color_type; + info_ptr->compression_type = (png_byte)compression_type; + info_ptr->filter_type = (png_byte)filter_type; + info_ptr->interlace_type = (png_byte)interlace_type; + + png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, + info_ptr->compression_type, info_ptr->filter_type); + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_ptr->channels = 3; + + else + info_ptr->channels = 1; + + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + info_ptr->channels++; + + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); + + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); +} + +#ifdef PNG_oFFs_SUPPORTED +void PNGAPI +png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr, + png_int_32 offset_x, png_int_32 offset_y, int unit_type) +{ + png_debug1(1, "in %s storage function", "oFFs"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_offset = offset_x; + info_ptr->y_offset = offset_y; + info_ptr->offset_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_oFFs; +} +#endif + +#ifdef PNG_pCAL_SUPPORTED +void PNGAPI +png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, + int nparams, png_const_charp units, png_charpp params) +{ + png_size_t length; + int i; + + png_debug1(1, "in %s storage function", "pCAL"); + + if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL + || (nparams > 0 && params == NULL)) + return; + + length = strlen(purpose) + 1; + png_debug1(3, "allocating purpose for info (%lu bytes)", + (unsigned long)length); + + /* TODO: validate format of calibration name and unit name */ + + /* Check that the type matches the specification. */ + if (type < 0 || type > 3) + png_error(png_ptr, "Invalid pCAL equation type"); + + if (nparams < 0 || nparams > 255) + png_error(png_ptr, "Invalid pCAL parameter count"); + + /* Validate params[nparams] */ + for (i=0; ipcal_purpose = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); + + if (info_ptr->pcal_purpose == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL purpose"); + return; + } + + memcpy(info_ptr->pcal_purpose, purpose, length); + + png_debug(3, "storing X0, X1, type, and nparams in info"); + info_ptr->pcal_X0 = X0; + info_ptr->pcal_X1 = X1; + info_ptr->pcal_type = (png_byte)type; + info_ptr->pcal_nparams = (png_byte)nparams; + + length = strlen(units) + 1; + png_debug1(3, "allocating units for info (%lu bytes)", + (unsigned long)length); + + info_ptr->pcal_units = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); + + if (info_ptr->pcal_units == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL units"); + return; + } + + memcpy(info_ptr->pcal_units, units, length); + + info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + (png_size_t)((nparams + 1) * (sizeof (png_charp))))); + + if (info_ptr->pcal_params == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL params"); + return; + } + + memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp))); + + for (i = 0; i < nparams; i++) + { + length = strlen(params[i]) + 1; + png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, + (unsigned long)length); + + info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length); + + if (info_ptr->pcal_params[i] == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL parameter"); + return; + } + + memcpy(info_ptr->pcal_params[i], params[i], length); + } + + info_ptr->valid |= PNG_INFO_pCAL; + info_ptr->free_me |= PNG_FREE_PCAL; +} +#endif + +#ifdef PNG_sCAL_SUPPORTED +void PNGAPI +png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, + int unit, png_const_charp swidth, png_const_charp sheight) +{ + png_size_t lengthw = 0, lengthh = 0; + + png_debug1(1, "in %s storage function", "sCAL"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Double check the unit (should never get here with an invalid + * unit unless this is an API call.) + */ + if (unit != 1 && unit != 2) + png_error(png_ptr, "Invalid sCAL unit"); + + if (swidth == NULL || (lengthw = strlen(swidth)) == 0 || + swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw)) + png_error(png_ptr, "Invalid sCAL width"); + + if (sheight == NULL || (lengthh = strlen(sheight)) == 0 || + sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh)) + png_error(png_ptr, "Invalid sCAL height"); + + info_ptr->scal_unit = (png_byte)unit; + + ++lengthw; + + png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw); + + info_ptr->scal_s_width = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthw)); + + if (info_ptr->scal_s_width == NULL) + { + png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + return; + } + + memcpy(info_ptr->scal_s_width, swidth, lengthw); + + ++lengthh; + + png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh); + + info_ptr->scal_s_height = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthh)); + + if (info_ptr->scal_s_height == NULL) + { + png_free (png_ptr, info_ptr->scal_s_width); + info_ptr->scal_s_width = NULL; + + png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + return; + } + + memcpy(info_ptr->scal_s_height, sheight, lengthh); + + info_ptr->valid |= PNG_INFO_sCAL; + info_ptr->free_me |= PNG_FREE_SCAL; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit, + double width, double height) +{ + png_debug1(1, "in %s storage function", "sCAL"); + + /* Check the arguments. */ + if (width <= 0) + png_warning(png_ptr, "Invalid sCAL width ignored"); + + else if (height <= 0) + png_warning(png_ptr, "Invalid sCAL height ignored"); + + else + { + /* Convert 'width' and 'height' to ASCII. */ + char swidth[PNG_sCAL_MAX_DIGITS+1]; + char sheight[PNG_sCAL_MAX_DIGITS+1]; + + png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width, + PNG_sCAL_PRECISION); + png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height, + PNG_sCAL_PRECISION); + + png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); + } +} +# endif + +# ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit, + png_fixed_point width, png_fixed_point height) +{ + png_debug1(1, "in %s storage function", "sCAL"); + + /* Check the arguments. */ + if (width <= 0) + png_warning(png_ptr, "Invalid sCAL width ignored"); + + else if (height <= 0) + png_warning(png_ptr, "Invalid sCAL height ignored"); + + else + { + /* Convert 'width' and 'height' to ASCII. */ + char swidth[PNG_sCAL_MAX_DIGITS+1]; + char sheight[PNG_sCAL_MAX_DIGITS+1]; + + png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width); + png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height); + + png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); + } +} +# endif +#endif + +#ifdef PNG_pHYs_SUPPORTED +void PNGAPI +png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_32 res_x, png_uint_32 res_y, int unit_type) +{ + png_debug1(1, "in %s storage function", "pHYs"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_pixels_per_unit = res_x; + info_ptr->y_pixels_per_unit = res_y; + info_ptr->phys_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_pHYs; +} +#endif + +void PNGAPI +png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, + png_const_colorp palette, int num_palette) +{ + + png_debug1(1, "in %s storage function", "PLTE"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Invalid palette length"); + + else + { + png_warning(png_ptr, "Invalid palette length"); + return; + } + } + + if ((num_palette > 0 && palette == NULL) || + (num_palette == 0 +# ifdef PNG_MNG_FEATURES_SUPPORTED + && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 +# endif + )) + { + png_chunk_report(png_ptr, "Invalid palette", PNG_CHUNK_ERROR); + return; + } + + /* It may not actually be necessary to set png_ptr->palette here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + * + * 1.6.0: the above statement appears to be incorrect; something has to set + * the palette inside png_struct on read. + */ + png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); + + /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead + * of num_palette entries, in case of an invalid PNG file that has + * too-large sample values. + */ + png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); + + if (num_palette > 0) + memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color))); + info_ptr->palette = png_ptr->palette; + info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; + + info_ptr->free_me |= PNG_FREE_PLTE; + + info_ptr->valid |= PNG_INFO_PLTE; +} + +#ifdef PNG_sBIT_SUPPORTED +void PNGAPI +png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_color_8p sig_bit) +{ + png_debug1(1, "in %s storage function", "sBIT"); + + if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL) + return; + + info_ptr->sig_bit = *sig_bit; + info_ptr->valid |= PNG_INFO_sBIT; +} +#endif + +#ifdef PNG_sRGB_SUPPORTED +void PNGAPI +png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) +{ + png_debug1(1, "in %s storage function", "sRGB"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent); + png_colorspace_sync_info(png_ptr, info_ptr); +} + +void PNGAPI +png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, + int srgb_intent) +{ + png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent)) + { + /* This causes the gAMA and cHRM to be written too */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } + + png_colorspace_sync_info(png_ptr, info_ptr); +} +#endif /* sRGB */ + + +#ifdef PNG_iCCP_SUPPORTED +void PNGAPI +png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_charp name, int compression_type, + png_const_bytep profile, png_uint_32 proflen) +{ + png_charp new_iccp_name; + png_bytep new_iccp_profile; + png_size_t length; + + png_debug1(1, "in %s storage function", "iCCP"); + + if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) + return; + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_app_error(png_ptr, "Invalid iCCP compression method"); + + /* Set the colorspace first because this validates the profile; do not + * override previously set app cHRM or gAMA here (because likely as not the + * application knows better than libpng what the correct values are.) Pass + * the info_ptr color_type field to png_colorspace_set_ICC because in the + * write case it has not yet been stored in png_ptr. + */ + { + int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name, + proflen, profile, info_ptr->color_type); + + png_colorspace_sync_info(png_ptr, info_ptr); + + /* Don't do any of the copying if the profile was bad, or inconsistent. */ + if (!result) + return; + + /* But do write the gAMA and cHRM chunks from the profile. */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } + + length = strlen(name)+1; + new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); + + if (new_iccp_name == NULL) + { + png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); + return; + } + + memcpy(new_iccp_name, name, length); + new_iccp_profile = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, proflen)); + + if (new_iccp_profile == NULL) + { + png_free(png_ptr, new_iccp_name); + png_benign_error(png_ptr, + "Insufficient memory to process iCCP profile"); + return; + } + + memcpy(new_iccp_profile, profile, proflen); + + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); + + info_ptr->iccp_proflen = proflen; + info_ptr->iccp_name = new_iccp_name; + info_ptr->iccp_profile = new_iccp_profile; + info_ptr->free_me |= PNG_FREE_ICCP; + info_ptr->valid |= PNG_INFO_iCCP; +} +#endif + +#ifdef PNG_TEXT_SUPPORTED +void PNGAPI +png_set_text(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_textp text_ptr, int num_text) +{ + int ret; + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); + + if (ret) + png_error(png_ptr, "Insufficient memory to store text"); +} + +int /* PRIVATE */ +png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_textp text_ptr, int num_text) +{ + int i; + + png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" : + (unsigned long)png_ptr->chunk_name); + + if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL) + return(0); + + /* Make sure we have enough space in the "text" array in info_struct + * to hold all of the incoming text_ptr objects. This compare can't overflow + * because max_text >= num_text (anyway, subtract of two positive integers + * can't overflow in any case.) + */ + if (num_text > info_ptr->max_text - info_ptr->num_text) + { + int old_num_text = info_ptr->num_text; + int max_text; + png_textp new_text = NULL; + + /* Calculate an appropriate max_text, checking for overflow. */ + max_text = old_num_text; + if (num_text <= INT_MAX - max_text) + { + max_text += num_text; + + /* Round up to a multiple of 8 */ + if (max_text < INT_MAX-8) + max_text = (max_text + 8) & ~0x7; + + else + max_text = INT_MAX; + + /* Now allocate a new array and copy the old members in, this does all + * the overflow checks. + */ + new_text = png_voidcast(png_textp,png_realloc_array(png_ptr, + info_ptr->text, old_num_text, max_text-old_num_text, + sizeof *new_text)); + } + + if (new_text == NULL) + { + png_chunk_report(png_ptr, "too many text chunks", + PNG_CHUNK_WRITE_ERROR); + return 1; + } + + png_free(png_ptr, info_ptr->text); + + info_ptr->text = new_text; + info_ptr->free_me |= PNG_FREE_TEXT; + info_ptr->max_text = max_text; + /* num_text is adjusted below as the entries are copied in */ + + png_debug1(3, "allocated %d entries for info_ptr->text", max_text); + } + + for (i = 0; i < num_text; i++) + { + size_t text_length, key_len; + size_t lang_len, lang_key_len; + png_textp textp = &(info_ptr->text[info_ptr->num_text]); + + if (text_ptr[i].key == NULL) + continue; + + if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE || + text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST) + { + png_chunk_report(png_ptr, "text compression mode is out of range", + PNG_CHUNK_WRITE_ERROR); + continue; + } + + key_len = strlen(text_ptr[i].key); + + if (text_ptr[i].compression <= 0) + { + lang_len = 0; + lang_key_len = 0; + } + + else +# ifdef PNG_iTXt_SUPPORTED + { + /* Set iTXt data */ + + if (text_ptr[i].lang != NULL) + lang_len = strlen(text_ptr[i].lang); + + else + lang_len = 0; + + if (text_ptr[i].lang_key != NULL) + lang_key_len = strlen(text_ptr[i].lang_key); + + else + lang_key_len = 0; + } +# else /* PNG_iTXt_SUPPORTED */ + { + png_chunk_report(png_ptr, "iTXt chunk not supported", + PNG_CHUNK_WRITE_ERROR); + continue; + } +# endif + + if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') + { + text_length = 0; +# ifdef PNG_iTXt_SUPPORTED + if (text_ptr[i].compression > 0) + textp->compression = PNG_ITXT_COMPRESSION_NONE; + + else +# endif + textp->compression = PNG_TEXT_COMPRESSION_NONE; + } + + else + { + text_length = strlen(text_ptr[i].text); + textp->compression = text_ptr[i].compression; + } + + textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr, + key_len + text_length + lang_len + lang_key_len + 4)); + + if (textp->key == NULL) + { + png_chunk_report(png_ptr, "text chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + return 1; + } + + png_debug2(2, "Allocated %lu bytes at %p in png_set_text", + (unsigned long)(png_uint_32) + (key_len + lang_len + lang_key_len + text_length + 4), + textp->key); + + memcpy(textp->key, text_ptr[i].key, key_len); + *(textp->key + key_len) = '\0'; + + if (text_ptr[i].compression > 0) + { + textp->lang = textp->key + key_len + 1; + memcpy(textp->lang, text_ptr[i].lang, lang_len); + *(textp->lang + lang_len) = '\0'; + textp->lang_key = textp->lang + lang_len + 1; + memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); + *(textp->lang_key + lang_key_len) = '\0'; + textp->text = textp->lang_key + lang_key_len + 1; + } + + else + { + textp->lang=NULL; + textp->lang_key=NULL; + textp->text = textp->key + key_len + 1; + } + + if (text_length) + memcpy(textp->text, text_ptr[i].text, text_length); + + *(textp->text + text_length) = '\0'; + +# ifdef PNG_iTXt_SUPPORTED + if (textp->compression > 0) + { + textp->text_length = 0; + textp->itxt_length = text_length; + } + + else +# endif + { + textp->text_length = text_length; + textp->itxt_length = 0; + } + + info_ptr->num_text++; + png_debug1(3, "transferred text chunk %d", info_ptr->num_text); + } + + return(0); +} +#endif + +#ifdef PNG_tIME_SUPPORTED +void PNGAPI +png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_timep mod_time) +{ + png_debug1(1, "in %s storage function", "tIME"); + + if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL || + (png_ptr->mode & PNG_WROTE_tIME)) + return; + + if (mod_time->month == 0 || mod_time->month > 12 || + mod_time->day == 0 || mod_time->day > 31 || + mod_time->hour > 23 || mod_time->minute > 59 || + mod_time->second > 60) + { + png_warning(png_ptr, "Ignoring invalid time value"); + return; + } + + info_ptr->mod_time = *mod_time; + info_ptr->valid |= PNG_INFO_tIME; +} +#endif + +#ifdef PNG_tRNS_SUPPORTED +void PNGAPI +png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, + png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color) +{ + png_debug1(1, "in %s storage function", "tRNS"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (trans_alpha != NULL) + { + /* It may not actually be necessary to set png_ptr->trans_alpha here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + * + * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively + * relies on png_set_tRNS storing the information in png_struct + * (otherwise it won't be there for the code in pngrtran.c). + */ + + png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); + + /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ + png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep, + png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); + + if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) + memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); + } + + if (trans_color != NULL) + { + int sample_max = (1 << info_ptr->bit_depth); + + if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && + trans_color->gray > sample_max) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + (trans_color->red > sample_max || + trans_color->green > sample_max || + trans_color->blue > sample_max))) + png_warning(png_ptr, + "tRNS chunk has out-of-range samples for bit_depth"); + + info_ptr->trans_color = *trans_color; + + if (num_trans == 0) + num_trans = 1; + } + + info_ptr->num_trans = (png_uint_16)num_trans; + + if (num_trans != 0) + { + info_ptr->valid |= PNG_INFO_tRNS; + info_ptr->free_me |= PNG_FREE_TRNS; + } +} +#endif + +#ifdef PNG_sPLT_SUPPORTED +void PNGAPI +png_set_sPLT(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries) +/* + * entries - array of png_sPLT_t structures + * to be added to the list of palettes + * in the info structure. + * + * nentries - number of palette structures to be + * added. + */ +{ + png_sPLT_tp np; + + if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL) + return; + + /* Use the internal realloc function, which checks for all the possible + * overflows. Notice that the parameters are (int) and (size_t) + */ + np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr, + info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, + sizeof *np)); + + if (np == NULL) + { + /* Out of memory or too many chunks */ + png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR); + return; + } + + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = np; + info_ptr->free_me |= PNG_FREE_SPLT; + + np += info_ptr->splt_palettes_num; + + do + { + png_size_t length; + + /* Skip invalid input entries */ + if (entries->name == NULL || entries->entries == NULL) + { + /* png_handle_sPLT doesn't do this, so this is an app error */ + png_app_error(png_ptr, "png_set_sPLT: invalid sPLT"); + /* Just skip the invalid entry */ + continue; + } + + np->depth = entries->depth; + + /* In the even of out-of-memory just return - there's no point keeping on + * trying to add sPLT chunks. + */ + length = strlen(entries->name) + 1; + np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length)); + + if (np->name == NULL) + break; + + memcpy(np->name, entries->name, length); + + /* IMPORTANT: we have memory now that won't get freed if something else + * goes wrong, this code must free it. png_malloc_array produces no + * warnings, use a png_chunk_report (below) if there is an error. + */ + np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr, + entries->nentries, sizeof (png_sPLT_entry))); + + if (np->entries == NULL) + { + png_free(png_ptr, np->name); + break; + } + + np->nentries = entries->nentries; + /* This multiply can't overflow because png_malloc_array has already + * checked it when doing the allocation. + */ + memcpy(np->entries, entries->entries, + entries->nentries * sizeof (png_sPLT_entry)); + + /* Note that 'continue' skips the advance of the out pointer and out + * count, so an invalid entry is not added. + */ + info_ptr->valid |= PNG_INFO_sPLT; + ++(info_ptr->splt_palettes_num); + ++np; + } + while (++entries, --nentries); + + if (nentries > 0) + png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); +} +#endif /* PNG_sPLT_SUPPORTED */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +static png_byte +check_location(png_const_structrp png_ptr, int location) +{ + location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT); + + /* New in 1.6.0; copy the location and check it. This is an API + * change, previously the app had to use the + * png_set_unknown_chunk_location API below for each chunk. + */ + if (location == 0 && !(png_ptr->mode & PNG_IS_READ_STRUCT)) + { + /* Write struct, so unknown chunks come from the app */ + png_app_warning(png_ptr, + "png_set_unknown_chunks now expects a valid location"); + /* Use the old behavior */ + location = (png_byte)(png_ptr->mode & + (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)); + } + + /* This need not be an internal error - if the app calls + * png_set_unknown_chunks on a read pointer it must get the location right. + */ + if (location == 0) + png_error(png_ptr, "invalid location in png_set_unknown_chunks"); + + /* Now reduce the location to the top-most set bit by removing each least + * significant bit in turn. + */ + while (location != (location & -location)) + location &= ~(location & -location); + + /* The cast is safe because 'location' is a bit mask and only the low four + * bits are significant. + */ + return (png_byte)location; +} + +void PNGAPI +png_set_unknown_chunks(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) +{ + png_unknown_chunkp np; + + if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || + unknowns == NULL) + return; + + /* Check for the failure cases where support has been disabled at compile + * time. This code is hardly ever compiled - it's here because + * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this + * code) but may be meaningless if the read or write handling of unknown + * chunks is not compiled in. + */ +# if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_READ_SUPPORTED) + if (png_ptr->mode & PNG_IS_READ_STRUCT) + { + png_app_error(png_ptr, "no unknown chunk support on read"); + return; + } +# endif +# if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_WRITE_SUPPORTED) + if (!(png_ptr->mode & PNG_IS_READ_STRUCT)) + { + png_app_error(png_ptr, "no unknown chunk support on write"); + return; + } +# endif + + /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that + * unknown critical chunks could be lost with just a warning resulting in + * undefined behavior. Now png_chunk_report is used to provide behavior + * appropriate to read or write. + */ + np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr, + info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, + sizeof *np)); + + if (np == NULL) + { + png_chunk_report(png_ptr, "too many unknown chunks", + PNG_CHUNK_WRITE_ERROR); + return; + } + + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = np; /* safe because it is initialized */ + info_ptr->free_me |= PNG_FREE_UNKN; + + np += info_ptr->unknown_chunks_num; + + /* Increment unknown_chunks_num each time round the loop to protect the + * just-allocated chunk data. + */ + for (; num_unknowns > 0; --num_unknowns, ++unknowns) + { + memcpy(np->name, unknowns->name, (sizeof np->name)); + np->name[(sizeof np->name)-1] = '\0'; + np->location = check_location(png_ptr, unknowns->location); + + if (unknowns->size == 0) + { + np->data = NULL; + np->size = 0; + } + + else + { + np->data = png_voidcast(png_bytep, + png_malloc_base(png_ptr, unknowns->size)); + + if (np->data == NULL) + { + png_chunk_report(png_ptr, "unknown chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + /* But just skip storing the unknown chunk */ + continue; + } + + memcpy(np->data, unknowns->data, unknowns->size); + np->size = unknowns->size; + } + + /* These increments are skipped on out-of-memory for the data - the + * unknown chunk entry gets overwritten if the png_chunk_report returns. + * This is correct in the read case (the chunk is just dropped.) + */ + ++np; + ++(info_ptr->unknown_chunks_num); + } +} + +void PNGAPI +png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, + int chunk, int location) +{ + /* This API is pretty pointless in 1.6.0 because the location can be set + * before the call to png_set_unknown_chunks. + * + * TODO: add a png_app_warning in 1.7 + */ + if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && + chunk < info_ptr->unknown_chunks_num) + { + if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0) + { + png_app_error(png_ptr, "invalid unknown chunk location"); + /* Fake out the pre 1.6.0 behavior: */ + if ((location & PNG_HAVE_IDAT)) /* undocumented! */ + location = PNG_AFTER_IDAT; + + else + location = PNG_HAVE_IHDR; /* also undocumented */ + } + + info_ptr->unknown_chunks[chunk].location = + check_location(png_ptr, location); + } +} +#endif + + +#ifdef PNG_MNG_FEATURES_SUPPORTED +png_uint_32 PNGAPI +png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features) +{ + png_debug(1, "in png_permit_mng_features"); + + if (png_ptr == NULL) + return 0; + + png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES; + + return png_ptr->mng_features_permitted; +} +#endif + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +static unsigned int +add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep) +{ + unsigned int i; + + /* Utility function: update the 'keep' state of a chunk if it is already in + * the list, otherwise add it to the list. + */ + for (i=0; i= PNG_HANDLE_CHUNK_LAST) + { + png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep"); + return; + } + + if (num_chunks_in <= 0) + { + png_ptr->unknown_default = keep; + + /* '0' means just set the flags, so stop here */ + if (num_chunks_in == 0) + return; + } + + if (num_chunks_in < 0) + { + /* Ignore all unknown chunks and all chunks recognized by + * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND + */ + static PNG_CONST png_byte chunks_to_ignore[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 99, 72, 82, 77, '\0', /* cHRM */ + 103, 65, 77, 65, '\0', /* gAMA */ + 104, 73, 83, 84, '\0', /* hIST */ + 105, 67, 67, 80, '\0', /* iCCP */ + 105, 84, 88, 116, '\0', /* iTXt */ + 111, 70, 70, 115, '\0', /* oFFs */ + 112, 67, 65, 76, '\0', /* pCAL */ + 112, 72, 89, 115, '\0', /* pHYs */ + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 67, 65, 76, '\0', /* sCAL */ + 115, 80, 76, 84, '\0', /* sPLT */ + 115, 84, 69, 82, '\0', /* sTER */ + 115, 82, 71, 66, '\0', /* sRGB */ + 116, 69, 88, 116, '\0', /* tEXt */ + 116, 73, 77, 69, '\0', /* tIME */ + 122, 84, 88, 116, '\0' /* zTXt */ + }; + + chunk_list = chunks_to_ignore; + num_chunks = (sizeof chunks_to_ignore)/5; + } + + else /* num_chunks_in > 0 */ + { + if (chunk_list == NULL) + { + /* Prior to 1.6.0 this was silently ignored, now it is an app_error + * which can be switched off. + */ + png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list"); + return; + } + + num_chunks = num_chunks_in; + } + + old_num_chunks = png_ptr->num_chunk_list; + if (png_ptr->chunk_list == NULL) + old_num_chunks = 0; + + /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow. + */ + if (num_chunks + old_num_chunks > UINT_MAX/5) + { + png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks"); + return; + } + + /* If these chunks are being reset to the default then no more memory is + * required because add_one_chunk above doesn't extend the list if the 'keep' + * parameter is the default. + */ + if (keep) + { + new_list = png_voidcast(png_bytep, png_malloc(png_ptr, + 5 * (num_chunks + old_num_chunks))); + + if (old_num_chunks > 0) + memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks); + } + + else if (old_num_chunks > 0) + new_list = png_ptr->chunk_list; + + else + new_list = NULL; + + /* Add the new chunks together with each one's handling code. If the chunk + * already exists the code is updated, otherwise the chunk is added to the + * end. (In libpng 1.6.0 order no longer matters because this code enforces + * the earlier convention that the last setting is the one that is used.) + */ + if (new_list != NULL) + { + png_const_bytep inlist; + png_bytep outlist; + unsigned int i; + + for (i=0; ichunk_list != new_list) + png_free(png_ptr, new_list); + + new_list = NULL; + } + } + + else + num_chunks = 0; + + png_ptr->num_chunk_list = num_chunks; + + if (png_ptr->chunk_list != new_list) + { + if (png_ptr->chunk_list != NULL) + png_free(png_ptr, png_ptr->chunk_list); + + png_ptr->chunk_list = new_list; + } +} +#endif + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +void PNGAPI +png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr, + png_user_chunk_ptr read_user_chunk_fn) +{ + png_debug(1, "in png_set_read_user_chunk_fn"); + + if (png_ptr == NULL) + return; + + png_ptr->read_user_chunk_fn = read_user_chunk_fn; + png_ptr->user_chunk_ptr = user_chunk_ptr; +} +#endif + +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytepp row_pointers) +{ + png_debug1(1, "in %s storage function", "rows"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers)) + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); + + info_ptr->row_pointers = row_pointers; + + if (row_pointers) + info_ptr->valid |= PNG_INFO_IDAT; +} +#endif + +void PNGAPI +png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size) +{ + if (png_ptr == NULL) + return; + + if (size == 0 || size > PNG_UINT_31_MAX) + png_error(png_ptr, "invalid compression buffer size"); + +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + if (png_ptr->mode & PNG_IS_READ_STRUCT) + { + png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */ + return; + } +# endif + +# ifdef PNG_WRITE_SUPPORTED + if (!(png_ptr->mode & PNG_IS_READ_STRUCT)) + { + if (png_ptr->zowner != 0) + { + png_warning(png_ptr, + "Compression buffer size cannot be changed because it is in use"); + return; + } + + if (size > ZLIB_IO_MAX) + { + png_warning(png_ptr, + "Compression buffer size limited to system maximum"); + size = ZLIB_IO_MAX; /* must fit */ + } + + else if (size < 6) + { + /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH + * if this is permitted. + */ + png_warning(png_ptr, + "Compression buffer size cannot be reduced below 6"); + return; + } + + if (png_ptr->zbuffer_size != size) + { + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); + png_ptr->zbuffer_size = (uInt)size; + } + } +# endif +} + +void PNGAPI +png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask) +{ + if (png_ptr && info_ptr) + info_ptr->valid &= ~mask; +} + + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* This function was added to libpng 1.2.6 */ +void PNGAPI +png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max, + png_uint_32 user_height_max) +{ + /* Images with dimensions larger than these limits will be + * rejected by png_set_IHDR(). To accept any PNG datastream + * regardless of dimensions, set both limits to 0x7ffffffL. + */ + if (png_ptr == NULL) + return; + + png_ptr->user_width_max = user_width_max; + png_ptr->user_height_max = user_height_max; +} + +/* This function was added to libpng 1.4.0 */ +void PNGAPI +png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max) +{ + if (png_ptr) + png_ptr->user_chunk_cache_max = user_chunk_cache_max; +} + +/* This function was added to libpng 1.4.1 */ +void PNGAPI +png_set_chunk_malloc_max (png_structrp png_ptr, + png_alloc_size_t user_chunk_malloc_max) +{ + if (png_ptr) + png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; +} +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ + + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_set_benign_errors(png_structrp png_ptr, int allowed) +{ + png_debug(1, "in png_set_benign_errors"); + + /* If allowed is 1, png_benign_error() is treated as a warning. + * + * If allowed is 0, png_benign_error() is treated as an error (which + * is the default behavior if png_set_benign_errors() is not called). + */ + + if (allowed) + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN; + + else + png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN); +} +#endif /* PNG_BENIGN_ERRORS_SUPPORTED */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Whether to report invalid palette index; added at libng-1.5.10. + * It is possible for an indexed (color-type==3) PNG file to contain + * pixels with invalid (out-of-range) indexes if the PLTE chunk has + * fewer entries than the image's bit-depth would allow. We recover + * from this gracefully by filling any incomplete palette with zeroes + * (opaque black). By default, when this occurs libpng will issue + * a benign error. This API can be used to override that behavior. + */ +void PNGAPI +png_set_check_for_invalid_index(png_structrp png_ptr, int allowed) +{ + png_debug(1, "in png_set_check_for_invalid_index"); + + if (allowed > 0) + png_ptr->num_palette_max = 0; + + else + png_ptr->num_palette_max = -1; +} +#endif +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngtrans.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngtrans.c new file mode 100644 index 0000000000..a46b0fc331 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngtrans.c @@ -0,0 +1,842 @@ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +/* pngtrans.c - transforms the data in a row (used by both readers and writers) + * + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Turn on BGR-to-RGB mapping */ +void PNGAPI +png_set_bgr(png_structrp png_ptr) +{ + png_debug(1, "in png_set_bgr"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_BGR; +} +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Turn on 16 bit byte swapping */ +void PNGAPI +png_set_swap(png_structrp png_ptr) +{ + png_debug(1, "in png_set_swap"); + + if (png_ptr == NULL) + return; + + if (png_ptr->bit_depth == 16) + png_ptr->transformations |= PNG_SWAP_BYTES; +} +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Turn on pixel packing */ +void PNGAPI +png_set_packing(png_structrp png_ptr) +{ + png_debug(1, "in png_set_packing"); + + if (png_ptr == NULL) + return; + + if (png_ptr->bit_depth < 8) + { + png_ptr->transformations |= PNG_PACK; + png_ptr->usr_bit_depth = 8; + } +} +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Turn on packed pixel swapping */ +void PNGAPI +png_set_packswap(png_structrp png_ptr) +{ + png_debug(1, "in png_set_packswap"); + + if (png_ptr == NULL) + return; + + if (png_ptr->bit_depth < 8) + png_ptr->transformations |= PNG_PACKSWAP; +} +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +void PNGAPI +png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits) +{ + png_debug(1, "in png_set_shift"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_SHIFT; + png_ptr->shift = *true_bits; +} +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +int PNGAPI +png_set_interlace_handling(png_structrp png_ptr) +{ + png_debug(1, "in png_set_interlace handling"); + + if (png_ptr && png_ptr->interlaced) + { + png_ptr->transformations |= PNG_INTERLACE; + return (7); + } + + return (1); +} +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte on read, or remove a filler or alpha byte on write. + * The filler type has changed in v0.95 to allow future 2-byte fillers + * for 48-bit input data, as well as to avoid problems with some compilers + * that don't like bytes as parameters. + */ +void PNGAPI +png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_filler"); + + if (png_ptr == NULL) + return; + + /* In libpng 1.6 it is possible to determine whether this is a read or write + * operation and therefore to do more checking here for a valid call. + */ + if (png_ptr->mode & PNG_IS_READ_STRUCT) + { +# ifdef PNG_READ_FILLER_SUPPORTED + /* On read png_set_filler is always valid, regardless of the base PNG + * format, because other transformations can give a format where the + * filler code can execute (basically an 8 or 16-bit component RGB or G + * format.) + * + * NOTE: usr_channels is not used by the read code! (This has led to + * confusion in the past.) The filler is only used in the read code. + */ + png_ptr->filler = (png_uint_16)filler; +# else + png_app_error(png_ptr, "png_set_filler not supported on read"); + PNG_UNUSED(filler) /* not used in the write case */ + return; +# endif + } + + else /* write */ + { +# ifdef PNG_WRITE_FILLER_SUPPORTED + /* On write the usr_channels parameter must be set correctly at the + * start to record the number of channels in the app-supplied data. + */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_RGB: + png_ptr->usr_channels = 4; + break; + + case PNG_COLOR_TYPE_GRAY: + if (png_ptr->bit_depth >= 8) + { + png_ptr->usr_channels = 2; + break; + } + + else + { + /* There simply isn't any code in libpng to strip out bits + * from bytes when the components are less than a byte in + * size! + */ + png_app_error(png_ptr, + "png_set_filler is invalid for low bit depth gray output"); + return; + } + + default: + png_app_error(png_ptr, + "png_set_filler: inappropriate color type"); + return; + } +# else + png_app_error(png_ptr, "png_set_filler not supported on write"); + return; +# endif + } + + /* Here on success - libpng supports the operation, set the transformation + * and the flag to say where the filler channel is. + */ + png_ptr->transformations |= PNG_FILLER; + + if (filler_loc == PNG_FILLER_AFTER) + png_ptr->flags |= PNG_FLAG_FILLER_AFTER; + + else + png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; +} + +/* Added to libpng-1.2.7 */ +void PNGAPI +png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_add_alpha"); + + if (png_ptr == NULL) + return; + + png_set_filler(png_ptr, filler, filler_loc); + /* The above may fail to do anything. */ + if (png_ptr->transformations & PNG_FILLER) + png_ptr->transformations |= PNG_ADD_ALPHA; +} + +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +void PNGAPI +png_set_swap_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_swap_alpha"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_SWAP_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +void PNGAPI +png_set_invert_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_invert_alpha"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_INVERT_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +void PNGAPI +png_set_invert_mono(png_structrp png_ptr) +{ + png_debug(1, "in png_set_invert_mono"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_INVERT_MONO; +} + +/* Invert monochrome grayscale data */ +void /* PRIVATE */ +png_do_invert(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_invert"); + + /* This test removed from libpng version 1.0.13 and 1.2.0: + * if (row_info->bit_depth == 1 && + */ + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + png_bytep rp = row; + png_size_t i; + png_size_t istop = row_info->rowbytes; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(~(*rp)); + rp++; + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 8) + { + png_bytep rp = row; + png_size_t i; + png_size_t istop = row_info->rowbytes; + + for (i = 0; i < istop; i += 2) + { + *rp = (png_byte)(~(*rp)); + rp += 2; + } + } + +#ifdef PNG_16BIT_SUPPORTED + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 16) + { + png_bytep rp = row; + png_size_t i; + png_size_t istop = row_info->rowbytes; + + for (i = 0; i < istop; i += 4) + { + *rp = (png_byte)(~(*rp)); + *(rp + 1) = (png_byte)(~(*(rp + 1))); + rp += 4; + } + } +#endif +} +#endif + +#ifdef PNG_16BIT_SUPPORTED +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swaps byte order on 16 bit depth images */ +void /* PRIVATE */ +png_do_swap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_swap"); + + if (row_info->bit_depth == 16) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop= row_info->width * row_info->channels; + + for (i = 0; i < istop; i++, rp += 2) + { + png_byte t = *rp; + *rp = *(rp + 1); + *(rp + 1) = t; + } + } +} +#endif +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +static PNG_CONST png_byte onebppswaptable[256] = { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, + 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, + 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, + 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, + 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, + 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, + 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, + 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, + 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, + 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, + 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF +}; + +static PNG_CONST png_byte twobppswaptable[256] = { + 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0, + 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0, + 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4, + 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4, + 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8, + 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, + 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC, + 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC, + 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1, + 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1, + 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5, + 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5, + 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9, + 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9, + 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD, + 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD, + 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2, + 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2, + 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6, + 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6, + 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA, + 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA, + 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE, + 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE, + 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3, + 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3, + 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7, + 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7, + 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB, + 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, + 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF, + 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF +}; + +static PNG_CONST png_byte fourbppswaptable[256] = { + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, + 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, + 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, + 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, + 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, + 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, + 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, + 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, + 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, + 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, + 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, + 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, + 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, + 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, + 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, + 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, + 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, + 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, + 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, + 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, + 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, + 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, + 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, + 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, + 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, + 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, + 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, + 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, + 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, + 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, + 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF +}; + +/* Swaps pixel packing order within bytes */ +void /* PRIVATE */ +png_do_packswap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_packswap"); + + if (row_info->bit_depth < 8) + { + png_bytep rp; + png_const_bytep end, table; + + end = row + row_info->rowbytes; + + if (row_info->bit_depth == 1) + table = onebppswaptable; + + else if (row_info->bit_depth == 2) + table = twobppswaptable; + + else if (row_info->bit_depth == 4) + table = fourbppswaptable; + + else + return; + + for (rp = row; rp < end; rp++) + *rp = table[*rp]; + } +} +#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +/* Remove a channel - this used to be 'png_do_strip_filler' but it used a + * somewhat weird combination of flags to determine what to do. All the calls + * to png_do_strip_filler are changed in 1.5.2 to call this instead with the + * correct arguments. + * + * The routine isn't general - the channel must be the channel at the start or + * end (not in the middle) of each pixel. + */ +void /* PRIVATE */ +png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) +{ + png_bytep sp = row; /* source pointer */ + png_bytep dp = row; /* destination pointer */ + png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */ + + /* At the start sp will point to the first byte to copy and dp to where + * it is copied to. ep always points just beyond the end of the row, so + * the loop simply copies (channels-1) channels until sp reaches ep. + * + * at_start: 0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc. + * nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc. + */ + + /* GA, GX, XG cases */ + if (row_info->channels == 2) + { + if (row_info->bit_depth == 8) + { + if (at_start) /* Skip initial filler */ + ++sp; + else /* Skip initial channel and, for sp, the filler */ + sp += 2, ++dp; + + /* For a 1 pixel wide image there is nothing to do */ + while (sp < ep) + *dp++ = *sp, sp += 2; + + row_info->pixel_depth = 8; + } + + else if (row_info->bit_depth == 16) + { + if (at_start) /* Skip initial filler */ + sp += 2; + else /* Skip initial channel and, for sp, the filler */ + sp += 4, dp += 2; + + while (sp < ep) + *dp++ = *sp++, *dp++ = *sp, sp += 3; + + row_info->pixel_depth = 16; + } + + else + return; /* bad bit depth */ + + row_info->channels = 1; + + /* Finally fix the color type if it records an alpha channel */ + if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + row_info->color_type = PNG_COLOR_TYPE_GRAY; + } + + /* RGBA, RGBX, XRGB cases */ + else if (row_info->channels == 4) + { + if (row_info->bit_depth == 8) + { + if (at_start) /* Skip initial filler */ + ++sp; + else /* Skip initial channels and, for sp, the filler */ + sp += 4, dp += 3; + + /* Note that the loop adds 3 to dp and 4 to sp each time. */ + while (sp < ep) + *dp++ = *sp++, *dp++ = *sp++, *dp++ = *sp, sp += 2; + + row_info->pixel_depth = 24; + } + + else if (row_info->bit_depth == 16) + { + if (at_start) /* Skip initial filler */ + sp += 2; + else /* Skip initial channels and, for sp, the filler */ + sp += 8, dp += 6; + + while (sp < ep) + { + /* Copy 6 bytes, skip 2 */ + *dp++ = *sp++, *dp++ = *sp++; + *dp++ = *sp++, *dp++ = *sp++; + *dp++ = *sp++, *dp++ = *sp, sp += 3; + } + + row_info->pixel_depth = 48; + } + + else + return; /* bad bit depth */ + + row_info->channels = 3; + + /* Finally fix the color type if it records an alpha channel */ + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + row_info->color_type = PNG_COLOR_TYPE_RGB; + } + + else + return; /* The filler channel has gone already */ + + /* Fix the rowbytes value. */ + row_info->rowbytes = dp-row; +} +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Swaps red and blue bytes within a pixel */ +void /* PRIVATE */ +png_do_bgr(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_bgr"); + + if ((row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 3) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 4) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + } + +#ifdef PNG_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 6) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 8) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + } +#endif + } +} +#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ + +#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ + defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) +/* Added at libpng-1.5.10 */ +void /* PRIVATE */ +png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) +{ + if (png_ptr->num_palette < (1 << row_info->bit_depth) && + png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */ + { + /* Calculations moved outside switch in an attempt to stop different + * compiler warnings. 'padding' is in *bits* within the last byte, it is + * an 'int' because pixel_depth becomes an 'int' in the expression below, + * and this calculation is used because it avoids warnings that other + * forms produced on either GCC or MSVC. + */ + int padding = (-row_info->pixel_depth * row_info->width) & 7; + png_bytep rp = png_ptr->row_buf + row_info->rowbytes; + + switch (row_info->bit_depth) + { + case 1: + { + /* in this case, all bytes must be 0 so we don't need + * to unpack the pixels except for the rightmost one. + */ + for (; rp > png_ptr->row_buf; rp--) + { + if (*rp >> padding != 0) + png_ptr->num_palette_max = 1; + padding = 0; + } + + break; + } + + case 2: + { + for (; rp > png_ptr->row_buf; rp--) + { + int i = ((*rp >> padding) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 2) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 4) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 6) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + padding = 0; + } + + break; + } + + case 4: + { + for (; rp > png_ptr->row_buf; rp--) + { + int i = ((*rp >> padding) & 0x0f); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 4) & 0x0f); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + padding = 0; + } + + break; + } + + case 8: + { + for (; rp > png_ptr->row_buf; rp--) + { + if (*rp > png_ptr->num_palette_max) + png_ptr->num_palette_max = (int) *rp; + } + + break; + } + + default: + break; + } + } +} +#endif /* PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +void PNGAPI +png_set_user_transform_info(png_structrp png_ptr, png_voidp + user_transform_ptr, int user_transform_depth, int user_transform_channels) +{ + png_debug(1, "in png_set_user_transform_info"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + (png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) + { + png_app_error(png_ptr, + "info change after png_start_read_image or png_read_update_info"); + return; + } +#endif + + png_ptr->user_transform_ptr = user_transform_ptr; + png_ptr->user_transform_depth = (png_byte)user_transform_depth; + png_ptr->user_transform_channels = (png_byte)user_transform_channels; +} +#endif + +/* This function returns a pointer to the user_transform_ptr associated with + * the user transform functions. The application should free any memory + * associated with this pointer before png_write_destroy and png_read_destroy + * are called. + */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +png_voidp PNGAPI +png_get_user_transform_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + + return png_ptr->user_transform_ptr; +} +#endif + +#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED +png_uint_32 PNGAPI +png_get_current_row_number(png_const_structrp png_ptr) +{ + /* See the comments in png.h - this is the sub-image row when reading and + * interlaced image. + */ + if (png_ptr != NULL) + return png_ptr->row_number; + + return PNG_UINT_32_MAX; /* help the app not to fail silently */ +} + +png_byte PNGAPI +png_get_current_pass_number(png_const_structrp png_ptr) +{ + if (png_ptr != NULL) + return png_ptr->pass; + return 8; /* invalid */ +} +#endif /* PNG_USER_TRANSFORM_INFO_SUPPORTED */ +#endif /* PNG_READ_USER_TRANSFORM_SUPPORTED || + PNG_WRITE_USER_TRANSFORM_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwio.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwio.c new file mode 100644 index 0000000000..5f3133e5d5 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwio.c @@ -0,0 +1,165 @@ + +/* pngwio.c - functions for data output + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all output. Users who need + * special handling are expected to write functions that have the same + * arguments as these and perform similar functions, but that possibly + * use different output methods. Note that you shouldn't change these + * functions, but rather write replacement functions and then change + * them at run time with png_set_write_fn(...). + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +#include "pngpriv.h" + +#ifdef PNG_WRITE_SUPPORTED + +/* Write the data to whatever output you are using. The default routine + * writes to a file pointer. Note that this routine sometimes gets called + * with very small lengths, so you should implement some kind of simple + * buffering if you are using unbuffered writes. This should never be asked + * to write more than 64K on a 16 bit machine. + */ + +void /* PRIVATE */ +png_write_data(png_structrp png_ptr, png_const_bytep data, png_size_t length) +{ + /* NOTE: write_data_fn must not change the buffer! */ + if (png_ptr->write_data_fn != NULL ) + (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data), + length); + + else + png_error(png_ptr, "Call to NULL write function"); +} + +#ifdef PNG_STDIO_SUPPORTED +/* This is the function that does the actual writing of data. If you are + * not writing to a standard C stream, you should create a replacement + * write_data function and use it at run time with png_set_write_fn(), rather + * than changing the library. + */ +void PNGCBAPI +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + if (png_ptr == NULL) + return; + + check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); + + if (check != length) + png_error(png_ptr, "Write Error"); +} +#endif + +/* This function is called to output any data pending writing (normally + * to disk). After png_flush is called, there should be no data pending + * writing in any buffers. + */ +#ifdef PNG_WRITE_FLUSH_SUPPORTED +void /* PRIVATE */ +png_flush(png_structrp png_ptr) +{ + if (png_ptr->output_flush_fn != NULL) + (*(png_ptr->output_flush_fn))(png_ptr); +} + +# ifdef PNG_STDIO_SUPPORTED +void PNGCBAPI +png_default_flush(png_structp png_ptr) +{ + png_FILE_p io_ptr; + + if (png_ptr == NULL) + return; + + io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr)); + fflush(io_ptr); +} +# endif +#endif + +/* This function allows the application to supply new output functions for + * libpng if standard C streams aren't being used. + * + * This function takes as its arguments: + * png_ptr - pointer to a png output data structure + * io_ptr - pointer to user supplied structure containing info about + * the output functions. May be NULL. + * write_data_fn - pointer to a new output function that takes as its + * arguments a pointer to a png_struct, a pointer to + * data to be written, and a 32-bit unsigned int that is + * the number of bytes to be written. The new write + * function should call png_error(png_ptr, "Error msg") + * to exit and output any fatal error messages. May be + * NULL, in which case libpng's default function will + * be used. + * flush_data_fn - pointer to a new flush function that takes as its + * arguments a pointer to a png_struct. After a call to + * the flush function, there should be no data in any buffers + * or pending transmission. If the output method doesn't do + * any buffering of output, a function prototype must still be + * supplied although it doesn't have to do anything. If + * PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile + * time, output_flush_fn will be ignored, although it must be + * supplied for compatibility. May be NULL, in which case + * libpng's default function will be used, if + * PNG_WRITE_FLUSH_SUPPORTED is defined. This is not + * a good idea if io_ptr does not point to a standard + * *FILE structure. + */ +void PNGAPI +png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = io_ptr; + +#ifdef PNG_STDIO_SUPPORTED + if (write_data_fn != NULL) + png_ptr->write_data_fn = write_data_fn; + + else + png_ptr->write_data_fn = png_default_write_data; +#else + png_ptr->write_data_fn = write_data_fn; +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_STDIO_SUPPORTED + + if (output_flush_fn != NULL) + png_ptr->output_flush_fn = output_flush_fn; + + else + png_ptr->output_flush_fn = png_default_flush; + +# else + png_ptr->output_flush_fn = output_flush_fn; +# endif +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + + /* It is an error to read while writing a png file */ + if (png_ptr->read_data_fn != NULL) + { + png_ptr->read_data_fn = NULL; + + png_warning(png_ptr, + "Can't set both read_data_fn and write_data_fn in the" + " same structure"); + } +} +#endif /* PNG_WRITE_SUPPORTED */ +#endif//_FPDFAPI_MINI_ diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwrite.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwrite.c new file mode 100644 index 0000000000..7efcfc3a26 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwrite.c @@ -0,0 +1,2331 @@ + +/* pngwrite.c - general routines to write a PNG file + * + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +#include "pngpriv.h" +#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +# include +#endif + +#ifdef PNG_WRITE_SUPPORTED + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +/* Write out all the unknown chunks for the current given location */ +static void +write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, + unsigned int where) +{ + if (info_ptr->unknown_chunks_num) + { + png_const_unknown_chunkp up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + ++up) + if (up->location & where) + { + /* If per-chunk unknown chunk handling is enabled use it, otherwise + * just write the chunks the application has set. + */ +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int keep = png_handle_as_unknown(png_ptr, up->name); + + /* NOTE: this code is radically different from the read side in the + * matter of handling an ancillary unknown chunk. In the read side + * the default behavior is to discard it, in the code below the default + * behavior is to write it. Critical chunks are, however, only + * written if explicitly listed or if the default is set to write all + * unknown chunks. + * + * The default handling is also slightly weird - it is not possible to + * stop the writing of all unsafe-to-copy chunks! + * + * TODO: REVIEW: this would seem to be a bug. + */ + if (keep != PNG_HANDLE_CHUNK_NEVER && + ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ || + keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_AS_DEFAULT && + png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS))) +#endif + { + /* TODO: review, what is wrong with a zero length unknown chunk? */ + if (up->size == 0) + png_warning(png_ptr, "Writing zero-length unknown chunk"); + + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +} +#endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */ + +/* Writes all the PNG information. This is the suggested way to use the + * library. If you have a new chunk to add, make a function to write it, + * and put it in the correct location here. If you want the chunk written + * after the image data, put it in png_write_end(). I strongly encourage + * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing + * the chunk, as that will keep the code from breaking if you want to just + * write a plain PNG file. If you have long comments, I suggest writing + * them in png_write_end(), and compressing them. + */ +void PNGAPI +png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) +{ + png_debug(1, "in png_write_info_before_PLTE"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + { + /* Write PNG signature */ + png_write_sig(png_ptr); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ + (png_ptr->mng_features_permitted)) + { + png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); + png_ptr->mng_features_permitted = 0; + } +#endif + + /* Write IHDR information. */ + png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, + info_ptr->filter_type, +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + info_ptr->interlace_type +#else + 0 +#endif + ); + + /* The rest of these check to see if the valid field has the appropriate + * flag set, and if it does, writes the chunk. + * + * 1.6.0: COLORSPACE support controls the writing of these chunks too, and + * the chunks will be written if the WRITE routine is there and information + * is available in the COLORSPACE. (See png_colorspace_sync_info in png.c + * for where the valid flags get set.) + * + * Under certain circumstances the colorspace can be invalidated without + * syncing the info_struct 'valid' flags; this happens if libpng detects and + * error and calls png_error while the color space is being set, yet the + * application continues writing the PNG. So check the 'invalid' flag here + * too. + */ +#ifdef PNG_GAMMA_SUPPORTED +# ifdef PNG_WRITE_gAMA_SUPPORTED + if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) && + (info_ptr->valid & PNG_INFO_gAMA)) + png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); +# endif +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED + /* Write only one of sRGB or an ICC profile. If a profile was supplied + * and it matches one of the known sRGB ones issue a warning. + */ +# ifdef PNG_WRITE_iCCP_SUPPORTED + if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && + (info_ptr->valid & PNG_INFO_iCCP)) + { +# ifdef PNG_WRITE_sRGB_SUPPORTED + if (info_ptr->valid & PNG_INFO_sRGB) + png_app_warning(png_ptr, + "profile matches sRGB but writing iCCP instead"); +# endif + + png_write_iCCP(png_ptr, info_ptr->iccp_name, + info_ptr->iccp_profile); + } +# ifdef PNG_WRITE_sRGB_SUPPORTED + else +# endif +# endif + +# ifdef PNG_WRITE_sRGB_SUPPORTED + if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && + (info_ptr->valid & PNG_INFO_sRGB)) + png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent); +# endif /* WRITE_sRGB */ +#endif /* COLORSPACE */ + +#ifdef PNG_WRITE_sBIT_SUPPORTED + if (info_ptr->valid & PNG_INFO_sBIT) + png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED +# ifdef PNG_WRITE_cHRM_SUPPORTED + if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) && + (info_ptr->valid & PNG_INFO_cHRM)) + png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy); +# endif +#endif + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); +#endif + + png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; + } +} + +void PNGAPI +png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) +{ +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) + int i; +#endif + + png_debug(1, "in png_write_info"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_write_info_before_PLTE(png_ptr, info_ptr); + + if (info_ptr->valid & PNG_INFO_PLTE) + png_write_PLTE(png_ptr, info_ptr->palette, + (png_uint_32)info_ptr->num_palette); + + else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Valid palette required for paletted images"); + +#ifdef PNG_WRITE_tRNS_SUPPORTED + if (info_ptr->valid & PNG_INFO_tRNS) + { +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel (in tRNS) */ + if ((png_ptr->transformations & PNG_INVERT_ALPHA) && + info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + int j; + for (j = 0; j<(int)info_ptr->num_trans; j++) + info_ptr->trans_alpha[j] = + (png_byte)(255 - info_ptr->trans_alpha[j]); + } +#endif + png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color), + info_ptr->num_trans, info_ptr->color_type); + } +#endif +#ifdef PNG_WRITE_bKGD_SUPPORTED + if (info_ptr->valid & PNG_INFO_bKGD) + png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED + if (info_ptr->valid & PNG_INFO_hIST) + png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED + if (info_ptr->valid & PNG_INFO_oFFs) + png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, + info_ptr->offset_unit_type); +#endif + +#ifdef PNG_WRITE_pCAL_SUPPORTED + if (info_ptr->valid & PNG_INFO_pCAL) + png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, + info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, + info_ptr->pcal_units, info_ptr->pcal_params); +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED + if (info_ptr->valid & PNG_INFO_sCAL) + png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_s_width, info_ptr->scal_s_height); +#endif /* sCAL */ + +#ifdef PNG_WRITE_pHYs_SUPPORTED + if (info_ptr->valid & PNG_INFO_pHYs) + png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, + info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); +#endif /* pHYs */ + +#ifdef PNG_WRITE_tIME_SUPPORTED + if (info_ptr->valid & PNG_INFO_tIME) + { + png_write_tIME(png_ptr, &(info_ptr->mod_time)); + png_ptr->mode |= PNG_WROTE_tIME; + } +#endif /* tIME */ + +#ifdef PNG_WRITE_sPLT_SUPPORTED + if (info_ptr->valid & PNG_INFO_sPLT) + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); +#endif /* sPLT */ + +#ifdef PNG_WRITE_TEXT_SUPPORTED + /* Check to see if we need to write text chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing header text chunk %d, type %d", i, + info_ptr->text[i].compression); + /* An internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#ifdef PNG_WRITE_iTXt_SUPPORTED + /* Write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); +#else + png_warning(png_ptr, "Unable to write international text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + + /* If we want a compressed text chunk */ + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) + { +#ifdef PNG_WRITE_zTXt_SUPPORTED + /* Write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); +#else + png_warning(png_ptr, "Unable to write compressed text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + } + + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#ifdef PNG_WRITE_tEXt_SUPPORTED + /* Write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, + 0); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; +#else + /* Can't get here */ + png_warning(png_ptr, "Unable to write uncompressed text"); +#endif + } + } +#endif /* tEXt */ + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE); +#endif +} + +/* Writes the end of the PNG file. If you don't want to write comments or + * time information, you can pass NULL for info. If you already wrote these + * in png_write_info(), do not write them again here. If you have long + * comments, I suggest writing them here, and compressing them. + */ +void PNGAPI +png_write_end(png_structrp png_ptr, png_inforp info_ptr) +{ + png_debug(1, "in png_write_end"); + + if (png_ptr == NULL) + return; + + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "No IDATs written into file"); + +#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED + if (png_ptr->num_palette_max > png_ptr->num_palette) + png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); +#endif + + /* See if user wants us to write information chunks */ + if (info_ptr != NULL) + { +#ifdef PNG_WRITE_TEXT_SUPPORTED + int i; /* local index variable */ +#endif +#ifdef PNG_WRITE_tIME_SUPPORTED + /* Check to see if user has supplied a time chunk */ + if ((info_ptr->valid & PNG_INFO_tIME) && + !(png_ptr->mode & PNG_WROTE_tIME)) + png_write_tIME(png_ptr, &(info_ptr->mod_time)); + +#endif +#ifdef PNG_WRITE_TEXT_SUPPORTED + /* Loop through comment chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing trailer text chunk %d, type %d", i, + info_ptr->text[i].compression); + /* An internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#ifdef PNG_WRITE_iTXt_SUPPORTED + /* Write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); +#else + png_warning(png_ptr, "Unable to write international text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + + else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) + { +#ifdef PNG_WRITE_zTXt_SUPPORTED + /* Write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); +#else + png_warning(png_ptr, "Unable to write compressed text"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + } + + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#ifdef PNG_WRITE_tEXt_SUPPORTED + /* Write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0); +#else + png_warning(png_ptr, "Unable to write uncompressed text"); +#endif + + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + } +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); +#endif + } + + png_ptr->mode |= PNG_AFTER_IDAT; + + /* Write end of PNG file */ + png_write_IEND(png_ptr); + /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, + * and restored again in libpng-1.2.30, may cause some applications that + * do not set png_ptr->output_flush_fn to crash. If your application + * experiences a problem, please try building libpng with + * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to + * png-mng-implement at lists.sf.net . + */ +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED + png_flush(png_ptr); +# endif +#endif +} + +#ifdef PNG_CONVERT_tIME_SUPPORTED +void PNGAPI +png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime) +{ + png_debug(1, "in png_convert_from_struct_tm"); + + ptime->year = (png_uint_16)(1900 + ttime->tm_year); + ptime->month = (png_byte)(ttime->tm_mon + 1); + ptime->day = (png_byte)ttime->tm_mday; + ptime->hour = (png_byte)ttime->tm_hour; + ptime->minute = (png_byte)ttime->tm_min; + ptime->second = (png_byte)ttime->tm_sec; +} + +void PNGAPI +png_convert_from_time_t(png_timep ptime, time_t ttime) +{ + struct tm *tbuf; + + png_debug(1, "in png_convert_from_time_t"); + + tbuf = gmtime(&ttime); + png_convert_from_struct_tm(ptime, tbuf); +} +#endif + +/* Initialize png_ptr structure, and allocate any memory needed */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) +{ +#ifndef PNG_USER_MEM_SUPPORTED + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, NULL, NULL, NULL); +#else + return png_create_write_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL); +} + +/* Alternate initialize png_ptr structure, and allocate any memory needed */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) +{ + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* PNG_USER_MEM_SUPPORTED */ + if (png_ptr != NULL) + { + /* Set the zlib control values to defaults; they can be overridden by the + * application after the struct has been created. + */ + png_ptr->zbuffer_size = PNG_ZBUF_SIZE; + + /* The 'zlib_strategy' setting is irrelevant because png_default_claim in + * pngwutil.c defaults it according to whether or not filters will be + * used, and ignores this setting. + */ + png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; + png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_mem_level = 8; + png_ptr->zlib_window_bits = 15; + png_ptr->zlib_method = 8; + +#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED + png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; + png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_text_mem_level = 8; + png_ptr->zlib_text_window_bits = 15; + png_ptr->zlib_text_method = 8; +#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ + + /* This is a highly dubious configuration option; by default it is off, + * but it may be appropriate for private builds that are testing + * extensions not conformant to the current specification, or of + * applications that must not fail to write at all costs! + */ +#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; + /* In stable builds only warn if an application error can be completely + * handled. + */ +#endif + + /* App warnings are warnings in release (or release candidate) builds but + * are errors during development. + */ +#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; +#endif + + /* TODO: delay this, it can be done in png_init_io() (if the app doesn't + * do it itself) avoiding setting the default function if it is not + * required. + */ + png_set_write_fn(png_ptr, NULL, NULL, NULL); + } + + return png_ptr; +} + + +/* Write a few rows of image data. If the image is interlaced, + * either you will have to write the 7 sub images, or, if you + * have called png_set_interlace_handling(), you will have to + * "write" the image seven times. + */ +void PNGAPI +png_write_rows(png_structrp png_ptr, png_bytepp row, + png_uint_32 num_rows) +{ + png_uint_32 i; /* row counter */ + png_bytepp rp; /* row pointer */ + + png_debug(1, "in png_write_rows"); + + if (png_ptr == NULL) + return; + + /* Loop through the rows */ + for (i = 0, rp = row; i < num_rows; i++, rp++) + { + png_write_row(png_ptr, *rp); + } +} + +/* Write the image. You only need to call this function once, even + * if you are writing an interlaced image. + */ +void PNGAPI +png_write_image(png_structrp png_ptr, png_bytepp image) +{ + png_uint_32 i; /* row index */ + int pass, num_pass; /* pass variables */ + png_bytepp rp; /* points to current row */ + + if (png_ptr == NULL) + return; + + png_debug(1, "in png_write_image"); + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Initialize interlace handling. If image is not interlaced, + * this will set pass to 1 + */ + num_pass = png_set_interlace_handling(png_ptr); +#else + num_pass = 1; +#endif + /* Loop through passes */ + for (pass = 0; pass < num_pass; pass++) + { + /* Loop through image */ + for (i = 0, rp = image; i < png_ptr->height; i++, rp++) + { + png_write_row(png_ptr, *rp); + } + } +} + +/* Called by user to write a row of image data */ +void PNGAPI +png_write_row(png_structrp png_ptr, png_const_bytep row) +{ + /* 1.5.6: moved from png_struct to be a local structure: */ + png_row_info row_info; + + if (png_ptr == NULL) + return; + + png_debug2(1, "in png_write_row (row %u, pass %d)", + png_ptr->row_number, png_ptr->pass); + + /* Initialize transformations and other stuff if first time */ + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* Make sure we wrote the header info */ + if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + png_error(png_ptr, + "png_write_info was never called before png_write_row"); + + /* Check for transforms that have been set but were defined out */ +#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined"); +#endif +#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ + defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_warning(png_ptr, + "PNG_WRITE_PACKSWAP_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); +#endif + + png_write_start_row(png_ptr); + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced and not interested in row, return */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 3: + if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 4: + if ((png_ptr->row_number & 0x03) != 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 5: + if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 6: + if (!(png_ptr->row_number & 0x01)) + { + png_write_finish_row(png_ptr); + return; + } + break; + + default: /* error: ignore it */ + break; + } + } +#endif + + /* Set up row info for transformations */ + row_info.color_type = png_ptr->color_type; + row_info.width = png_ptr->usr_width; + row_info.channels = png_ptr->usr_channels; + row_info.bit_depth = png_ptr->usr_bit_depth; + row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels); + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); + + png_debug1(3, "row_info->color_type = %d", row_info.color_type); + png_debug1(3, "row_info->width = %u", row_info.width); + png_debug1(3, "row_info->channels = %d", row_info.channels); + png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth); + png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth); + png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes); + + /* Copy user's row into buffer, leaving room for filter byte. */ + memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes); + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Handle interlacing */ + if (png_ptr->interlaced && png_ptr->pass < 6 && + (png_ptr->transformations & PNG_INTERLACE)) + { + png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); + /* This should always get caught above, but still ... */ + if (!(row_info.width)) + { + png_write_finish_row(png_ptr); + return; + } + } +#endif + +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED + /* Handle other transformations */ + if (png_ptr->transformations) + png_do_write_transformations(png_ptr, &row_info); +#endif + + /* At this point the row_info pixel depth must match the 'transformed' depth, + * which is also the output depth. + */ + if (row_info.pixel_depth != png_ptr->pixel_depth || + row_info.pixel_depth != png_ptr->transformed_pixel_depth) + png_error(png_ptr, "internal write transform logic error"); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1); + } +#endif + +/* Added at libpng-1.5.10 */ +#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Check for out-of-range palette index */ + if (row_info.color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, &row_info); +#endif + + /* Find a filter if necessary, filter the row and write it out. */ + png_write_find_filter(png_ptr, &row_info); + + if (png_ptr->write_row_fn != NULL) + (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); +} + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set the automatic flush interval or 0 to turn flushing off */ +void PNGAPI +png_set_flush(png_structrp png_ptr, int nrows) +{ + png_debug(1, "in png_set_flush"); + + if (png_ptr == NULL) + return; + + png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); +} + +/* Flush the current output buffers now */ +void PNGAPI +png_write_flush(png_structrp png_ptr) +{ + png_debug(1, "in png_write_flush"); + + if (png_ptr == NULL) + return; + + /* We have already written out all of the data */ + if (png_ptr->row_number >= png_ptr->num_rows) + return; + + png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH); + png_ptr->flush_rows = 0; + png_flush(png_ptr); +} +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +static void png_reset_filter_heuristics(png_structrp png_ptr);/* forward decl */ +#endif + +/* Free any memory used in png_ptr struct without freeing the struct itself. */ +static void +png_write_destroy(png_structrp png_ptr) +{ + png_debug(1, "in png_write_destroy"); + + /* Free any memory zlib uses */ + if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) + deflateEnd(&png_ptr->zstream); + + /* Free our memory. png_free checks NULL for us. */ + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); + png_free(png_ptr, png_ptr->row_buf); +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_free(png_ptr, png_ptr->prev_row); + png_free(png_ptr, png_ptr->sub_row); + png_free(png_ptr, png_ptr->up_row); + png_free(png_ptr, png_ptr->avg_row); + png_free(png_ptr, png_ptr->paeth_row); +#endif + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + /* Use this to save a little code space, it doesn't free the filter_costs */ + png_reset_filter_heuristics(png_ptr); + png_free(png_ptr, png_ptr->filter_costs); + png_free(png_ptr, png_ptr->inv_filter_costs); +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + png_free(png_ptr, png_ptr->chunk_list); +#endif + + /* The error handling and memory handling information is left intact at this + * point: the jmp_buf may still have to be freed. See png_destroy_png_struct + * for how this happens. + */ +} + +/* Free all memory used by the write. + * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for + * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free + * the passed in info_structs but it would quietly fail to free any of the data + * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it + * has no png_ptr.) + */ +void PNGAPI +png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) +{ + png_debug(1, "in png_destroy_write_struct"); + + if (png_ptr_ptr != NULL) + { + png_structrp png_ptr = *png_ptr_ptr; + + if (png_ptr != NULL) /* added in libpng 1.6.0 */ + { + png_destroy_info_struct(png_ptr, info_ptr_ptr); + + *png_ptr_ptr = NULL; + png_write_destroy(png_ptr); + png_destroy_png_struct(png_ptr); + } + } +} + +/* Allow the application to select one or more row filters to use. */ +void PNGAPI +png_set_filter(png_structrp png_ptr, int method, int filters) +{ + png_debug(1, "in png_set_filter"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (method == PNG_INTRAPIXEL_DIFFERENCING)) + method = PNG_FILTER_TYPE_BASE; + +#endif + if (method == PNG_FILTER_TYPE_BASE) + { + switch (filters & (PNG_ALL_FILTERS | 0x07)) + { +#ifdef PNG_WRITE_FILTER_SUPPORTED + case 5: + case 6: + case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); + /* FALL THROUGH */ +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + case PNG_FILTER_VALUE_NONE: + png_ptr->do_filter = PNG_FILTER_NONE; break; + +#ifdef PNG_WRITE_FILTER_SUPPORTED + case PNG_FILTER_VALUE_SUB: + png_ptr->do_filter = PNG_FILTER_SUB; break; + + case PNG_FILTER_VALUE_UP: + png_ptr->do_filter = PNG_FILTER_UP; break; + + case PNG_FILTER_VALUE_AVG: + png_ptr->do_filter = PNG_FILTER_AVG; break; + + case PNG_FILTER_VALUE_PAETH: + png_ptr->do_filter = PNG_FILTER_PAETH; break; + + default: + png_ptr->do_filter = (png_byte)filters; break; +#else + default: + png_app_error(png_ptr, "Unknown row filter for method 0"); +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + } + + /* If we have allocated the row_buf, this means we have already started + * with the image and we should have allocated all of the filter buffers + * that have been selected. If prev_row isn't already allocated, then + * it is too late to start using the filters that need it, since we + * will be missing the data in the previous row. If an application + * wants to start and stop using particular filters during compression, + * it should start out with all of the filters, and then add and + * remove them after the start of compression. + */ + if (png_ptr->row_buf != NULL) + { +#ifdef PNG_WRITE_FILTER_SUPPORTED + if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) + { + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; + } + + if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Up filter after starting"); + png_ptr->do_filter = (png_byte)(png_ptr->do_filter & + ~PNG_FILTER_UP); + } + + else + { + png_ptr->up_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } + } + + if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Average filter after starting"); + png_ptr->do_filter = (png_byte)(png_ptr->do_filter & + ~PNG_FILTER_AVG); + } + + else + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + } + + if ((png_ptr->do_filter & PNG_FILTER_PAETH) && + png_ptr->paeth_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Paeth filter after starting"); + png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); + } + + else + { + png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } + + if (png_ptr->do_filter == PNG_NO_FILTERS) +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + png_ptr->do_filter = PNG_FILTER_NONE; + } + } + else + png_error(png_ptr, "Unknown custom filter method"); +} + +/* This allows us to influence the way in which libpng chooses the "best" + * filter for the current scanline. While the "minimum-sum-of-absolute- + * differences metric is relatively fast and effective, there is some + * question as to whether it can be improved upon by trying to keep the + * filtered data going to zlib more consistent, hopefully resulting in + * better compression. + */ +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ +/* Convenience reset API. */ +static void +png_reset_filter_heuristics(png_structrp png_ptr) +{ + /* Clear out any old values in the 'weights' - this must be done because if + * the app calls set_filter_heuristics multiple times with different + * 'num_weights' values we would otherwise potentially have wrong sized + * arrays. + */ + png_ptr->num_prev_filters = 0; + png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; + if (png_ptr->prev_filters != NULL) + { + png_bytep old = png_ptr->prev_filters; + png_ptr->prev_filters = NULL; + png_free(png_ptr, old); + } + if (png_ptr->filter_weights != NULL) + { + png_uint_16p old = png_ptr->filter_weights; + png_ptr->filter_weights = NULL; + png_free(png_ptr, old); + } + + if (png_ptr->inv_filter_weights != NULL) + { + png_uint_16p old = png_ptr->inv_filter_weights; + png_ptr->inv_filter_weights = NULL; + png_free(png_ptr, old); + } + + /* Leave the filter_costs - this array is fixed size. */ +} + +static int +png_init_filter_heuristics(png_structrp png_ptr, int heuristic_method, + int num_weights) +{ + if (png_ptr == NULL) + return 0; + + /* Clear out the arrays */ + png_reset_filter_heuristics(png_ptr); + + /* Check arguments; the 'reset' function makes the correct settings for the + * unweighted case, but we must handle the weight case by initializing the + * arrays for the caller. + */ + if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int i; + + if (num_weights > 0) + { + png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, + (png_uint_32)((sizeof (png_byte)) * num_weights)); + + /* To make sure that the weighting starts out fairly */ + for (i = 0; i < num_weights; i++) + { + png_ptr->prev_filters[i] = 255; + } + + png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)((sizeof (png_uint_16)) * num_weights)); + + png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)((sizeof (png_uint_16)) * num_weights)); + + for (i = 0; i < num_weights; i++) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + + /* Safe to set this now */ + png_ptr->num_prev_filters = (png_byte)num_weights; + } + + /* If, in the future, there are other filter methods, this would + * need to be based on png_ptr->filter. + */ + if (png_ptr->filter_costs == NULL) + { + png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); + + png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); + } + + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + { + png_ptr->inv_filter_costs[i] = + png_ptr->filter_costs[i] = PNG_COST_FACTOR; + } + + /* All the arrays are inited, safe to set this: */ + png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_WEIGHTED; + + /* Return the 'ok' code. */ + return 1; + } + else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT || + heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) + { + return 1; + } + else + { + png_warning(png_ptr, "Unknown filter heuristic method"); + return 0; + } +} + +/* Provide floating and fixed point APIs */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, + int num_weights, png_const_doublep filter_weights, + png_const_doublep filter_costs) +{ + png_debug(1, "in png_set_filter_heuristics"); + + /* The internal API allocates all the arrays and ensures that the elements of + * those arrays are set to the default value. + */ + if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) + return; + + /* If using the weighted method copy in the weights. */ + if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int i; + for (i = 0; i < num_weights; i++) + { + if (filter_weights[i] <= 0.0) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + + else + { + png_ptr->inv_filter_weights[i] = + (png_uint_16)(PNG_WEIGHT_FACTOR*filter_weights[i]+.5); + + png_ptr->filter_weights[i] = + (png_uint_16)(PNG_WEIGHT_FACTOR/filter_weights[i]+.5); + } + } + + /* Here is where we set the relative costs of the different filters. We + * should take the desired compression level into account when setting + * the costs, so that Paeth, for instance, has a high relative cost at low + * compression levels, while it has a lower relative cost at higher + * compression settings. The filter types are in order of increasing + * relative cost, so it would be possible to do this with an algorithm. + */ + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) if (filter_costs[i] >= 1.0) + { + png_ptr->inv_filter_costs[i] = + (png_uint_16)(PNG_COST_FACTOR / filter_costs[i] + .5); + + png_ptr->filter_costs[i] = + (png_uint_16)(PNG_COST_FACTOR * filter_costs[i] + .5); + } + } +} +#endif /* FLOATING_POINT */ + +#ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, + int num_weights, png_const_fixed_point_p filter_weights, + png_const_fixed_point_p filter_costs) +{ + png_debug(1, "in png_set_filter_heuristics_fixed"); + + /* The internal API allocates all the arrays and ensures that the elements of + * those arrays are set to the default value. + */ + if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) + return; + + /* If using the weighted method copy in the weights. */ + if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int i; + for (i = 0; i < num_weights; i++) + { + if (filter_weights[i] <= 0) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + + else + { + png_ptr->inv_filter_weights[i] = (png_uint_16) + ((PNG_WEIGHT_FACTOR*filter_weights[i]+PNG_FP_HALF)/PNG_FP_1); + + png_ptr->filter_weights[i] = (png_uint_16)((PNG_WEIGHT_FACTOR* + PNG_FP_1+(filter_weights[i]/2))/filter_weights[i]); + } + } + + /* Here is where we set the relative costs of the different filters. We + * should take the desired compression level into account when setting + * the costs, so that Paeth, for instance, has a high relative cost at low + * compression levels, while it has a lower relative cost at higher + * compression settings. The filter types are in order of increasing + * relative cost, so it would be possible to do this with an algorithm. + */ + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + if (filter_costs[i] >= PNG_FP_1) + { + png_uint_32 tmp; + + /* Use a 32 bit unsigned temporary here because otherwise the + * intermediate value will be a 32 bit *signed* integer (ANSI rules) + * and this will get the wrong answer on division. + */ + tmp = PNG_COST_FACTOR*PNG_FP_1 + (filter_costs[i]/2); + tmp /= filter_costs[i]; + + png_ptr->inv_filter_costs[i] = (png_uint_16)tmp; + + tmp = PNG_COST_FACTOR * filter_costs[i] + PNG_FP_HALF; + tmp /= PNG_FP_1; + + png_ptr->filter_costs[i] = (png_uint_16)tmp; + } + } +} +#endif /* FIXED_POINT */ +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +void PNGAPI +png_set_compression_level(png_structrp png_ptr, int level) +{ + png_debug(1, "in png_set_compression_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_level = level; +} + +void PNGAPI +png_set_compression_mem_level(png_structrp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_compression_mem_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_mem_level = mem_level; +} + +void PNGAPI +png_set_compression_strategy(png_structrp png_ptr, int strategy) +{ + png_debug(1, "in png_set_compression_strategy"); + + if (png_ptr == NULL) + return; + + /* The flag setting here prevents the libpng dynamic selection of strategy. + */ + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; + png_ptr->zlib_strategy = strategy; +} + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +void PNGAPI +png_set_compression_window_bits(png_structrp png_ptr, int window_bits) +{ + if (png_ptr == NULL) + return; + + /* Prior to 1.6.0 this would warn but then set the window_bits value, this + * meant that negative window bits values could be selected which would cause + * libpng to write a non-standard PNG file with raw deflate or gzip + * compressed IDAT or ancillary chunks. Such files can be read and there is + * no warning on read, so this seems like a very bad idea. + */ + if (window_bits > 15) + { + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } + + else if (window_bits < 8) + { + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + window_bits = 8; + } + + png_ptr->zlib_window_bits = window_bits; +} + +void PNGAPI +png_set_compression_method(png_structrp png_ptr, int method) +{ + png_debug(1, "in png_set_compression_method"); + + if (png_ptr == NULL) + return; + + /* This would produce an invalid PNG file if it worked, but it doesn't and + * deflate will fault it, so it is harmless to just warn here. + */ + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + + png_ptr->zlib_method = method; +} + +/* The following were added to libpng-1.5.4 */ +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +void PNGAPI +png_set_text_compression_level(png_structrp png_ptr, int level) +{ + png_debug(1, "in png_set_text_compression_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_level = level; +} + +void PNGAPI +png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_text_compression_mem_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_mem_level = mem_level; +} + +void PNGAPI +png_set_text_compression_strategy(png_structrp png_ptr, int strategy) +{ + png_debug(1, "in png_set_text_compression_strategy"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_strategy = strategy; +} + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +void PNGAPI +png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits) +{ + if (png_ptr == NULL) + return; + + if (window_bits > 15) + { + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } + + else if (window_bits < 8) + { + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + window_bits = 8; + } + + png_ptr->zlib_text_window_bits = window_bits; +} + +void PNGAPI +png_set_text_compression_method(png_structrp png_ptr, int method) +{ + png_debug(1, "in png_set_text_compression_method"); + + if (png_ptr == NULL) + return; + + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + + png_ptr->zlib_text_method = method; +} +#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ +/* end of API added to libpng-1.5.4 */ + +void PNGAPI +png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->write_row_fn = write_row_fn; +} + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +void PNGAPI +png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr + write_user_transform_fn) +{ + png_debug(1, "in png_set_write_user_transform_fn"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->write_user_transform_fn = write_user_transform_fn; +} +#endif + + +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_write_png(png_structrp png_ptr, png_inforp info_ptr, + int transforms, voidp params) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Write the file header information. */ + png_write_info(png_ptr, info_ptr); + + /* ------ these transformations don't touch the info structure ------- */ + +#ifdef PNG_WRITE_INVERT_SUPPORTED + /* Invert monochrome pixels */ + if (transforms & PNG_TRANSFORM_INVERT_MONO) + png_set_invert_mono(png_ptr); +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + if ((transforms & PNG_TRANSFORM_SHIFT) + && (info_ptr->valid & PNG_INFO_sBIT)) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED + /* Pack pixels into bytes */ + if (transforms & PNG_TRANSFORM_PACKING) + png_set_packing(png_ptr); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + /* Swap location of alpha bytes from ARGB to RGBA */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + png_set_swap_alpha(png_ptr); +#endif + +#ifdef PNG_WRITE_FILLER_SUPPORTED + /* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */ + if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + + else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); +#endif + +#ifdef PNG_WRITE_BGR_SUPPORTED + /* Flip BGR pixels to RGB */ + if (transforms & PNG_TRANSFORM_BGR) + png_set_bgr(png_ptr); +#endif + +#ifdef PNG_WRITE_SWAP_SUPPORTED + /* Swap bytes of 16-bit files to most significant byte first */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + png_set_swap(png_ptr); +#endif + +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + /* Swap bits of 1, 2, 4 bit packed pixel formats */ + if (transforms & PNG_TRANSFORM_PACKSWAP) + png_set_packswap(png_ptr); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + + /* ----------------------- end of transformations ------------------- */ + + /* Write the bits */ + if (info_ptr->valid & PNG_INFO_IDAT) + png_write_image(png_ptr, info_ptr->row_pointers); + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); + + PNG_UNUSED(transforms) /* Quiet compiler warnings */ + PNG_UNUSED(params) +} +#endif + + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */ +/* Initialize the write structure - general purpose utility. */ +static int +png_image_write_init(png_imagep image) +{ + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, + png_safe_error, png_safe_warning); + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + png_controlp control = png_voidcast(png_controlp, + png_malloc_warn(png_ptr, (sizeof *control))); + + if (control != NULL) + { + memset(control, 0, (sizeof *control)); + + control->png_ptr = png_ptr; + control->info_ptr = info_ptr; + control->for_write = 1; + + image->opaque = control; + return 1; + } + + /* Error clean up */ + png_destroy_info_struct(png_ptr, &info_ptr); + } + + png_destroy_write_struct(&png_ptr, NULL); + } + + return png_image_error(image, "png_image_write_: out of memory"); +} + +/* Arguments to png_image_write_main: */ +typedef struct +{ + /* Arguments: */ + png_imagep image; + png_const_voidp buffer; + png_int_32 row_stride; + png_const_voidp colormap; + int convert_to_8bit; + /* Local variables: */ + png_const_voidp first_row; + ptrdiff_t row_bytes; + png_voidp local_row; +} png_image_write_control; + +/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to + * do any necessary byte swapping. The component order is defined by the + * png_image format value. + */ +static int +png_write_image_16bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); + png_uint_16p row_end; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; + int aindex = 0; + png_uint_32 y = image->height; + + if (image->format & PNG_FORMAT_FLAG_ALPHA) + { + if (image->format & PNG_FORMAT_FLAG_AFIRST) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + + else + aindex = channels; + } + + else + png_error(png_ptr, "png_write_image: internal call error"); + + /* Work out the output row end and count over this, note that the increment + * above to 'row' means that row_end can actually be beyond the end of the + * row; this is correct. + */ + row_end = output_row + image->width * (channels+1); + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_uint_16p out_ptr = output_row; + + while (out_ptr < row_end) + { + const png_uint_16 alpha = in_ptr[aindex]; + png_uint_32 reciprocal = 0; + int c; + + out_ptr[aindex] = alpha; + + /* Calculate a reciprocal. The correct calculation is simply + * component/alpha*65535 << 15. (I.e. 15 bits of precision); this + * allows correct rounding by adding .5 before the shift. 'reciprocal' + * is only initialized when required. + */ + if (alpha > 0 && alpha < 65535) + reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; + + c = channels; + do /* always at least one channel */ + { + png_uint_16 component = *in_ptr++; + + /* The following gives 65535 for an alpha of 0, which is fine, + * otherwise if 0/0 is represented as some other value there is more + * likely to be a discontinuity which will probably damage + * compression when moving from a fully transparent area to a + * nearly transparent one. (The assumption here is that opaque + * areas tend not to be 0 intensity.) + */ + if (component >= alpha) + component = 65535; + + /* component 0 && alpha < 65535) + { + png_uint_32 calc = component * reciprocal; + calc += 16384; /* round to nearest */ + component = (png_uint_16)(calc >> 15); + } + + *out_ptr++ = component; + } + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } + + png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } + + return 1; +} + +/* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel + * is present it must be removed from the components, the components are then + * written in sRGB encoding. No components are added or removed. + * + * Calculate an alpha reciprocal to reverse pre-multiplication. As above the + * calculation can be done to 15 bits of accuracy; however, the output needs to + * be scaled in the range 0..255*65535, so include that scaling here. + */ +#define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha) + +static png_byte +png_unpremultiply(png_uint_32 component, png_uint_32 alpha, + png_uint_32 reciprocal/*from the above macro*/) +{ + /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 + * is represented as some other value there is more likely to be a + * discontinuity which will probably damage compression when moving from a + * fully transparent area to a nearly transparent one. (The assumption here + * is that opaque areas tend not to be 0 intensity.) + * + * There is a rounding problem here; if alpha is less than 128 it will end up + * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the + * output change for this too. + */ + if (component >= alpha || alpha < 128) + return 255; + + /* component 0) + { + /* The test is that alpha/257 (rounded) is less than 255, the first value + * that becomes 255 is 65407. + * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore, + * be exact!) [Could also test reciprocal != 0] + */ + if (alpha < 65407) + { + component *= reciprocal; + component += 64; /* round to nearest */ + component >>= 7; + } + + else + component *= 255; + + /* Convert the component to sRGB. */ + return (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + else + return 0; +} + +static int +png_write_image_8bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_bytep output_row = png_voidcast(png_bytep, display->local_row); + png_uint_32 y = image->height; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; + + if (image->format & PNG_FORMAT_FLAG_ALPHA) + { + png_bytep row_end; + int aindex; + + if (image->format & PNG_FORMAT_FLAG_AFIRST) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + + else + aindex = channels; + + /* Use row_end in place of a loop counter: */ + row_end = output_row + image->width * (channels+1); + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_16 alpha = in_ptr[aindex]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + int c; + + /* Scale and write the alpha channel. */ + out_ptr[aindex] = alphabyte; + + if (alphabyte > 0 && alphabyte < 255) + reciprocal = UNP_RECIPROCAL(alpha); + + c = channels; + do /* always at least one channel */ + *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } /* while out_ptr < row_end */ + + png_write_row(png_ptr, png_voidcast(png_const_bytep, + display->local_row)); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } /* while y */ + } + + else + { + /* No alpha channel, so the row_end really is the end of the row and it + * is sufficient to loop over the components one by one. + */ + png_bytep row_end = output_row + image->width * channels; + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_32 component = *in_ptr++; + + component *= 255; + *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + png_write_row(png_ptr, output_row); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } + } + + return 1; +} + +static void +png_image_set_PLTE(png_image_write_control *display) +{ + const png_imagep image = display->image; + const void *cmap = display->colormap; + const int entries = image->colormap_entries > 256 ? 256 : + (int)image->colormap_entries; + + /* NOTE: the caller must check for cmap != NULL and entries != 0 */ + const png_uint_32 format = image->format; + const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); + +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else +# define afirst 0 +# endif + +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int bgr = (format & PNG_FORMAT_FLAG_BGR) ? 2 : 0; +# else +# define bgr 0 +# endif + + int i, num_trans; + png_color palette[256]; + png_byte tRNS[256]; + + memset(tRNS, 255, (sizeof tRNS)); + memset(palette, 0, (sizeof palette)); + + for (i=num_trans=0; i= 3) /* RGB */ + { + palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[(2 ^ bgr)]); + palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[1]); + palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[bgr]); + } + + else /* Gray */ + palette[i].blue = palette[i].red = palette[i].green = + (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry); + } + + else /* alpha */ + { + png_uint_16 alpha = entry[afirst ? 0 : channels-1]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + + /* Calculate a reciprocal, as in the png_write_image_8bit code above + * this is designed to produce a value scaled to 255*65535 when + * divided by 128 (i.e. asr 7). + */ + if (alphabyte > 0 && alphabyte < 255) + reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha; + + tRNS[i] = alphabyte; + if (alphabyte < 255) + num_trans = i+1; + + if (channels >= 3) /* RGB */ + { + palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], + alpha, reciprocal); + palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, + reciprocal); + palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, + reciprocal); + } + + else /* gray */ + palette[i].blue = palette[i].red = palette[i].green = + png_unpremultiply(entry[afirst], alpha, reciprocal); + } + } + + else /* Color-map has sRGB values */ + { + png_const_bytep entry = png_voidcast(png_const_bytep, cmap); + + entry += i * channels; + + switch (channels) + { + case 4: + tRNS[i] = entry[afirst ? 0 : 3]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALL THROUGH */ + case 3: + palette[i].blue = entry[afirst + (2 ^ bgr)]; + palette[i].green = entry[afirst + 1]; + palette[i].red = entry[afirst + bgr]; + break; + + case 2: + tRNS[i] = entry[1 ^ afirst]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALL THROUGH */ + case 1: + palette[i].blue = palette[i].red = palette[i].green = + entry[afirst]; + break; + + default: + break; + } + } + } + +# ifdef afirst +# undef afirst +# endif +# ifdef bgr +# undef bgr +# endif + + png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, + entries); + + if (num_trans > 0) + png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, + num_trans, NULL); + + image->colormap_entries = entries; +} + +static int +png_image_write_main(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + png_uint_32 format = image->format; + + int colormap = (format & PNG_FORMAT_FLAG_COLORMAP) != 0; + int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR) != 0; /* input */ + int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0; + int write_16bit = linear && !colormap && !display->convert_to_8bit; + +# ifdef PNG_BENIGN_ERRORS_SUPPORTED + /* Make sure we error out on any bad situation */ + png_set_benign_errors(png_ptr, 0/*error*/); +# endif + + /* Default the 'row_stride' parameter if required. */ + if (display->row_stride == 0) + display->row_stride = PNG_IMAGE_ROW_STRIDE(*image); + + /* Set the required transforms then write the rows in the correct order. */ + if (format & PNG_FORMAT_FLAG_COLORMAP) + { + if (display->colormap != NULL && image->colormap_entries > 0) + { + png_uint_32 entries = image->colormap_entries; + + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), + PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_image_set_PLTE(display); + } + + else + png_error(image->opaque->png_ptr, + "no color-map for color-mapped image"); + } + + else + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + write_16bit ? 16 : 8, + ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + + ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* Counter-intuitively the data transformations must be called *after* + * png_write_info, not before as in the read code, but the 'set' functions + * must still be called before. Just set the color space information, never + * write an interlaced image. + */ + + if (write_16bit) + { + /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); + + if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB)) + png_set_cHRM_fixed(png_ptr, info_ptr, + /* color x y */ + /* white */ 31270, 32900, + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000 + ); + } + + else if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB)) + png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); + + /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit + * space must still be gamma encoded. + */ + else + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); + + /* Write the file header. */ + png_write_info(png_ptr, info_ptr); + + /* Now set up the data transformations (*after* the header is written), + * remove the handled transformations from the 'format' flags for checking. + * + * First check for a little endian system if writing 16 bit files. + */ + if (write_16bit) + { + PNG_CONST png_uint_16 le = 0x0001; + + if (*(png_const_bytep)&le) + png_set_swap(png_ptr); + } + +# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED + if (format & PNG_FORMAT_FLAG_BGR) + { + if (!colormap && (format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_bgr(png_ptr); + format &= ~PNG_FORMAT_FLAG_BGR; + } +# endif + +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if (format & PNG_FORMAT_FLAG_AFIRST) + { + if (!colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0) + png_set_swap_alpha(png_ptr); + format &= ~PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* If there are 16 or fewer color-map entries we wrote a lower bit depth + * above, but the application data is still byte packed. + */ + if (colormap && image->colormap_entries <= 16) + png_set_packing(png_ptr); + + /* That should have handled all (both) the transforms. */ + if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR | + PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0) + png_error(png_ptr, "png_write_image: unsupported transformation"); + + { + png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); + ptrdiff_t row_bytes = display->row_stride; + + if (linear) + row_bytes *= (sizeof (png_uint_16)); + + if (row_bytes < 0) + row += (image->height-1) * (-row_bytes); + + display->first_row = row; + display->row_bytes = row_bytes; + } + + /* Apply 'fast' options if the flag is set. */ + if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0) + { + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS); + /* NOTE: determined by experiment using pngstest, this reflects some + * balance between the time to write the image once and the time to read + * it about 50 times. The speed-up in pngstest was about 10-20% of the + * total (user) time on a heavily loaded system. + */ + png_set_compression_level(png_ptr, 3); + } + + /* Check for the cases that currently require a pre-transform on the row + * before it is written. This only applies when the input is 16-bit and + * either there is an alpha channel or it is converted to 8-bit. + */ + if ((linear && alpha) || (!colormap && display->convert_to_8bit)) + { + png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr))); + int result; + + display->local_row = row; + if (write_16bit) + result = png_safe_execute(image, png_write_image_16bit, display); + else + result = png_safe_execute(image, png_write_image_8bit, display); + display->local_row = NULL; + + png_free(png_ptr, row); + + /* Skip the 'write_end' on error: */ + if (!result) + return 0; + } + + /* Otherwise this is the case where the input is in a format currently + * supported by the rest of the libpng write code; call it directly. + */ + else + { + png_const_bytep row = png_voidcast(png_const_bytep, display->first_row); + ptrdiff_t row_bytes = display->row_bytes; + png_uint_32 y = image->height; + + while (y-- > 0) + { + png_write_row(png_ptr, row); + row += row_bytes; + } + } + + png_write_end(png_ptr, info_ptr); + return 1; +} + +int PNGAPI +png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, + const void *buffer, png_int_32 row_stride, const void *colormap) +{ + /* Write the image to the given (FILE*). */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file != NULL) + { + if (png_image_write_init(image)) + { + png_image_write_control display; + int result; + + /* This is slightly evil, but png_init_io doesn't do anything other + * than this and we haven't changed the standard IO functions so + * this saves a 'safe' function. + */ + image->opaque->png_ptr->io_ptr = file; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.convert_to_8bit = convert_to_8bit; + + result = png_safe_execute(image, png_image_write_main, &display); + png_image_free(image); + return result; + } + + else + return 0; + } + + else + return png_image_error(image, + "png_image_write_to_stdio: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} + +int PNGAPI +png_image_write_to_file(png_imagep image, const char *file_name, + int convert_to_8bit, const void *buffer, png_int_32 row_stride, + const void *colormap) +{ + /* Write the image to the named file. */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file_name != NULL) + { + FILE *fp = fopen(file_name, "wb"); + + if (fp != NULL) + { + if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, + row_stride, colormap)) + { + int error; /* from fflush/fclose */ + + /* Make sure the file is flushed correctly. */ + if (fflush(fp) == 0 && ferror(fp) == 0) + { + if (fclose(fp) == 0) + return 1; + + error = errno; /* from fclose */ + } + + else + { + error = errno; /* from fflush or ferror */ + (void)fclose(fp); + } + + (void)remove(file_name); + /* The image has already been cleaned up; this is just used to + * set the error (because the original write succeeded). + */ + return png_image_error(image, strerror(error)); + } + + else + { + /* Clean up: just the opened file. */ + (void)fclose(fp); + (void)remove(file_name); + return 0; + } + } + + else + return png_image_error(image, strerror(errno)); + } + + else + return png_image_error(image, + "png_image_write_to_file: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} +#endif /* PNG_STDIO_SUPPORTED */ +#endif /* SIMPLIFIED_WRITE */ +#endif /* PNG_WRITE_SUPPORTED */ +#endif//_FPDFAPI_MINI_ diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwtran.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwtran.c new file mode 100644 index 0000000000..8f2811099a --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwtran.c @@ -0,0 +1,638 @@ + +/* pngwtran.c - transforms the data in a row for PNG writers + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +#include "pngpriv.h" + +#ifdef PNG_WRITE_SUPPORTED + +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +/* Transform the data according to the user's wishes. The order of + * transformations is significant. + */ +void /* PRIVATE */ +png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info) +{ + png_debug(1, "in png_do_write_transformations"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + if (png_ptr->transformations & PNG_USER_TRANSFORM) + if (png_ptr->write_user_transform_fn != NULL) + (*(png_ptr->write_user_transform_fn)) /* User write transform + function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#endif + +#ifdef PNG_WRITE_FILLER_SUPPORTED + if (png_ptr->transformations & PNG_FILLER) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); +#endif + +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED + if (png_ptr->transformations & PNG_PACK) + png_do_pack(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->bit_depth); +#endif + +#ifdef PNG_WRITE_SWAP_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if (png_ptr->transformations & PNG_SHIFT) + png_do_shift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_BGR_SUPPORTED + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif +} + +#ifdef PNG_WRITE_PACK_SUPPORTED +/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The + * row_info bit depth should be 8 (one pixel per byte). The channels + * should be 1 (this only happens on grayscale and paletted images). + */ +void /* PRIVATE */ +png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) +{ + png_debug(1, "in png_do_pack"); + + if (row_info->bit_depth == 8 && + row_info->channels == 1) + { + switch ((int)bit_depth) + { + case 1: + { + png_bytep sp, dp; + int mask, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + mask = 0x80; + v = 0; + + for (i = 0; i < row_width; i++) + { + if (*sp != 0) + v |= mask; + + sp++; + + if (mask > 1) + mask >>= 1; + + else + { + mask = 0x80; + *dp = (png_byte)v; + dp++; + v = 0; + } + } + + if (mask != 0x80) + *dp = (png_byte)v; + + break; + } + + case 2: + { + png_bytep sp, dp; + int shift, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 6; + v = 0; + + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x03); + v |= (value << shift); + + if (shift == 0) + { + shift = 6; + *dp = (png_byte)v; + dp++; + v = 0; + } + + else + shift -= 2; + + sp++; + } + + if (shift != 6) + *dp = (png_byte)v; + + break; + } + + case 4: + { + png_bytep sp, dp; + int shift, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 4; + v = 0; + + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x0f); + v |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp = (png_byte)v; + dp++; + v = 0; + } + + else + shift -= 4; + + sp++; + } + + if (shift != 4) + *dp = (png_byte)v; + + break; + } + + default: + break; + } + + row_info->bit_depth = (png_byte)bit_depth; + row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED +/* Shift pixel values to take advantage of whole range. Pass the + * true number of bits in bit_depth. The row should be packed + * according to row_info->bit_depth. Thus, if you had a row of + * bit depth 4, but the pixels only had values from 0 to 7, you + * would pass 3 as bit_depth, and this routine would translate the + * data to 0 to 15. + */ +void /* PRIVATE */ +png_do_shift(png_row_infop row_info, png_bytep row, + png_const_color_8p bit_depth) +{ + png_debug(1, "in png_do_shift"); + + if (row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift_start[4], shift_dec[4]; + int channels = 0; + + if (row_info->color_type & PNG_COLOR_MASK_COLOR) + { + shift_start[channels] = row_info->bit_depth - bit_depth->red; + shift_dec[channels] = bit_depth->red; + channels++; + + shift_start[channels] = row_info->bit_depth - bit_depth->green; + shift_dec[channels] = bit_depth->green; + channels++; + + shift_start[channels] = row_info->bit_depth - bit_depth->blue; + shift_dec[channels] = bit_depth->blue; + channels++; + } + + else + { + shift_start[channels] = row_info->bit_depth - bit_depth->gray; + shift_dec[channels] = bit_depth->gray; + channels++; + } + + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + shift_start[channels] = row_info->bit_depth - bit_depth->alpha; + shift_dec[channels] = bit_depth->alpha; + channels++; + } + + /* With low row depths, could only be grayscale, so one channel */ + if (row_info->bit_depth < 8) + { + png_bytep bp = row; + png_size_t i; + unsigned int mask; + png_size_t row_bytes = row_info->rowbytes; + + if (bit_depth->gray == 1 && row_info->bit_depth == 2) + mask = 0x55; + + else if (row_info->bit_depth == 4 && bit_depth->gray == 3) + mask = 0x11; + + else + mask = 0xff; + + for (i = 0; i < row_bytes; i++, bp++) + { + int j; + unsigned int v, out; + + v = *bp; + out = 0; + + for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) + { + if (j > 0) + out |= v << j; + + else + out |= (v >> (-j)) & mask; + } + + *bp = (png_byte)(out & 0xff); + } + } + + else if (row_info->bit_depth == 8) + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (i = 0; i < istop; i++, bp++) + { + + const unsigned int c = i%channels; + int j; + unsigned int v, out; + + v = *bp; + out = 0; + + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + out |= v << j; + + else + out |= v >> (-j); + } + + *bp = (png_byte)(out & 0xff); + } + } + + else + { + png_bytep bp; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (bp = row, i = 0; i < istop; i++) + { + const unsigned int c = i%channels; + int j; + unsigned int value, v; + + v = png_get_uint_16(bp); + value = 0; + + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + value |= v << j; + + else + value |= v >> (-j); + } + *bp++ = (png_byte)((value >> 8) & 0xff); + *bp++ = (png_byte)(value & 0xff); + } + } + } +} +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_swap_alpha"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This converts from ARGB to RGBA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This converts from AARRGGBB to RRGGBBAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } +#endif /* PNG_WRITE_16BIT_SUPPORTED */ + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This converts from AG to GA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This converts from AAGG to GGAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } +#endif /* PNG_WRITE_16BIT_SUPPORTED */ + } + } +} +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_invert_alpha"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in RGBA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=3; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This inverts the alpha channel in RRGGBBAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=6; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } +#endif /* PNG_WRITE_16BIT_SUPPORTED */ + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in GA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This inverts the alpha channel in GGAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=2; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } +#endif /* PNG_WRITE_16BIT_SUPPORTED */ + } + } +} +#endif +#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing */ +void /* PRIVATE */ +png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_intrapixel"); + + if ((row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((*rp - *(rp + 1)) & 0xff); + *(rp + 2) = (png_byte)((*(rp + 2) - *(rp + 1)) & 0xff); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp + 1) = (png_byte)(red & 0xff); + *(rp + 4) = (png_byte)((blue >> 8) & 0xff); + *(rp + 5) = (png_byte)(blue & 0xff); + } + } +#endif /* PNG_WRITE_16BIT_SUPPORTED */ + } +} +#endif /* PNG_MNG_FEATURES_SUPPORTED */ +#endif /* PNG_WRITE_SUPPORTED */ +#endif//_FPDFAPI_MINI_ diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwutil.c b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwutil.c new file mode 100644 index 0000000000..40955b9381 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/fx_pngwutil.c @@ -0,0 +1,3024 @@ + +/* pngwutil.c - utilities to write a PNG file + * + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_) || defined(_PNG_DECODER_)) && !defined(_USE_ADDIN_) && !defined(_FX_EMB_NOUSE_DECODER_) +#include "pngpriv.h" + +#ifdef PNG_WRITE_SUPPORTED + +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +/* Place a 32-bit number into a buffer in PNG byte order. We work + * with unsigned numbers for convenience, although one supported + * ancillary chunk uses signed (two's complement) numbers. + */ +void PNGAPI +png_save_uint_32(png_bytep buf, png_uint_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); +} + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +void PNGAPI +png_save_uint_16(png_bytep buf, unsigned int i) +{ + buf[0] = (png_byte)((i >> 8) & 0xff); + buf[1] = (png_byte)(i & 0xff); +} +#endif + +/* Simple function to write the signature. If we have already written + * the magic bytes of the signature, or more likely, the PNG stream is + * being embedded into another stream and doesn't need its own signature, + * we should call png_set_sig_bytes() to tell libpng how many of the + * bytes have already been written. + */ +void PNGAPI +png_write_sig(png_structrp png_ptr) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the signature is being written */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE; +#endif + + /* Write the rest of the 8 byte signature */ + png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], + (png_size_t)(8 - png_ptr->sig_bytes)); + + if (png_ptr->sig_bytes < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; +} + +/* Write the start of a PNG chunk. The type is the chunk type. + * The total_length is the sum of the lengths of all the data you will be + * passing in png_write_chunk_data(). + */ +static void +png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name, + png_uint_32 length) +{ + png_byte buf[8]; + +#if defined(PNG_DEBUG) && (PNG_DEBUG > 0) + PNG_CSTRING_FROM_CHUNK(buf, chunk_name); + png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length); +#endif + + if (png_ptr == NULL) + return; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk header is being written. + * PNG_IO_CHUNK_HDR requires a single I/O call. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR; +#endif + + /* Write the length and the chunk name */ + png_save_uint_32(buf, length); + png_save_uint_32(buf + 4, chunk_name); + png_write_data(png_ptr, buf, 8); + + /* Put the chunk name into png_ptr->chunk_name */ + png_ptr->chunk_name = chunk_name; + + /* Reset the crc and run it over the chunk name */ + png_reset_crc(png_ptr); + + png_calculate_crc(png_ptr, buf + 4, 4); + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that chunk data will (possibly) be written. + * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA; +#endif +} + +void PNGAPI +png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string, + png_uint_32 length) +{ + png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length); +} + +/* Write the data of a PNG chunk started with png_write_chunk_header(). + * Note that multiple calls to this function are allowed, and that the + * sum of the lengths from these calls *must* add up to the total_length + * given to png_write_chunk_header(). + */ +void PNGAPI +png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, + png_size_t length) +{ + /* Write the data, and run the CRC over it */ + if (png_ptr == NULL) + return; + + if (data != NULL && length > 0) + { + png_write_data(png_ptr, data, length); + + /* Update the CRC after writing the data, + * in case that the user I/O routine alters it. + */ + png_calculate_crc(png_ptr, data, length); + } +} + +/* Finish a chunk started with png_write_chunk_header(). */ +void PNGAPI +png_write_chunk_end(png_structrp png_ptr) +{ + png_byte buf[4]; + + if (png_ptr == NULL) return; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk CRC is being written. + * PNG_IO_CHUNK_CRC requires a single I/O function call. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC; +#endif + + /* Write the crc in a single operation */ + png_save_uint_32(buf, png_ptr->crc); + + png_write_data(png_ptr, buf, (png_size_t)4); +} + +/* Write a PNG chunk all at once. The type is an array of ASCII characters + * representing the chunk name. The array must be at least 4 bytes in + * length, and does not need to be null terminated. To be safe, pass the + * pre-defined chunk names here, and if you need a new one, define it + * where the others are defined. The length is the length of the data. + * All the data must be present. If that is not possible, use the + * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() + * functions instead. + */ +static void +png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, + png_const_bytep data, png_size_t length) +{ + if (png_ptr == NULL) + return; + + /* On 64 bit architectures 'length' may not fit in a png_uint_32. */ + if (length > PNG_UINT_31_MAX) + png_error(png_ptr, "length exceeds PNG maxima"); + + png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length); + png_write_chunk_data(png_ptr, data, length); + png_write_chunk_end(png_ptr); +} + +/* This is the API that calls the internal function above. */ +void PNGAPI +png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, + png_const_bytep data, png_size_t length) +{ + png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data, + length); +} + +/* This is used below to find the size of an image to pass to png_deflate_claim, + * so it only needs to be accurate if the size is less than 16384 bytes (the + * point at which a lower LZ window size can be used.) + */ +static png_alloc_size_t +png_image_size(png_structrp png_ptr) +{ + /* Only return sizes up to the maximum of a png_uint_32, do this by limiting + * the width and height used to 15 bits. + */ + png_uint_32 h = png_ptr->height; + + if (png_ptr->rowbytes < 32768 && h < 32768) + { + if (png_ptr->interlaced) + { + /* Interlacing makes the image larger because of the replication of + * both the filter byte and the padding to a byte boundary. + */ + png_uint_32 w = png_ptr->width; + unsigned int pd = png_ptr->pixel_depth; + png_alloc_size_t cb_base; + int pass; + + for (cb_base=0, pass=0; pass<=6; ++pass) + { + png_uint_32 pw = PNG_PASS_COLS(w, pass); + + if (pw > 0) + cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass); + } + + return cb_base; + } + + else + return (png_ptr->rowbytes+1) * h; + } + + else + return 0xffffffffU; +} + +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + /* This is the code to hack the first two bytes of the deflate stream (the + * deflate header) to correct the windowBits value to match the actual data + * size. Note that the second argument is the *uncompressed* size but the + * first argument is the *compressed* data (and it must be deflate + * compressed.) + */ +static void +optimize_cmf(png_bytep data, png_alloc_size_t data_size) +{ + /* Optimize the CMF field in the zlib stream. The resultant zlib stream is + * still compliant to the stream specification. + */ + if (data_size <= 16384) /* else windowBits must be 15 */ + { + unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + { + unsigned int z_cinfo; + unsigned int half_z_window_size; + + z_cinfo = z_cmf >> 4; + half_z_window_size = 1U << (z_cinfo + 7); + + if (data_size <= half_z_window_size) /* else no change */ + { + unsigned int tmp; + + do + { + half_z_window_size >>= 1; + --z_cinfo; + } + while (z_cinfo > 0 && data_size <= half_z_window_size); + + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + + data[0] = (png_byte)z_cmf; + tmp = data[1] & 0xe0; + tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; + data[1] = (png_byte)tmp; + } + } + } +} +#else +# define optimize_cmf(dp,dl) ((void)0) +#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */ + +/* Initialize the compressor for the appropriate type of compression. */ +static int +png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, + png_alloc_size_t data_size) +{ + if (png_ptr->zowner != 0) + { + char msg[64]; + + PNG_STRING_FROM_CHUNK(msg, owner); + msg[4] = ':'; + msg[5] = ' '; + PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. + */ + (void)png_safecat(msg, (sizeof msg), 10, " using zstream"); +# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_warning(png_ptr, msg); + + /* Attempt sane error recovery */ + if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */ + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT"); + return Z_STREAM_ERROR; + } + + png_ptr->zowner = 0; +# else + png_error(png_ptr, msg); +# endif + } + + { + int level = png_ptr->zlib_level; + int method = png_ptr->zlib_method; + int windowBits = png_ptr->zlib_window_bits; + int memLevel = png_ptr->zlib_mem_level; + int strategy; /* set below */ + int ret; /* zlib return code */ + + if (owner == png_IDAT) + { + if (png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) + strategy = png_ptr->zlib_strategy; + + else if (png_ptr->do_filter != PNG_FILTER_NONE) + strategy = PNG_Z_DEFAULT_STRATEGY; + + else + strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY; + } + + else + { +# ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + level = png_ptr->zlib_text_level; + method = png_ptr->zlib_text_method; + windowBits = png_ptr->zlib_text_window_bits; + memLevel = png_ptr->zlib_text_mem_level; + strategy = png_ptr->zlib_text_strategy; +# else + /* If customization is not supported the values all come from the + * IDAT values except for the strategy, which is fixed to the + * default. (This is the pre-1.6.0 behavior too, although it was + * implemented in a very different way.) + */ + strategy = Z_DEFAULT_STRATEGY; +# endif + } + + /* Adjust 'windowBits' down if larger than 'data_size'; to stop this + * happening just pass 32768 as the data_size parameter. Notice that zlib + * requires an extra 262 bytes in the window in addition to the data to be + * able to see the whole of the data, so if data_size+262 takes us to the + * next windowBits size we need to fix up the value later. (Because even + * though deflate needs the extra window, inflate does not!) + */ + if (data_size <= 16384) + { + /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to + * work round a Microsoft Visual C misbehavior which, contrary to C-90, + * widens the result of the following shift to 64-bits if (and, + * apparently, only if) it is used in a test. + */ + unsigned int half_window_size = 1U << (windowBits-1); + + while (data_size + 262 <= half_window_size) + { + half_window_size >>= 1; + --windowBits; + } + } + + /* Check against the previous initialized values, if any. */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) && + (png_ptr->zlib_set_level != level || + png_ptr->zlib_set_method != method || + png_ptr->zlib_set_window_bits != windowBits || + png_ptr->zlib_set_mem_level != memLevel || + png_ptr->zlib_set_strategy != strategy)) + { + if (deflateEnd(&png_ptr->zstream) != Z_OK) + png_warning(png_ptr, "deflateEnd failed (ignored)"); + + png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED; + } + + /* For safety clear out the input and output pointers (currently zlib + * doesn't use them on Init, but it might in the future). + */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; + + /* Now initialize if required, setting the new parameters, otherwise just + * to a simple reset to the previous parameters. + */ + if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) + ret = deflateReset(&png_ptr->zstream); + + else + { + ret = deflateInit2(&png_ptr->zstream, level, method, windowBits, + memLevel, strategy); + + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; + } + + /* The return code is from either deflateReset or deflateInit2; they have + * pretty much the same set of error codes. + */ + if (ret == Z_OK) + png_ptr->zowner = owner; + + else + png_zstream_error(png_ptr, ret); + + return ret; + } +} + +/* Clean up (or trim) a linked list of compression buffers. */ +void /* PRIVATE */ +png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp) +{ + png_compression_bufferp list = *listp; + + if (list != NULL) + { + *listp = NULL; + + do + { + png_compression_bufferp next = list->next; + + png_free(png_ptr, list); + list = next; + } + while (list != NULL); + } +} + +#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +/* This pair of functions encapsulates the operation of (a) compressing a + * text string, and (b) issuing it later as a series of chunk data writes. + * The compression_state structure is shared context for these functions + * set up by the caller to allow access to the relevant local variables. + * + * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size + * temporary buffers. From 1.6.0 it is retained in png_struct so that it will + * be correctly freed in the event of a write error (previous implementations + * just leaked memory.) + */ +typedef struct +{ + png_const_bytep input; /* The uncompressed input data */ + png_alloc_size_t input_len; /* Its length */ + png_uint_32 output_len; /* Final compressed length */ + png_byte output[1024]; /* First block of output */ +} compression_state; + +static void +png_text_compress_init(compression_state *comp, png_const_bytep input, + png_alloc_size_t input_len) +{ + comp->input = input; + comp->input_len = input_len; + comp->output_len = 0; +} + +/* Compress the data in the compression state input */ +static int +png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, + compression_state *comp, png_uint_32 prefix_len) +{ + int ret; + + /* To find the length of the output it is necessary to first compress the + * input, the result is buffered rather than using the two-pass algorithm + * that is used on the inflate side; deflate is assumed to be slower and a + * PNG writer is assumed to have more memory available than a PNG reader. + * + * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an + * upper limit on the output size, but it is always bigger than the input + * size so it is likely to be more efficient to use this linked-list + * approach. + */ + ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len); + + if (ret != Z_OK) + return ret; + + /* Set up the compression buffers, we need a loop here to avoid overflowing a + * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited + * by the output buffer size, so there is no need to check that. Since this + * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits + * in size. + */ + { + png_compression_bufferp *end = &png_ptr->zbuffer_list; + png_alloc_size_t input_len = comp->input_len; /* may be zero! */ + png_uint_32 output_len; + + /* zlib updates these for us: */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input); + png_ptr->zstream.avail_in = 0; /* Set below */ + png_ptr->zstream.next_out = comp->output; + png_ptr->zstream.avail_out = (sizeof comp->output); + + output_len = png_ptr->zstream.avail_out; + + do + { + uInt avail_in = ZLIB_IO_MAX; + + if (avail_in > input_len) + avail_in = (uInt)input_len; + + input_len -= avail_in; + + png_ptr->zstream.avail_in = avail_in; + + if (png_ptr->zstream.avail_out == 0) + { + png_compression_buffer *next; + + /* Chunk data is limited to 2^31 bytes in length, so the prefix + * length must be counted here. + */ + if (output_len + prefix_len > PNG_UINT_31_MAX) + { + ret = Z_MEM_ERROR; + break; + } + + /* Need a new (malloc'ed) buffer, but there may be one present + * already. + */ + next = *end; + if (next == NULL) + { + next = png_voidcast(png_compression_bufferp, png_malloc_base + (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + + if (next == NULL) + { + ret = Z_MEM_ERROR; + break; + } + + /* Link in this buffer (so that it will be freed later) */ + next->next = NULL; + *end = next; + } + + png_ptr->zstream.next_out = next->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; + output_len += png_ptr->zstream.avail_out; + + /* Move 'end' to the next buffer pointer. */ + end = &next->next; + } + + /* Compress the data */ + ret = deflate(&png_ptr->zstream, + input_len > 0 ? Z_NO_FLUSH : Z_FINISH); + + /* Claw back input data that was not consumed (because avail_in is + * reset above every time round the loop). + */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; /* safety */ + } + while (ret == Z_OK); + + /* There may be some space left in the last output buffer, this needs to + * be subtracted from output_len. + */ + output_len -= png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* safety */ + comp->output_len = output_len; + + /* Now double check the output length, put in a custom message if it is + * too long. Otherwise ensure the z_stream::msg pointer is set to + * something. + */ + if (output_len + prefix_len >= PNG_UINT_31_MAX) + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long"); + ret = Z_MEM_ERROR; + } + + else + png_zstream_error(png_ptr, ret); + + /* Reset zlib for another zTXt/iTXt or image data */ + png_ptr->zowner = 0; + + /* The only success case is Z_STREAM_END, input_len must be 0, if not this + * is an internal error. + */ + if (ret == Z_STREAM_END && input_len == 0) + { + /* Fix up the deflate header, if required */ + optimize_cmf(comp->output, comp->input_len); + + /* But Z_OK is returned, not Z_STREAM_END; this allows the claim + * function above to return Z_STREAM_END on an error (though it never + * does in the current versions of zlib.) + */ + return Z_OK; + } + + else + return ret; + } +} + +/* Ship the compressed text out via chunk writes */ +static void +png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) +{ + png_uint_32 output_len = comp->output_len; + png_const_bytep output = comp->output; + png_uint_32 avail = (sizeof comp->output); + png_compression_buffer *next = png_ptr->zbuffer_list; + + for (;;) + { + if (avail > output_len) + avail = output_len; + + png_write_chunk_data(png_ptr, output, avail); + + output_len -= avail; + + if (output_len == 0 || next == NULL) + break; + + avail = png_ptr->zbuffer_size; + output = next->output; + next = next->next; + } + + /* This is an internal error; 'next' must have been NULL! */ + if (output_len > 0) + png_error(png_ptr, "error writing ancillary chunked compressed data"); +} +#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, + * and if invalid, correct the keyword rather than discarding the entire + * chunk. The PNG 1.0 specification requires keywords 1-79 characters in + * length, forbids leading or trailing whitespace, multiple internal spaces, + * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. + * + * The 'new_key' buffer must be 80 characters in size (for the keyword plus a + * trailing '\0'). If this routine returns 0 then there was no keyword, or a + * valid one could not be generated, and the caller must png_error. + */ +static png_uint_32 +png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) +{ + png_const_charp orig_key = key; + png_uint_32 key_len = 0; + int bad_character = 0; + int space = 1; + + png_debug(1, "in png_check_keyword"); + + if (key == NULL) + { + *new_key = 0; + return 0; + } + + while (*key && key_len < 79) + { + png_byte ch = (png_byte)(0xff & *key++); + + if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) + *new_key++ = ch, ++key_len, space = 0; + + else if (!space) + { + /* A space or an invalid character when one wasn't seen immediately + * before; output just a space. + */ + *new_key++ = 32, ++key_len, space = 1; + + /* If the character was not a space then it is invalid. */ + if (ch != 32) + bad_character = ch; + } + + else if (!bad_character) + bad_character = ch; /* just skip it, record the first error */ + } + + if (key_len > 0 && space) /* trailing space */ + { + --key_len, --new_key; + if (!bad_character) + bad_character = 32; + } + + /* Terminate the keyword */ + *new_key = 0; + + if (key_len == 0) + return 0; + + /* Try to only output one warning per keyword: */ + if (*key) /* keyword too long */ + png_warning(png_ptr, "keyword truncated"); + + else if (bad_character) + { + PNG_WARNING_PARAMETERS(p) + + png_warning_parameter(p, 1, orig_key); + png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character); + + png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'"); + } + + return key_len; +} +#endif + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. Note that the rest of this code depends upon this + * information being correct. + */ +void /* PRIVATE */ +png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, + int bit_depth, int color_type, int compression_type, int filter_type, + int interlace_type) +{ + png_byte buf[13]; /* Buffer to store the IHDR info */ + + png_debug(1, "in png_write_IHDR"); + + /* Check that we have valid input data from the application info */ + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: +#ifdef PNG_WRITE_16BIT_SUPPORTED + case 16: +#endif + png_ptr->channels = 1; break; + + default: + png_error(png_ptr, + "Invalid bit depth for grayscale image"); + } + break; + + case PNG_COLOR_TYPE_RGB: +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (bit_depth != 8 && bit_depth != 16) +#else + if (bit_depth != 8) +#endif + png_error(png_ptr, "Invalid bit depth for RGB image"); + + png_ptr->channels = 3; + break; + + case PNG_COLOR_TYPE_PALETTE: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: + png_ptr->channels = 1; + break; + + default: + png_error(png_ptr, "Invalid bit depth for paletted image"); + } + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); + + png_ptr->channels = 2; + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (bit_depth != 8 && bit_depth != 16) +#else + if (bit_depth != 8) +#endif + png_error(png_ptr, "Invalid bit depth for RGBA image"); + + png_ptr->channels = 4; + break; + + default: + png_error(png_ptr, "Invalid image color type specified"); + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Invalid compression type specified"); + compression_type = PNG_COMPRESSION_TYPE_BASE; + } + + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ( +#ifdef PNG_MNG_FEATURES_SUPPORTED + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && +#endif + filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Invalid filter type specified"); + filter_type = PNG_FILTER_TYPE_BASE; + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + if (interlace_type != PNG_INTERLACE_NONE && + interlace_type != PNG_INTERLACE_ADAM7) + { + png_warning(png_ptr, "Invalid interlace type specified"); + interlace_type = PNG_INTERLACE_ADAM7; + } +#else + interlace_type=PNG_INTERLACE_NONE; +#endif + + /* Save the relevent information */ + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->color_type = (png_byte)color_type; + png_ptr->interlaced = (png_byte)interlace_type; +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + png_ptr->width = width; + png_ptr->height = height; + + png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); + /* Set the usr info, so any transformations can modify it */ + png_ptr->usr_width = png_ptr->width; + png_ptr->usr_bit_depth = png_ptr->bit_depth; + png_ptr->usr_channels = png_ptr->channels; + + /* Pack the header information into the buffer */ + png_save_uint_32(buf, width); + png_save_uint_32(buf + 4, height); + buf[8] = (png_byte)bit_depth; + buf[9] = (png_byte)color_type; + buf[10] = (png_byte)compression_type; + buf[11] = (png_byte)filter_type; + buf[12] = (png_byte)interlace_type; + + /* Write the chunk */ + png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13); + + if (!(png_ptr->do_filter)) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + png_ptr->bit_depth < 8) + png_ptr->do_filter = PNG_FILTER_NONE; + + else + png_ptr->do_filter = PNG_ALL_FILTERS; + } + + png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */ +} + +/* Write the palette. We are careful not to trust png_color to be in the + * correct order for PNG, so people can redefine it to any convenient + * structure. + */ +void /* PRIVATE */ +png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, + png_uint_32 num_pal) +{ + png_uint_32 i; + png_const_colorp pal_ptr; + png_byte buf[3]; + + png_debug(1, "in png_write_PLTE"); + + if (( +#ifdef PNG_MNG_FEATURES_SUPPORTED + !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && +#endif + num_pal == 0) || num_pal > 256) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_error(png_ptr, "Invalid number of colors in palette"); + } + + else + { + png_warning(png_ptr, "Invalid number of colors in palette"); + return; + } + } + + if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + { + png_warning(png_ptr, + "Ignoring request to write a PLTE chunk in grayscale PNG"); + + return; + } + + png_ptr->num_palette = (png_uint_16)num_pal; + png_debug1(3, "num_palette = %d", png_ptr->num_palette); + + png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3)); +#ifdef PNG_POINTER_INDEXING_SUPPORTED + + for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) + { + buf[0] = pal_ptr->red; + buf[1] = pal_ptr->green; + buf[2] = pal_ptr->blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } + +#else + /* This is a little slower but some buggy compilers need to do this + * instead + */ + pal_ptr=palette; + + for (i = 0; i < num_pal; i++) + { + buf[0] = pal_ptr[i].red; + buf[1] = pal_ptr[i].green; + buf[2] = pal_ptr[i].blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } + +#endif + png_write_chunk_end(png_ptr); + png_ptr->mode |= PNG_HAVE_PLTE; +} + +/* This is similar to png_text_compress, above, except that it does not require + * all of the data at once and, instead of buffering the compressed result, + * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out + * because it calls the write interface. As a result it does its own error + * reporting and does not return an error code. In the event of error it will + * just call png_error. The input data length may exceed 32-bits. The 'flush' + * parameter is exactly the same as that to deflate, with the following + * meanings: + * + * Z_NO_FLUSH: normal incremental output of compressed data + * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush + * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up + * + * The routine manages the acquire and release of the png_ptr->zstream by + * checking and (at the end) clearing png_ptr->zowner, it does some sanity + * checks on the 'mode' flags while doing this. + */ +void /* PRIVATE */ +png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, + png_alloc_size_t input_len, int flush) +{ + if (png_ptr->zowner != png_IDAT) + { + /* First time. Ensure we have a temporary buffer for compression and + * trim the buffer list if it has more than one entry to free memory. + * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been + * created at this point, but the check here is quick and safe. + */ + if (png_ptr->zbuffer_list == NULL) + { + png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, + png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + png_ptr->zbuffer_list->next = NULL; + } + + else + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next); + + /* It is a terminal error if we can't claim the zstream. */ + if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + /* The output state is maintained in png_ptr->zstream, so it must be + * initialized here after the claim. + */ + png_ptr->zstream.next_out = png_ptr->zbuffer_list->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; + } + + /* Now loop reading and writing until all the input is consumed or an error + * terminates the operation. The _out values are maintained across calls to + * this function, but the input must be reset each time. + */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + png_ptr->zstream.avail_in = 0; /* set below */ + for (;;) + { + int ret; + + /* INPUT: from the row data */ + uInt avail = ZLIB_IO_MAX; + + if (avail > input_len) + avail = (uInt)input_len; /* safe because of the check */ + + png_ptr->zstream.avail_in = avail; + input_len -= avail; + + ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush); + + /* Include as-yet unconsumed input */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; + + /* OUTPUT: write complete IDAT chunks when avail_out drops to zero, note + * that these two zstream fields are preserved across the calls, therefore + * there is no need to set these up on entry to the loop. + */ + if (png_ptr->zstream.avail_out == 0) + { + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size; + + /* Write an IDAT containing the data then reset the buffer. The + * first IDAT may need deflate header optimization. + */ +# ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if (!(png_ptr->mode & PNG_HAVE_IDAT) && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +# endif + + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->mode |= PNG_HAVE_IDAT; + + png_ptr->zstream.next_out = data; + png_ptr->zstream.avail_out = size; + + /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with + * the same flush parameter until it has finished output, for NO_FLUSH + * it doesn't matter. + */ + if (ret == Z_OK && flush != Z_NO_FLUSH) + continue; + } + + /* The order of these checks doesn't matter much; it just effect which + * possible error might be detected if multiple things go wrong at once. + */ + if (ret == Z_OK) /* most likely return code! */ + { + /* If all the input has been consumed then just return. If Z_FINISH + * was used as the flush parameter something has gone wrong if we get + * here. + */ + if (input_len == 0) + { + if (flush == Z_FINISH) + png_error(png_ptr, "Z_OK on Z_FINISH with output space"); + + return; + } + } + + else if (ret == Z_STREAM_END && flush == Z_FINISH) + { + /* This is the end of the IDAT data; any pending output must be + * flushed. For small PNG files we may still be at the beginning. + */ + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out; + +# ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if (!(png_ptr->mode & PNG_HAVE_IDAT) && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +# endif + + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->zstream.avail_out = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; + + png_ptr->zowner = 0; /* Release the stream */ + return; + } + + else + { + /* This is an error condition. */ + png_zstream_error(png_ptr, ret); + png_error(png_ptr, png_ptr->zstream.msg); + } + } +} + +/* Write an IEND chunk */ +void /* PRIVATE */ +png_write_IEND(png_structrp png_ptr) +{ + png_debug(1, "in png_write_IEND"); + + png_write_complete_chunk(png_ptr, png_IEND, NULL, (png_size_t)0); + png_ptr->mode |= PNG_HAVE_IEND; +} + +#ifdef PNG_WRITE_gAMA_SUPPORTED +/* Write a gAMA chunk */ +void /* PRIVATE */ +png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma) +{ + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA"); + + /* file_gamma is saved in 1/100,000ths */ + png_save_uint_32(buf, (png_uint_32)file_gamma); + png_write_complete_chunk(png_ptr, png_gAMA, buf, (png_size_t)4); +} +#endif + +#ifdef PNG_WRITE_sRGB_SUPPORTED +/* Write a sRGB chunk */ +void /* PRIVATE */ +png_write_sRGB(png_structrp png_ptr, int srgb_intent) +{ + png_byte buf[1]; + + png_debug(1, "in png_write_sRGB"); + + if (srgb_intent >= PNG_sRGB_INTENT_LAST) + png_warning(png_ptr, + "Invalid sRGB rendering intent specified"); + + buf[0]=(png_byte)srgb_intent; + png_write_complete_chunk(png_ptr, png_sRGB, buf, (png_size_t)1); +} +#endif + +#ifdef PNG_WRITE_iCCP_SUPPORTED +/* Write an iCCP chunk */ +void /* PRIVATE */ +png_write_iCCP(png_structrp png_ptr, png_const_charp name, + png_const_bytep profile) +{ + png_uint_32 name_len; + png_uint_32 profile_len; + png_byte new_name[81]; /* 1 byte for the compression byte */ + compression_state comp; + + png_debug(1, "in png_write_iCCP"); + + /* These are all internal problems: the profile should have been checked + * before when it was stored. + */ + if (profile == NULL) + png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */ + + profile_len = png_get_uint_32(profile); + + if (profile_len < 132) + png_error(png_ptr, "ICC profile too short"); + + if (profile_len & 0x03) + png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)"); + + { + png_uint_32 embedded_profile_len = png_get_uint_32(profile); + + if (profile_len != embedded_profile_len) + png_error(png_ptr, "Profile length does not match profile"); + } + + name_len = png_check_keyword(png_ptr, name, new_name); + + if (name_len == 0) + png_error(png_ptr, "iCCP: invalid keyword"); + + new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE; + + /* Make sure we include the NULL after the name and the compression type */ + ++name_len; + + png_text_compress_init(&comp, profile, profile_len); + + /* Allow for keyword terminator and compression byte */ + if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len); + + png_write_chunk_data(png_ptr, new_name, name_len); + + png_write_compressed_data_out(png_ptr, &comp); + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_sPLT_SUPPORTED +/* Write a sPLT chunk */ +void /* PRIVATE */ +png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) +{ + png_uint_32 name_len; + png_byte new_name[80]; + png_byte entrybuf[10]; + png_size_t entry_size = (spalette->depth == 8 ? 6 : 10); + png_size_t palette_size = entry_size * spalette->nentries; + png_sPLT_entryp ep; +#ifndef PNG_POINTER_INDEXING_SUPPORTED + int i; +#endif + + png_debug(1, "in png_write_sPLT"); + + name_len = png_check_keyword(png_ptr, spalette->name, new_name); + + if (name_len == 0) + png_error(png_ptr, "sPLT: invalid keyword"); + + /* Make sure we include the NULL after the name */ + png_write_chunk_header(png_ptr, png_sPLT, + (png_uint_32)(name_len + 2 + palette_size)); + + png_write_chunk_data(png_ptr, (png_bytep)new_name, + (png_size_t)(name_len + 1)); + + png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1); + + /* Loop through each palette entry, writing appropriately */ +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (ep = spalette->entries; epentries + spalette->nentries; ep++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep->red; + entrybuf[1] = (png_byte)ep->green; + entrybuf[2] = (png_byte)ep->blue; + entrybuf[3] = (png_byte)ep->alpha; + png_save_uint_16(entrybuf + 4, ep->frequency); + } + + else + { + png_save_uint_16(entrybuf + 0, ep->red); + png_save_uint_16(entrybuf + 2, ep->green); + png_save_uint_16(entrybuf + 4, ep->blue); + png_save_uint_16(entrybuf + 6, ep->alpha); + png_save_uint_16(entrybuf + 8, ep->frequency); + } + + png_write_chunk_data(png_ptr, entrybuf, entry_size); + } +#else + ep=spalette->entries; + for (i = 0; i>spalette->nentries; i++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep[i].red; + entrybuf[1] = (png_byte)ep[i].green; + entrybuf[2] = (png_byte)ep[i].blue; + entrybuf[3] = (png_byte)ep[i].alpha; + png_save_uint_16(entrybuf + 4, ep[i].frequency); + } + + else + { + png_save_uint_16(entrybuf + 0, ep[i].red); + png_save_uint_16(entrybuf + 2, ep[i].green); + png_save_uint_16(entrybuf + 4, ep[i].blue); + png_save_uint_16(entrybuf + 6, ep[i].alpha); + png_save_uint_16(entrybuf + 8, ep[i].frequency); + } + + png_write_chunk_data(png_ptr, entrybuf, entry_size); + } +#endif + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED +/* Write the sBIT chunk */ +void /* PRIVATE */ +png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) +{ + png_byte buf[4]; + png_size_t size; + + png_debug(1, "in png_write_sBIT"); + + /* Make sure we don't depend upon the order of PNG_COLOR_8 */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + png_byte maxbits; + + maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : + png_ptr->usr_bit_depth); + + if (sbit->red == 0 || sbit->red > maxbits || + sbit->green == 0 || sbit->green > maxbits || + sbit->blue == 0 || sbit->blue > maxbits) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + + buf[0] = sbit->red; + buf[1] = sbit->green; + buf[2] = sbit->blue; + size = 3; + } + + else + { + if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + + buf[0] = sbit->gray; + size = 1; + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + { + if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + + buf[size++] = sbit->alpha; + } + + png_write_complete_chunk(png_ptr, png_sBIT, buf, size); +} +#endif + +#ifdef PNG_WRITE_cHRM_SUPPORTED +/* Write the cHRM chunk */ +void /* PRIVATE */ +png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy) +{ + png_byte buf[32]; + + png_debug(1, "in png_write_cHRM"); + + /* Each value is saved in 1/100,000ths */ + png_save_int_32(buf, xy->whitex); + png_save_int_32(buf + 4, xy->whitey); + + png_save_int_32(buf + 8, xy->redx); + png_save_int_32(buf + 12, xy->redy); + + png_save_int_32(buf + 16, xy->greenx); + png_save_int_32(buf + 20, xy->greeny); + + png_save_int_32(buf + 24, xy->bluex); + png_save_int_32(buf + 28, xy->bluey); + + png_write_complete_chunk(png_ptr, png_cHRM, buf, 32); +} +#endif + +#ifdef PNG_WRITE_tRNS_SUPPORTED +/* Write the tRNS chunk */ +void /* PRIVATE */ +png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, + png_const_color_16p tran, int num_trans, int color_type) +{ + png_byte buf[6]; + + png_debug(1, "in png_write_tRNS"); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) + { + png_app_warning(png_ptr, + "Invalid number of transparent colors specified"); + return; + } + + /* Write the chunk out as it is */ + png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, + (png_size_t)num_trans); + } + + else if (color_type == PNG_COLOR_TYPE_GRAY) + { + /* One 16 bit value */ + if (tran->gray >= (1 << png_ptr->bit_depth)) + { + png_app_warning(png_ptr, + "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); + + return; + } + + png_save_uint_16(buf, tran->gray); + png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)2); + } + + else if (color_type == PNG_COLOR_TYPE_RGB) + { + /* Three 16 bit values */ + png_save_uint_16(buf, tran->red); + png_save_uint_16(buf + 2, tran->green); + png_save_uint_16(buf + 4, tran->blue); +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) +#else + if (buf[0] | buf[2] | buf[4]) +#endif + { + png_app_warning(png_ptr, + "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); + return; + } + + png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)6); + } + + else + { + png_app_warning(png_ptr, "Can't write tRNS with an alpha channel"); + } +} +#endif + +#ifdef PNG_WRITE_bKGD_SUPPORTED +/* Write the background chunk */ +void /* PRIVATE */ +png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) +{ + png_byte buf[6]; + + png_debug(1, "in png_write_bKGD"); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if ( +#ifdef PNG_MNG_FEATURES_SUPPORTED + (png_ptr->num_palette || + (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && +#endif + back->index >= png_ptr->num_palette) + { + png_warning(png_ptr, "Invalid background palette index"); + return; + } + + buf[0] = back->index; + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1); + } + + else if (color_type & PNG_COLOR_MASK_COLOR) + { + png_save_uint_16(buf, back->red); + png_save_uint_16(buf + 2, back->green); + png_save_uint_16(buf + 4, back->blue); +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) +#else + if (buf[0] | buf[2] | buf[4]) +#endif + { + png_warning(png_ptr, + "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); + + return; + } + + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)6); + } + + else + { + if (back->gray >= (1 << png_ptr->bit_depth)) + { + png_warning(png_ptr, + "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); + + return; + } + + png_save_uint_16(buf, back->gray); + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2); + } +} +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED +/* Write the histogram */ +void /* PRIVATE */ +png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) +{ + int i; + png_byte buf[3]; + + png_debug(1, "in png_write_hIST"); + + if (num_hist > (int)png_ptr->num_palette) + { + png_debug2(3, "num_hist = %d, num_palette = %d", num_hist, + png_ptr->num_palette); + + png_warning(png_ptr, "Invalid number of histogram entries specified"); + return; + } + + png_write_chunk_header(png_ptr, png_hIST, (png_uint_32)(num_hist * 2)); + + for (i = 0; i < num_hist; i++) + { + png_save_uint_16(buf, hist[i]); + png_write_chunk_data(png_ptr, buf, (png_size_t)2); + } + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_tEXt_SUPPORTED +/* Write a tEXt chunk */ +void /* PRIVATE */ +png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, + png_size_t text_len) +{ + png_uint_32 key_len; + png_byte new_key[80]; + + png_debug(1, "in png_write_tEXt"); + + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "tEXt: invalid keyword"); + + if (text == NULL || *text == '\0') + text_len = 0; + + else + text_len = strlen(text); + + if (text_len > PNG_UINT_31_MAX - (key_len+1)) + png_error(png_ptr, "tEXt: text too long"); + + /* Make sure we include the 0 after the key */ + png_write_chunk_header(png_ptr, png_tEXt, + (png_uint_32)/*checked above*/(key_len + text_len + 1)); + /* + * We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + */ + png_write_chunk_data(png_ptr, new_key, key_len + 1); + + if (text_len) + png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len); + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_zTXt_SUPPORTED +/* Write a compressed text chunk */ +void /* PRIVATE */ +png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, + png_size_t text_len, int compression) +{ + png_uint_32 key_len; + png_byte new_key[81]; + compression_state comp; + + png_debug(1, "in png_write_zTXt"); + PNG_UNUSED(text_len) /* Always use strlen */ + + if (compression == PNG_TEXT_COMPRESSION_NONE) + { + png_write_tEXt(png_ptr, key, text, 0); + return; + } + + if (compression != PNG_TEXT_COMPRESSION_zTXt) + png_error(png_ptr, "zTXt: invalid compression type"); + + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "zTXt: invalid keyword"); + + /* Add the compression method and 1 for the keyword separator. */ + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; + + /* Compute the compressed data; do it now for the length */ + png_text_compress_init(&comp, (png_const_bytep)text, + text == NULL ? 0 : strlen(text)); + + if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + /* Write start of chunk */ + png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len); + + /* Write key */ + png_write_chunk_data(png_ptr, new_key, key_len); + + /* Write the compressed data */ + png_write_compressed_data_out(png_ptr, &comp); + + /* Close the chunk */ + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_iTXt_SUPPORTED +/* Write an iTXt chunk */ +void /* PRIVATE */ +png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, + png_const_charp lang, png_const_charp lang_key, png_const_charp text) +{ + png_uint_32 key_len, prefix_len; + png_size_t lang_len, lang_key_len; + png_byte new_key[82]; + compression_state comp; + + png_debug(1, "in png_write_iTXt"); + + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "iTXt: invalid keyword"); + + /* Set the compression flag */ + switch (compression) + { + case PNG_ITXT_COMPRESSION_NONE: + case PNG_TEXT_COMPRESSION_NONE: + compression = new_key[++key_len] = 0; /* no compression */ + break; + + case PNG_TEXT_COMPRESSION_zTXt: + case PNG_ITXT_COMPRESSION_zTXt: + compression = new_key[++key_len] = 1; /* compressed */ + break; + + default: + png_error(png_ptr, "iTXt: invalid compression"); + } + + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; /* for the keywod separator */ + + /* We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG, however, + * specifies that the text is UTF-8 and this really doesn't require any + * checking. + * + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + * + * TODO: validate the language tag correctly (see the spec.) + */ + if (lang == NULL) lang = ""; /* empty language is valid */ + lang_len = strlen(lang)+1; + if (lang_key == NULL) lang_key = ""; /* may be empty */ + lang_key_len = strlen(lang_key)+1; + if (text == NULL) text = ""; /* may be empty */ + + prefix_len = key_len; + if (lang_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; + else + prefix_len = (png_uint_32)(prefix_len + lang_len); + + if (lang_key_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; + else + prefix_len = (png_uint_32)(prefix_len + lang_key_len); + + png_text_compress_init(&comp, (png_const_bytep)text, strlen(text)); + + if (compression) + { + if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + } + + else + { + if (comp.input_len > PNG_UINT_31_MAX-prefix_len) + png_error(png_ptr, "iTXt: uncompressed text too long"); + + /* So the string will fit in a chunk: */ + comp.output_len = (png_uint_32)/*SAFE*/comp.input_len; + } + + png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len); + + png_write_chunk_data(png_ptr, new_key, key_len); + + png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len); + + png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len); + + if (compression) + png_write_compressed_data_out(png_ptr, &comp); + + else + png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.input_len); + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED +/* Write the oFFs chunk */ +void /* PRIVATE */ +png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset, + int unit_type) +{ + png_byte buf[9]; + + png_debug(1, "in png_write_oFFs"); + + if (unit_type >= PNG_OFFSET_LAST) + png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); + + png_save_int_32(buf, x_offset); + png_save_int_32(buf + 4, y_offset); + buf[8] = (png_byte)unit_type; + + png_write_complete_chunk(png_ptr, png_oFFs, buf, (png_size_t)9); +} +#endif +#ifdef PNG_WRITE_pCAL_SUPPORTED +/* Write the pCAL chunk (described in the PNG extensions document) */ +void /* PRIVATE */ +png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, + png_int_32 X1, int type, int nparams, png_const_charp units, + png_charpp params) +{ + png_uint_32 purpose_len; + png_size_t units_len, total_len; + png_size_tp params_len; + png_byte buf[10]; + png_byte new_purpose[80]; + int i; + + png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); + + if (type >= PNG_EQUATION_LAST) + png_error(png_ptr, "Unrecognized equation type for pCAL chunk"); + + purpose_len = png_check_keyword(png_ptr, purpose, new_purpose); + + if (purpose_len == 0) + png_error(png_ptr, "pCAL: invalid keyword"); + + ++purpose_len; /* terminator */ + + png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); + units_len = strlen(units) + (nparams == 0 ? 0 : 1); + png_debug1(3, "pCAL units length = %d", (int)units_len); + total_len = purpose_len + units_len + 10; + + params_len = (png_size_tp)png_malloc(png_ptr, + (png_alloc_size_t)(nparams * (sizeof (png_size_t)))); + + /* Find the length of each parameter, making sure we don't count the + * null terminator for the last parameter. + */ + for (i = 0; i < nparams; i++) + { + params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1); + png_debug2(3, "pCAL parameter %d length = %lu", i, + (unsigned long)params_len[i]); + total_len += params_len[i]; + } + + png_debug1(3, "pCAL total length = %d", (int)total_len); + png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, new_purpose, purpose_len); + png_save_int_32(buf, X0); + png_save_int_32(buf + 4, X1); + buf[8] = (png_byte)type; + buf[9] = (png_byte)nparams; + png_write_chunk_data(png_ptr, buf, (png_size_t)10); + png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len); + + for (i = 0; i < nparams; i++) + { + png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]); + } + + png_free(png_ptr, params_len); + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED +/* Write the sCAL chunk */ +void /* PRIVATE */ +png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width, + png_const_charp height) +{ + png_byte buf[64]; + png_size_t wlen, hlen, total_len; + + png_debug(1, "in png_write_sCAL_s"); + + wlen = strlen(width); + hlen = strlen(height); + total_len = wlen + hlen + 2; + + if (total_len > 64) + { + png_warning(png_ptr, "Can't write sCAL (buffer too small)"); + return; + } + + buf[0] = (png_byte)unit; + memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ + memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ + + png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); + png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len); +} +#endif + +#ifdef PNG_WRITE_pHYs_SUPPORTED +/* Write the pHYs chunk */ +void /* PRIVATE */ +png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, + png_uint_32 y_pixels_per_unit, + int unit_type) +{ + png_byte buf[9]; + + png_debug(1, "in png_write_pHYs"); + + if (unit_type >= PNG_RESOLUTION_LAST) + png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); + + png_save_uint_32(buf, x_pixels_per_unit); + png_save_uint_32(buf + 4, y_pixels_per_unit); + buf[8] = (png_byte)unit_type; + + png_write_complete_chunk(png_ptr, png_pHYs, buf, (png_size_t)9); +} +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +/* Write the tIME chunk. Use either png_convert_from_struct_tm() + * or png_convert_from_time_t(), or fill in the structure yourself. + */ +void /* PRIVATE */ +png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) +{ + png_byte buf[7]; + + png_debug(1, "in png_write_tIME"); + + if (mod_time->month > 12 || mod_time->month < 1 || + mod_time->day > 31 || mod_time->day < 1 || + mod_time->hour > 23 || mod_time->second > 60) + { + png_warning(png_ptr, "Invalid time specified for tIME chunk"); + return; + } + + png_save_uint_16(buf, mod_time->year); + buf[2] = mod_time->month; + buf[3] = mod_time->day; + buf[4] = mod_time->hour; + buf[5] = mod_time->minute; + buf[6] = mod_time->second; + + png_write_complete_chunk(png_ptr, png_tIME, buf, (png_size_t)7); +} +#endif + +/* Initializes the row writing capability of libpng */ +void /* PRIVATE */ +png_write_start_row(png_structrp png_ptr) +{ +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + png_alloc_size_t buf_size; + int usr_pixel_depth; + + png_debug(1, "in png_write_start_row"); + + usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth; + buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1; + + /* 1.5.6: added to allow checking in the row write code. */ + png_ptr->transformed_pixel_depth = png_ptr->pixel_depth; + png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth; + + /* Set up row buffer */ + png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size); + + png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; + +#ifdef PNG_WRITE_FILTER_SUPPORTED + /* Set up filtering buffer, if using this filter */ + if (png_ptr->do_filter & PNG_FILTER_SUB) + { + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); + + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; + } + + /* We only need to keep the previous row if we are using one of these. */ + if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) + { + /* Set up previous row buffer */ + png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size); + + if (png_ptr->do_filter & PNG_FILTER_UP) + { + png_ptr->up_row = (png_bytep)png_malloc(png_ptr, + png_ptr->rowbytes + 1); + + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } + + if (png_ptr->do_filter & PNG_FILTER_AVG) + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + png_ptr->rowbytes + 1); + + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + + if (png_ptr->do_filter & PNG_FILTER_PAETH) + { + png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, + png_ptr->rowbytes + 1); + + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced, we need to set up width and height of pass */ + if (png_ptr->interlaced) + { + if (!(png_ptr->transformations & PNG_INTERLACE)) + { + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + + png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - + png_pass_start[0]) / png_pass_inc[0]; + } + + else + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } + } + + else +#endif + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } +} + +/* Internal use only. Called when finished processing a row of data. */ +void /* PRIVATE */ +png_write_finish_row(png_structrp png_ptr) +{ +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + png_debug(1, "in png_write_finish_row"); + + /* Next row */ + png_ptr->row_number++; + + /* See if we are done */ + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced, go to next pass */ + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + if (png_ptr->transformations & PNG_INTERLACE) + { + png_ptr->pass++; + } + + else + { + /* Loop until we find a non-zero width or height pass */ + do + { + png_ptr->pass++; + + if (png_ptr->pass >= 7) + break; + + png_ptr->usr_width = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + + if (png_ptr->transformations & PNG_INTERLACE) + break; + + } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); + + } + + /* Reset the row above the image for the next pass */ + if (png_ptr->pass < 7) + { + if (png_ptr->prev_row != NULL) + memset(png_ptr->prev_row, 0, + (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* + png_ptr->usr_bit_depth, png_ptr->width)) + 1); + + return; + } + } +#endif + + /* If we get here, we've just written the last row, so we need + to flush the compressor */ + png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH); +} + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Pick out the correct pixels for the interlace pass. + * The basic idea here is to go through the row with a source + * pointer and a destination pointer (sp and dp), and copy the + * correct pixels for the pass. As the row gets compacted, + * sp will always be >= dp, so we should never overwrite anything. + * See the default: case for the easiest code to understand. + */ +void /* PRIVATE */ +png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) +{ + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + png_debug(1, "in png_do_write_interlace"); + + /* We don't have to do anything on the last pass (6) */ + if (pass < 6) + { + /* Each pixel depth is handled separately */ + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + d = 0; + shift = 7; + + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 3); + value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; + d |= (value << shift); + + if (shift == 0) + { + shift = 7; + *dp++ = (png_byte)d; + d = 0; + } + + else + shift--; + + } + if (shift != 7) + *dp = (png_byte)d; + + break; + } + + case 2: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 6; + d = 0; + + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 2); + value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; + d |= (value << shift); + + if (shift == 0) + { + shift = 6; + *dp++ = (png_byte)d; + d = 0; + } + + else + shift -= 2; + } + if (shift != 6) + *dp = (png_byte)d; + + break; + } + + case 4: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 4; + d = 0; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 1); + value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; + d |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp++ = (png_byte)d; + d = 0; + } + + else + shift -= 4; + } + if (shift != 4) + *dp = (png_byte)d; + + break; + } + + default: + { + png_bytep sp; + png_bytep dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + png_size_t pixel_bytes; + + /* Start at the beginning */ + dp = row; + + /* Find out how many bytes each pixel takes up */ + pixel_bytes = (row_info->pixel_depth >> 3); + + /* Loop through the row, only looking at the pixels that matter */ + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + /* Find out where the original pixel is */ + sp = row + (png_size_t)i * pixel_bytes; + + /* Move the pixel */ + if (dp != sp) + memcpy(dp, sp, pixel_bytes); + + /* Next pixel */ + dp += pixel_bytes; + } + break; + } + } + /* Set new row width */ + row_info->width = (row_info->width + + png_pass_inc[pass] - 1 - + png_pass_start[pass]) / + png_pass_inc[pass]; + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + +/* This filters the row, chooses which filter to use, if it has not already + * been specified by the application, and then writes the row out with the + * chosen filter. + */ +static void png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + png_size_t row_bytes); + +#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) +#define PNG_HISHIFT 10 +#define PNG_LOMASK ((png_uint_32)0xffffL) +#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) +void /* PRIVATE */ +png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) +{ + png_bytep best_row; +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_bytep prev_row, row_buf; + png_uint_32 mins, bpp; + png_byte filter_to_do = png_ptr->do_filter; + png_size_t row_bytes = row_info->rowbytes; +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + int num_p_filters = png_ptr->num_prev_filters; +#endif + + png_debug(1, "in png_write_find_filter"); + +#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS) + { + /* These will never be selected so we need not test them. */ + filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH); + } +#endif + + /* Find out how many bytes offset each pixel is */ + bpp = (row_info->pixel_depth + 7) >> 3; + + prev_row = png_ptr->prev_row; +#endif + best_row = png_ptr->row_buf; +#ifdef PNG_WRITE_FILTER_SUPPORTED + row_buf = best_row; + mins = PNG_MAXSUM; + + /* The prediction method we use is to find which method provides the + * smallest value when summing the absolute values of the distances + * from zero, using anything >= 128 as negative numbers. This is known + * as the "minimum sum of absolute differences" heuristic. Other + * heuristics are the "weighted minimum sum of absolute differences" + * (experimental and can in theory improve compression), and the "zlib + * predictive" method (not implemented yet), which does test compressions + * of lines using different filter methods, and then chooses the + * (series of) filter(s) that give minimum compressed data size (VERY + * computationally expensive). + * + * GRR 980525: consider also + * + * (1) minimum sum of absolute differences from running average (i.e., + * keep running sum of non-absolute differences & count of bytes) + * [track dispersion, too? restart average if dispersion too large?] + * + * (1b) minimum sum of absolute differences from sliding average, probably + * with window size <= deflate window (usually 32K) + * + * (2) minimum sum of squared differences from zero or running average + * (i.e., ~ root-mean-square approach) + */ + + + /* We don't need to test the 'no filter' case if this is the only filter + * that has been chosen, as it doesn't actually do anything to the data. + */ + if ((filter_to_do & PNG_FILTER_NONE) && filter_to_do != PNG_FILTER_NONE) + { + png_bytep rp; + png_uint_32 sum = 0; + png_size_t i; + int v; + + for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) + { + v = *rp; + sum += (v < 128) ? v : 256 - v; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + png_uint_32 sumhi, sumlo; + int j; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ + + /* Reduce the sum if we match any of the previous rows */ + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + /* Factor in the cost of this filter (this is here for completeness, + * but it makes no sense to have a "cost" for the NONE filter, as + * it has the minimum possible computational cost - none). + */ + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + mins = sum; + } + + /* Sub filter */ + if (filter_to_do == PNG_FILTER_SUB) + /* It's the only filter so no testing is needed */ + { + png_bytep rp, lp, dp; + png_size_t i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + *dp = *rp; + } + + for (lp = row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + } + + best_row = png_ptr->sub_row; + } + + else if (filter_to_do & PNG_FILTER_SUB) + { + png_bytep rp, dp, lp; + png_uint_32 sum = 0, lmins = mins; + png_size_t i; + int v; + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + /* We temporarily increase the "minimum sum" by the factor we + * would reduce the sum of this filter, so that we can do the + * early exit comparison without scaling the sum each time. + */ + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + v = *dp = *rp; + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->sub_row; + } + } + + /* Up filter */ + if (filter_to_do == PNG_FILTER_UP) + { + png_bytep rp, dp, pp; + png_size_t i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; + i++, rp++, pp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + } + + best_row = png_ptr->up_row; + } + + else if (filter_to_do & PNG_FILTER_UP) + { + png_bytep rp, dp, pp; + png_uint_32 sum = 0, lmins = mins; + png_size_t i; + int v; + + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->up_row; + } + } + + /* Avg filter */ + if (filter_to_do == PNG_FILTER_AVG) + { + png_bytep rp, dp, pp, lp; + png_uint_32 i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + } + + for (lp = row_buf + 1; i < row_bytes; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) + & 0xff); + } + best_row = png_ptr->avg_row; + } + + else if (filter_to_do & PNG_FILTER_AVG) + { + png_bytep rp, dp, pp, lp; + png_uint_32 sum = 0, lmins = mins; + png_size_t i; + int v; + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = row_buf + 1; i < row_bytes; i++) + { + v = *dp++ = + (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->avg_row; + } + } + + /* Paeth filter */ + if (filter_to_do == PNG_FILTER_PAETH) + { + png_bytep rp, dp, pp, cp, lp; + png_size_t i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + } + best_row = png_ptr->paeth_row; + } + + else if (filter_to_do & PNG_FILTER_PAETH) + { + png_bytep rp, dp, pp, cp, lp; + png_uint_32 sum = 0, lmins = mins; + png_size_t i; + int v; + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + +#ifndef PNG_SLOW_PAETH + p = b - c; + pc = a - c; +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; +#else /* PNG_SLOW_PAETH */ + p = a + b - c; + pa = abs(p - a); + pb = abs(p - b); + pc = abs(p - c); + + if (pa <= pb && pa <= pc) + p = a; + + else if (pb <= pc) + p = b; + + else + p = c; +#endif /* PNG_SLOW_PAETH */ + + v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + best_row = png_ptr->paeth_row; + } + } +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + + /* Do the actual writing of the filtered row data from the chosen filter. */ + png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1); + +#ifdef PNG_WRITE_FILTER_SUPPORTED +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + /* Save the type of filter we picked this time for future calculations */ + if (png_ptr->num_prev_filters > 0) + { + int j; + + for (j = 1; j < num_p_filters; j++) + { + png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; + } + + png_ptr->prev_filters[j] = best_row[0]; + } +#endif +#endif /* PNG_WRITE_FILTER_SUPPORTED */ +} + + +/* Do the actual writing of a previously filtered row. */ +static void +png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + png_size_t full_row_length/*includes filter byte*/) +{ + png_debug(1, "in png_write_filtered_row"); + + png_debug1(2, "filter = %d", filtered_row[0]); + + png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH); + + /* Swap the current and previous rows */ + if (png_ptr->prev_row != NULL) + { + png_bytep tptr; + + tptr = png_ptr->prev_row; + png_ptr->prev_row = png_ptr->row_buf; + png_ptr->row_buf = tptr; + } + + /* Finish row - updates counters and flushes zlib if last row */ + png_write_finish_row(png_ptr); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_ptr->flush_rows++; + + if (png_ptr->flush_dist > 0 && + png_ptr->flush_rows >= png_ptr->flush_dist) + { + png_write_flush(png_ptr); + } +#endif +} +#endif /* PNG_WRITE_SUPPORTED */ +#endif//_FPDFAPI_MINI_ diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/png.h b/core/src/fxcodec/fx_lpng/lpng_v163/png.h new file mode 100644 index 0000000000..c3fb52d11a --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/png.h @@ -0,0 +1,3563 @@ + +/* png.h - header file for PNG reference library + * + * libpng version 1.6.3 - July 18, 2013 + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license (See LICENSE, below) + * + * Authors and maintainers: + * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat + * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.6.3 - July 18, 2013: Glenn + * See also "Contributing Authors", below. + * + * Note about libpng version numbers: + * + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: + * + * source png.h png.h shared-lib + * version string int version + * ------- ------ ----- ---------- + * 0.89c "1.0 beta 3" 0.89 89 1.0.89 + * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + * 0.97c 0.97 97 2.0.97 + * 0.98 0.98 98 2.0.98 + * 0.99 0.99 98 2.0.99 + * 0.99a-m 0.99 99 2.0.99 + * 1.00 1.00 100 2.1.0 [100 should be 10000] + * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + * 1.0.1 png.h string is 10001 2.1.0 + * 1.0.1a-e identical to the 10002 from here on, the shared library + * 1.0.2 source version) 10002 is 2.V where V is the source code + * 1.0.2a-b 10003 version, except as noted. + * 1.0.3 10003 + * 1.0.3a-d 10004 + * 1.0.4 10004 + * 1.0.4a-f 10005 + * 1.0.5 (+ 2 patches) 10005 + * 1.0.5a-d 10006 + * 1.0.5e-r 10100 (not source compatible) + * 1.0.5s-v 10006 (not binary compatible) + * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + * 1.0.6d-f 10007 (still binary incompatible) + * 1.0.6g 10007 + * 1.0.6h 10007 10.6h (testing xy.z so-numbering) + * 1.0.6i 10007 10.6i + * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + * 1.0.7 1 10007 (still compatible) + * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + * 1.0.8rc1 1 10008 2.1.0.8rc1 + * 1.0.8 1 10008 2.1.0.8 + * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + * 1.0.9rc1 1 10009 2.1.0.9rc1 + * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + * 1.0.9rc2 1 10009 2.1.0.9rc2 + * 1.0.9 1 10009 2.1.0.9 + * 1.0.10beta1 1 10010 2.1.0.10beta1 + * 1.0.10rc1 1 10010 2.1.0.10rc1 + * 1.0.10 1 10010 2.1.0.10 + * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + * 1.0.11rc1 1 10011 2.1.0.11rc1 + * 1.0.11 1 10011 2.1.0.11 + * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 + * 1.0.12rc1 2 10012 2.1.0.12rc1 + * 1.0.12 2 10012 2.1.0.12 + * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) + * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 + * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 + * 1.2.0rc1 3 10200 3.1.2.0rc1 + * 1.2.0 3 10200 3.1.2.0 + * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 + * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 + * 1.2.1 3 10201 3.1.2.1 + * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 + * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 + * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 + * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 + * 1.0.13 10 10013 10.so.0.1.0.13 + * 1.2.2 12 10202 12.so.0.1.2.2 + * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 + * 1.2.3 12 10203 12.so.0.1.2.3 + * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 + * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 + * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 + * 1.0.14 10 10014 10.so.0.1.0.14 + * 1.2.4 13 10204 12.so.0.1.2.4 + * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 + * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 + * 1.0.15 10 10015 10.so.0.1.0.15 + * 1.2.5 13 10205 12.so.0.1.2.5 + * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 + * 1.0.16 10 10016 10.so.0.1.0.16 + * 1.2.6 13 10206 12.so.0.1.2.6 + * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 + * 1.0.17rc1 10 10017 12.so.0.1.0.17rc1 + * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 + * 1.0.17 10 10017 12.so.0.1.0.17 + * 1.2.7 13 10207 12.so.0.1.2.7 + * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 + * 1.0.18rc1-5 10 10018 12.so.0.1.0.18rc1-5 + * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 + * 1.0.18 10 10018 12.so.0.1.0.18 + * 1.2.8 13 10208 12.so.0.1.2.8 + * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 + * 1.2.9beta4-11 13 10209 12.so.0.9[.0] + * 1.2.9rc1 13 10209 12.so.0.9[.0] + * 1.2.9 13 10209 12.so.0.9[.0] + * 1.2.10beta1-7 13 10210 12.so.0.10[.0] + * 1.2.10rc1-2 13 10210 12.so.0.10[.0] + * 1.2.10 13 10210 12.so.0.10[.0] + * 1.4.0beta1-5 14 10400 14.so.0.0[.0] + * 1.2.11beta1-4 13 10211 12.so.0.11[.0] + * 1.4.0beta7-8 14 10400 14.so.0.0[.0] + * 1.2.11 13 10211 12.so.0.11[.0] + * 1.2.12 13 10212 12.so.0.12[.0] + * 1.4.0beta9-14 14 10400 14.so.0.0[.0] + * 1.2.13 13 10213 12.so.0.13[.0] + * 1.4.0beta15-36 14 10400 14.so.0.0[.0] + * 1.4.0beta37-87 14 10400 14.so.14.0[.0] + * 1.4.0rc01 14 10400 14.so.14.0[.0] + * 1.4.0beta88-109 14 10400 14.so.14.0[.0] + * 1.4.0rc02-08 14 10400 14.so.14.0[.0] + * 1.4.0 14 10400 14.so.14.0[.0] + * 1.4.1beta01-03 14 10401 14.so.14.1[.0] + * 1.4.1rc01 14 10401 14.so.14.1[.0] + * 1.4.1beta04-12 14 10401 14.so.14.1[.0] + * 1.4.1 14 10401 14.so.14.1[.0] + * 1.4.2 14 10402 14.so.14.2[.0] + * 1.4.3 14 10403 14.so.14.3[.0] + * 1.4.4 14 10404 14.so.14.4[.0] + * 1.5.0beta01-58 15 10500 15.so.15.0[.0] + * 1.5.0rc01-07 15 10500 15.so.15.0[.0] + * 1.5.0 15 10500 15.so.15.0[.0] + * 1.5.1beta01-11 15 10501 15.so.15.1[.0] + * 1.5.1rc01-02 15 10501 15.so.15.1[.0] + * 1.5.1 15 10501 15.so.15.1[.0] + * 1.5.2beta01-03 15 10502 15.so.15.2[.0] + * 1.5.2rc01-03 15 10502 15.so.15.2[.0] + * 1.5.2 15 10502 15.so.15.2[.0] + * 1.5.3beta01-10 15 10503 15.so.15.3[.0] + * 1.5.3rc01-02 15 10503 15.so.15.3[.0] + * 1.5.3beta11 15 10503 15.so.15.3[.0] + * 1.5.3 [omitted] + * 1.5.4beta01-08 15 10504 15.so.15.4[.0] + * 1.5.4rc01 15 10504 15.so.15.4[.0] + * 1.5.4 15 10504 15.so.15.4[.0] + * 1.5.5beta01-08 15 10505 15.so.15.5[.0] + * 1.5.5rc01 15 10505 15.so.15.5[.0] + * 1.5.5 15 10505 15.so.15.5[.0] + * 1.5.6beta01-07 15 10506 15.so.15.6[.0] + * 1.5.6rc01-03 15 10506 15.so.15.6[.0] + * 1.5.6 15 10506 15.so.15.6[.0] + * 1.5.7beta01-05 15 10507 15.so.15.7[.0] + * 1.5.7rc01-03 15 10507 15.so.15.7[.0] + * 1.5.7 15 10507 15.so.15.7[.0] + * 1.6.0beta01-40 16 10600 16.so.16.0[.0] + * 1.6.0rc01-08 16 10600 16.so.16.0[.0] + * 1.6.0 16 10600 16.so.16.0[.0] + * 1.6.1beta01-09 16 10601 16.so.16.1[.0] + * 1.6.1rc01 16 10601 16.so.16.1[.0] + * 1.6.1 16 10601 16.so.16.1[.0] + * 1.6.2beta01 16 10602 16.so.16.2[.0] + * 1.6.2rc01-06 16 10602 16.so.16.2[.0] + * 1.6.2 16 10602 16.so.16.2[.0] + * 1.6.3beta01-11 16 10603 16.so.16.3[.0] + * 1.6.3rc01 16 10603 16.so.16.3[.0] + * 1.6.3 16 10603 16.so.16.3[.0] + * + * Henceforth the source version will match the shared-library major + * and minor numbers; the shared-library major version number will be + * used for changes in backward compatibility, as it is intended. The + * PNG_LIBPNG_VER macro, which is not used within libpng but is available + * for applications, is an unsigned integer of the form xyyzz corresponding + * to the source version x.y.z (leading zeros in y and z). Beta versions + * were given the previous public release number plus a letter, until + * version 1.0.6j; from then on they were given the upcoming public + * release number plus "betaNN" or "rcNN". + * + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. + * + * DLLNUM will change each time there are forward or backward changes + * in binary compatibility (e.g., when a new feature is added). + * + * See libpng-manual.txt or libpng.3 for more information. The PNG + * specification is available as a W3C Recommendation and as an ISO + * Specification, defines should NOT be changed. + */ +#define PNG_INFO_gAMA 0x0001 +#define PNG_INFO_sBIT 0x0002 +#define PNG_INFO_cHRM 0x0004 +#define PNG_INFO_PLTE 0x0008 +#define PNG_INFO_tRNS 0x0010 +#define PNG_INFO_bKGD 0x0020 +#define PNG_INFO_hIST 0x0040 +#define PNG_INFO_pHYs 0x0080 +#define PNG_INFO_oFFs 0x0100 +#define PNG_INFO_tIME 0x0200 +#define PNG_INFO_pCAL 0x0400 +#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */ + +/* This is used for the transformation routines, as some of them + * change these values for the row. It also should enable using + * the routines for other purposes. + */ +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + png_size_t rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info * png_row_infop; +typedef png_row_info * * png_row_infopp; + +/* These are the function types for the I/O functions and for the functions + * that allow the user to override the default I/O functions with his or her + * own. The png_error_ptr type should match that of user-supplied warning + * and error functions, while the png_rw_ptr type should match that of the + * user read/write data functions. Note that the 'write' function must not + * modify the buffer it is passed. The 'read' function, on the other hand, is + * expected to return the read data in the buffer. + */ +typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp)); +typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, png_size_t)); +typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp)); +typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32, + int)); +typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32, + int)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop)); +typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop)); + +/* The following callback receives png_uint_32 row_number, int pass for the + * png_bytep data of the row. When transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep, + png_uint_32, int)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop, + png_bytep)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp, + png_unknown_chunkp)); +#endif +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +/* not used anywhere */ +/* typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); */ +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This must match the function definition in , and the application + * must include this before png.h to obtain the definition of jmp_buf. The + * function is required to be PNG_NORETURN, but this is not checked. If the + * function does return the application will crash via an abort() or similar + * system level call. + * + * If you get a warning here while building the library you may need to make + * changes to ensure that pnglibconf.h records the calling convention used by + * your compiler. This may be very difficult - try using a different compiler + * to build the library! + */ +PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef); +#endif + +/* Transform masks for the high-level interface */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only */ +/* Added to libpng-1.2.34 */ +#define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER +#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ +/* Added to libpng-1.4.0 */ +#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ +/* Added to libpng-1.5.4 */ +#define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */ +#define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */ + +/* Flags for MNG supported features */ +#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 +#define PNG_FLAG_MNG_FILTER_64 0x04 +#define PNG_ALL_MNG_FEATURES 0x05 + +/* NOTE: prior to 1.5 these functions had no 'API' style declaration, + * this allowed the zlib default functions to be used on Windows + * platforms. In 1.5 the zlib default malloc (which just calls malloc and + * ignores the first argument) should be completely compatible with the + * following. + */ +typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp, + png_alloc_size_t)); +typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp)); + +/* Section 3: exported functions + * Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng-manual.txt for the + * full explanation, see example.c for the summary. This just provides + * a simple one line description of the use of each function. + * + * The PNG_EXPORT() and PNG_EXPORTA() macros used below are defined in + * pngconf.h and in the *.dfn files in the scripts directory. + * + * PNG_EXPORT(ordinal, type, name, (args)); + * + * ordinal: ordinal that is used while building + * *.def files. The ordinal value is only + * relevant when preprocessing png.h with + * the *.dfn files for building symbol table + * entries, and are removed by pngconf.h. + * type: return type of the function + * name: function name + * args: function arguments, with types + * + * When we wish to append attributes to a function prototype we use + * the PNG_EXPORTA() macro instead. + * + * PNG_EXPORTA(ordinal, type, name, (args), attributes); + * + * ordinal, type, name, and args: same as in PNG_EXPORT(). + * attributes: function attributes + */ + +/* Returns the version number of the library */ +PNG_EXPORT(1, png_uint_32, png_access_version_number, (void)); + +/* Tell lib we have already handled the first magic bytes. + * Handling more than 8 bytes from the beginning of the file is an error. + */ +PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes)); + +/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a + * PNG file. Returns zero if the supplied bytes match the 8-byte PNG + * signature, and non-zero otherwise. Having num_to_check == 0 or + * start > 7 will always fail (ie return non-zero). + */ +PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, png_size_t start, + png_size_t num_to_check)); + +/* Simple signature checking function. This is the same as calling + * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). + */ +#define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n)) + +/* Allocate and initialize png_ptr struct for reading, and any other memory. */ +PNG_EXPORTA(4, png_structp, png_create_read_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn), + PNG_ALLOCATED); + +/* Allocate and initialize png_ptr struct for writing, and any other memory */ +PNG_EXPORTA(5, png_structp, png_create_write_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn), + PNG_ALLOCATED); + +PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size, + (png_const_structrp png_ptr)); + +PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr, + png_size_t size)); + +/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp + * match up. + */ +#ifdef PNG_SETJMP_SUPPORTED +/* This function returns the jmp_buf built in to *png_ptr. It must be + * supplied with an appropriate 'longjmp' function to use on that jmp_buf + * unless the default error function is overridden in which case NULL is + * acceptable. The size of the jmp_buf is checked against the actual size + * allocated by the library - the call will return NULL on a mismatch + * indicating an ABI mismatch. + */ +PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr, + png_longjmp_ptr longjmp_fn, size_t jmp_buf_size)); +# define png_jmpbuf(png_ptr) \ + (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf)))) +#else +# define png_jmpbuf(png_ptr) \ + (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP) +#endif +/* This function should be used by libpng applications in place of + * longjmp(png_ptr->jmpbuf, val). If longjmp_fn() has been set, it + * will use it; otherwise it will call PNG_ABORT(). This function was + * added in libpng-1.5.0. + */ +PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val), + PNG_NORETURN); + +#ifdef PNG_READ_SUPPORTED +/* Reset the compression stream */ +PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED); +#endif + +/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORTA(11, png_structp, png_create_read_struct_2, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), + PNG_ALLOCATED); +PNG_EXPORTA(12, png_structp, png_create_write_struct_2, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), + PNG_ALLOCATED); +#endif + +/* Write the PNG file signature. */ +PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr)); + +/* Write a PNG chunk - size, type, (optional) data, CRC. */ +PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep + chunk_name, png_const_bytep data, png_size_t length)); + +/* Write the start of a PNG chunk - length and chunk name. */ +PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr, + png_const_bytep chunk_name, png_uint_32 length)); + +/* Write the data of a PNG chunk started with png_write_chunk_start(). */ +PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr, + png_const_bytep data, png_size_t length)); + +/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ +PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr)); + +/* Allocate and initialize the info structure */ +PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr), + PNG_ALLOCATED); + +/* DEPRECATED: this function allowed init structures to be created using the + * default allocation method (typically malloc). Use is deprecated in 1.6.0 and + * the API will be removed in the future. + */ +PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr, + png_size_t png_info_struct_size), PNG_DEPRECATED); + +/* Writes all the PNG information before the image. */ +PNG_EXPORT(20, void, png_write_info_before_PLTE, + (png_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(21, void, png_write_info, + (png_structrp png_ptr, png_const_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. */ +PNG_EXPORT(22, void, png_read_info, + (png_structrp png_ptr, png_inforp info_ptr)); +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED + /* Convert to a US string format: there is no localization support in this + * routine. The original implementation used a 29 character buffer in + * png_struct, this will be removed in future versions. + */ +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */ +PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr, + png_const_timep ptime),PNG_DEPRECATED); +#endif +PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29], + png_const_timep ptime)); +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED +/* Convert from a struct tm to png_time */ +PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime, + const struct tm * ttime)); + +/* Convert from time_t to png_time. Uses gmtime() */ +PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime)); +#endif /* PNG_CONVERT_tIME_SUPPORTED */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ +PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr)); +PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr)); +PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr)); +PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion + * of a tRNS chunk if present. + */ +PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Use blue, green, red order for pixels. */ +PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand the grayscale to 24-bit RGB if necessary. */ +PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB to grayscale. */ +#define PNG_ERROR_ACTION_NONE 1 +#define PNG_ERROR_ACTION_WARN 2 +#define PNG_ERROR_ACTION_ERROR 3 +#define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/ + +PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr, + int error_action, double red, double green)) +PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green)) + +PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp + png_ptr)); +#endif + +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, + png_colorp palette)); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* How the alpha channel is interpreted - this affects how the color channels of + * a PNG file are returned when an alpha channel, or tRNS chunk in a palette + * file, is present. + * + * This has no effect on the way pixels are written into a PNG output + * datastream. The color samples in a PNG datastream are never premultiplied + * with the alpha samples. + * + * The default is to return data according to the PNG specification: the alpha + * channel is a linear measure of the contribution of the pixel to the + * corresponding composited pixel. The gamma encoded color channels must be + * scaled according to the contribution and to do this it is necessary to undo + * the encoding, scale the color values, perform the composition and reencode + * the values. This is the 'PNG' mode. + * + * The alternative is to 'associate' the alpha with the color information by + * storing color channel values that have been scaled by the alpha. The + * advantage is that the color channels can be resampled (the image can be + * scaled) in this form. The disadvantage is that normal practice is to store + * linear, not (gamma) encoded, values and this requires 16-bit channels for + * still images rather than the 8-bit channels that are just about sufficient if + * gamma encoding is used. In addition all non-transparent pixel values, + * including completely opaque ones, must be gamma encoded to produce the final + * image. This is the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' mode (the + * latter being the two common names for associated alpha color channels.) + * + * Since it is not necessary to perform arithmetic on opaque color values so + * long as they are not to be resampled and are in the final color space it is + * possible to optimize the handling of alpha by storing the opaque pixels in + * the PNG format (adjusted for the output color space) while storing partially + * opaque pixels in the standard, linear, format. The accuracy required for + * standard alpha composition is relatively low, because the pixels are + * isolated, therefore typically the accuracy loss in storing 8-bit linear + * values is acceptable. (This is not true if the alpha channel is used to + * simulate transparency over large areas - use 16 bits or the PNG mode in + * this case!) This is the 'OPTIMIZED' mode. For this mode a pixel is + * treated as opaque only if the alpha value is equal to the maximum value. + * + * The final choice is to gamma encode the alpha channel as well. This is + * broken because, in practice, no implementation that uses this choice + * correctly undoes the encoding before handling alpha composition. Use this + * choice only if other serious errors in the software or hardware you use + * mandate it; the typical serious error is for dark halos to appear around + * opaque areas of the composited PNG image because of arithmetic overflow. + * + * The API function png_set_alpha_mode specifies which of these choices to use + * with an enumerated 'mode' value and the gamma of the required output: + */ +#define PNG_ALPHA_PNG 0 /* according to the PNG standard */ +#define PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */ +#define PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */ +#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */ +#define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */ +#define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */ + +PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode, + double output_gamma)) +PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr, + int mode, png_fixed_point output_gamma)) +#endif + +#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) +/* The output_gamma value is a screen gamma in libpng terminology: it expresses + * how to decode the output values, not how they are encoded. The values used + * correspond to the normal numbers used to describe the overall gamma of a + * computer display system; for example 2.2 for an sRGB conformant system. The + * values are scaled by 100000 in the _fixed version of the API (so 220000 for + * sRGB.) + * + * The inverse of the value is always used to provide a default for the PNG file + * encoding if it has no gAMA chunk and if png_set_gamma() has not been called + * to override the PNG gamma information. + * + * When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode + * opaque pixels however pixels with lower alpha values are not encoded, + * regardless of the output gamma setting. + * + * When the standard Porter Duff handling is requested with mode 1 the output + * encoding is set to be linear and the output_gamma value is only relevant + * as a default for input data that has no gamma information. The linear output + * encoding will be overridden if png_set_gamma() is called - the results may be + * highly unexpected! + * + * The following numbers are derived from the sRGB standard and the research + * behind it. sRGB is defined to be approximated by a PNG gAMA chunk value of + * 0.45455 (1/2.2) for PNG. The value implicitly includes any viewing + * correction required to take account of any differences in the color + * environment of the original scene and the intended display environment; the + * value expresses how to *decode* the image for display, not how the original + * data was *encoded*. + * + * sRGB provides a peg for the PNG standard by defining a viewing environment. + * sRGB itself, and earlier TV standards, actually use a more complex transform + * (a linear portion then a gamma 2.4 power law) than PNG can express. (PNG is + * limited to simple power laws.) By saying that an image for direct display on + * an sRGB conformant system should be stored with a gAMA chunk value of 45455 + * (11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification + * makes it possible to derive values for other display systems and + * environments. + * + * The Mac value is deduced from the sRGB based on an assumption that the actual + * extra viewing correction used in early Mac display systems was implemented as + * a power 1.45 lookup table. + * + * Any system where a programmable lookup table is used or where the behavior of + * the final display device characteristics can be changed requires system + * specific code to obtain the current characteristic. However this can be + * difficult and most PNG gamma correction only requires an approximate value. + * + * By default, if png_set_alpha_mode() is not called, libpng assumes that all + * values are unencoded, linear, values and that the output device also has a + * linear characteristic. This is only very rarely correct - it is invariably + * better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the + * default if you don't know what the right answer is! + * + * The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS + * 10.6) which used a correction table to implement a somewhat lower gamma on an + * otherwise sRGB system. + * + * Both these values are reserved (not simple gamma values) in order to allow + * more precise correction internally in the future. + * + * NOTE: the following values can be passed to either the fixed or floating + * point APIs, but the floating point API will also accept floating point + * values. + */ +#define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */ +#define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */ +#define PNG_GAMMA_sRGB 220000 /* Television standards--matches sRGB gamma */ +#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */ +#endif + +/* The following are examples of calls to png_set_alpha_mode to achieve the + * required overall gamma correction and, where necessary, alpha + * premultiplication. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * This is the default libpng handling of the alpha channel - it is not + * pre-multiplied into the color components. In addition the call states + * that the output is for a sRGB system and causes all PNG files without gAMA + * chunks to be assumed to be encoded using sRGB. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * In this case the output is assumed to be something like an sRGB conformant + * display preceeded by a power-law lookup table of power 1.45. This is how + * early Mac systems behaved. + * + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); + * This is the classic Jim Blinn approach and will work in academic + * environments where everything is done by the book. It has the shortcoming + * of assuming that input PNG data with no gamma information is linear - this + * is unlikely to be correct unless the PNG files where generated locally. + * Most of the time the output precision will be so low as to show + * significant banding in dark areas of the image. + * + * png_set_expand_16(pp); + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); + * This is a somewhat more realistic Jim Blinn inspired approach. PNG files + * are assumed to have the sRGB encoding if not marked with a gamma value and + * the output is always 16 bits per component. This permits accurate scaling + * and processing of the data. If you know that your input PNG files were + * generated locally you might need to replace PNG_DEFAULT_sRGB with the + * correct value for your system. + * + * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); + * If you just need to composite the PNG image onto an existing background + * and if you control the code that does this you can use the optimization + * setting. In this case you just copy completely opaque pixels to the + * output. For pixels that are not completely transparent (you just skip + * those) you do the composition math using png_composite or png_composite_16 + * below then encode the resultant 8-bit or 16-bit values to match the output + * encoding. + * + * Other cases + * If neither the PNG nor the standard linear encoding work for you because + * of the software or hardware you use then you have a big problem. The PNG + * case will probably result in halos around the image. The linear encoding + * will probably result in a washed out, too bright, image (it's actually too + * contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably + * substantially reduce the halos. Alternatively try: + * + * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); + * This option will also reduce the halos, but there will be slight dark + * halos round the opaque parts of the image where the background is light. + * In the OPTIMIZED mode the halos will be light halos where the background + * is dark. Take your pick - the halos are unavoidable unless you can get + * your hardware/software fixed! (The OPTIMIZED approach is slightly + * faster.) + * + * When the default gamma of PNG files doesn't match the output gamma. + * If you have PNG files with no gamma information png_set_alpha_mode allows + * you to provide a default gamma, but it also sets the ouput gamma to the + * matching value. If you know your PNG files have a gamma that doesn't + * match the output you can take advantage of the fact that + * png_set_alpha_mode always sets the output gamma but only sets the PNG + * default if it is not already set: + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * The first call sets both the default and the output gamma values, the + * second call overrides the output gamma without changing the default. This + * is easier than achieving the same effect with png_set_gamma. You must use + * PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will + * fire if more than one call to png_set_alpha_mode and png_set_background is + * made in the same read operation, however multiple calls with PNG_ALPHA_PNG + * are ignored. + */ + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ +PNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler, + int flags)); +/* The values of the PNG_FILLER_ defines should NOT be changed */ +# define PNG_FILLER_BEFORE 0 +# define PNG_FILLER_AFTER 1 +/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ +PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr, + png_uint_32 filler, int flags)); +#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swap bytes in 16-bit depth files. */ +PNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ +PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ + defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Swap packing order of pixels in bytes. */ +PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Converts files to legal bit depths. */ +PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p + true_bits)); +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Have the code handle the interlacing. Returns the number of passes. + * MUST be called before png_read_update_info or png_start_read_image, + * otherwise it will not have the desired effect. Note that it is still + * necessary to call png_read_row or png_read_rows png_get_image_height + * times for each pass. +*/ +PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +/* Invert monochrome files */ +PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Handle alpha and tRNS by replacing with a background color. Prior to + * libpng-1.5.4 this API must not be called before the PNG file header has been + * read. Doing so will result in unexpected behavior and possible warnings or + * errors if the PNG file contains a bKGD chunk. + */ +PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)) +PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, png_fixed_point background_gamma)) +#endif +#ifdef PNG_READ_BACKGROUND_SUPPORTED +# define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +# define PNG_BACKGROUND_GAMMA_SCREEN 1 +# define PNG_BACKGROUND_GAMMA_FILE 2 +# define PNG_BACKGROUND_GAMMA_UNIQUE 3 +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale a 16-bit depth file down to 8-bit, accurately. */ +PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_16_TO_8 SUPPORTED /* Name prior to 1.5.4 */ +/* Strip the second byte of information from a 16-bit depth file. */ +PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* Turn on quantizing, and reduce the palette to the number of colors + * available. + */ +PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_const_uint_16p histogram, int full_quantize)); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* The threshold on gamma processing is configurable but hard-wired into the + * library. The following is the floating point variant. + */ +#define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001) + +/* Handle gamma correction. Screen_gamma=(display_exponent). + * NOTE: this API simply sets the screen and file gamma values. It will + * therefore override the value for gamma in a PNG file if it is called after + * the file header has been read - use with care - call before reading the PNG + * file for best results! + * + * These routines accept the same gamma values as png_set_alpha_mode (described + * above). The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either + * API (floating point or fixed.) Notice, however, that the 'file_gamma' value + * is the inverse of a 'screen gamma' value. + */ +PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr, + double screen_gamma, double override_file_gamma)) +PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr, + png_fixed_point screen_gamma, png_fixed_point override_file_gamma)) +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set how many lines between output flushes - 0 for no flushing */ +PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows)); +/* Flush the current PNG output buffer */ +PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr)); +#endif + +/* Optional update palette with requested transformations */ +PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr)); + +/* Optional call to update the users info structure */ +PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr, + png_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. */ +PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read a row of data. */ +PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row, + png_bytep display_row)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the whole image into memory at once. */ +PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image)); +#endif + +/* Write a row of image data */ +PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr, + png_const_bytep row)); + +/* Write a few rows of image data: (*row) is not written; however, the type + * is declared as writeable to maintain compatibility with previous versions + * of libpng and to allow the 'display_row' array from read_rows to be passed + * unchanged to write_rows. + */ +PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row, + png_uint_32 num_rows)); + +/* Write the image data */ +PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image)); + +/* Write the end of the PNG file. */ +PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr, + png_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. */ +PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr)); +#endif + +/* Free any memory associated with the png_info_struct */ +PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr, + png_infopp info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr)); + +/* Set the libpng method of handling chunk CRC errors */ +PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, + int ancil_action)); + +/* Values for png_set_crc_action() say how to handle CRC errors in + * ancillary and critical chunks, and whether to use the data contained + * therein. Note that it is impossible to "discard" data in a critical + * chunk. For versions prior to 0.90, the action was always error/quit, + * whereas in version 0.90 and later, the action for CRC errors in ancillary + * chunks is warn/discard. These values should NOT be changed. + * + * value action:critical action:ancillary + */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ + +/* These functions give the user control over the scan-line filtering in + * libpng and the compression methods used by zlib. These functions are + * mainly useful for testing, as the defaults should work with most users. + * Those users who are tight on memory or want faster performance at the + * expense of compression can modify them. See the compression library + * header file (zlib.h) for an explination of the compression functions. + */ + +/* Set the filtering method(s) used by libpng. Currently, the only valid + * value for "method" is 0. + */ +PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, + int filters)); + +/* Flags for png_set_filter() to say which filters to use. The flags + * are chosen so that they don't conflict with real filter types + * below, in case they are supplied instead of the #defined constants. + * These values should NOT be changed. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. + * These defines should NOT be changed. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */ +/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ + * defines, either the default (minimum-sum-of-absolute-differences), or + * the experimental method (weighted-minimum-sum-of-absolute-differences). + * + * Weights are factors >= 1.0, indicating how important it is to keep the + * filter type consistent between rows. Larger numbers mean the current + * filter is that many times as likely to be the same as the "num_weights" + * previous filters. This is cumulative for each previous row with a weight. + * There needs to be "num_weights" values in "filter_weights", or it can be + * NULL if the weights aren't being specified. Weights have no influence on + * the selection of the first row filter. Well chosen weights can (in theory) + * improve the compression for a given image. + * + * Costs are factors >= 1.0 indicating the relative decoding costs of a + * filter type. Higher costs indicate more decoding expense, and are + * therefore less likely to be selected over a filter with lower computational + * costs. There needs to be a value in "filter_costs" for each valid filter + * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't + * setting the costs. Costs try to improve the speed of decompression without + * unduly increasing the compressed image size. + * + * A negative weight or cost indicates the default value is to be used, and + * values in the range [0.0, 1.0) indicate the value is to remain unchanged. + * The default values for both weights and costs are currently 1.0, but may + * change if good general weighting/cost heuristics can be found. If both + * the weights and costs are set to 1.0, this degenerates the WEIGHTED method + * to the UNWEIGHTED method, but with added encoding time/computation. + */ +PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr, + int heuristic_method, int num_weights, png_const_doublep filter_weights, + png_const_doublep filter_costs)) +PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, + (png_structrp png_ptr, int heuristic_method, int num_weights, + png_const_fixed_point_p filter_weights, + png_const_fixed_point_p filter_costs)) +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +/* Heuristic used for row filter selection. These defines should NOT be + * changed. + */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ + +#ifdef PNG_WRITE_SUPPORTED +/* Set the library compression level. Currently, valid values range from + * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 + * (0 - no compression, 9 - "maximal" compression). Note that tests have + * shown that zlib compression levels 3-6 usually perform as well as level 9 + * for PNG images, and do considerably fewer caclulations. In the future, + * these values may not correspond directly to the zlib compression levels. + */ +PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr, + int level)); + +PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr, + int mem_level)); + +PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr, + int window_bits)); + +PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr, + int method)); +#endif + +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +/* Also set zlib parameters for compressing non-IDAT chunks */ +PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr, + int level)); + +PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr, + int mem_level)); + +PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(225, void, png_set_text_compression_window_bits, + (png_structrp png_ptr, int window_bits)); + +PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr, + int method)); +#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ + +/* These next functions are called for input/output, memory, and error + * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + * and call standard C I/O routines such as fread(), fwrite(), and + * fprintf(). These functions can be made to use other I/O routines + * at run time for those applications that need to handle I/O in a + * different manner by calling png_set_???_fn(). See libpng-manual.txt for + * more information. + */ + +#ifdef PNG_STDIO_SUPPORTED +/* Initialize the input/output for the PNG file to the default functions. */ +PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp)); +#endif + +/* Replace the (error and abort), and warning functions with user + * supplied functions. If no messages are to be printed you must still + * write and use replacement functions. The replacement error_fn should + * still do a longjmp to the last setjmp location if you are using this + * method of error handling. If error_fn or warning_fn is NULL, the + * default function will be used. + */ + +PNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); + +/* Return the user pointer associated with the error functions */ +PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr)); + +/* Replace the default data output functions with a user supplied one(s). + * If buffered output is not used, then output_flush_fn can be set to NULL. + * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time + * output_flush_fn will be ignored (and thus can be NULL). + * It is probably a mistake to use NULL for output_flush_fn if + * write_data_fn is not also NULL unless you have built libpng with + * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's + * default flush function, which uses the standard *FILE structure, will + * be used. + */ +PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); + +/* Replace the default data input function with a user supplied one. */ +PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn)); + +/* Return the user pointer associated with the I/O functions */ +PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr)); + +PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr, + png_read_status_ptr read_row_fn)); + +PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr, + png_write_status_ptr write_row_fn)); + +#ifdef PNG_USER_MEM_SUPPORTED +/* Replace the default memory allocation functions with user supplied one(s). */ +PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +/* Return the user pointer associated with the memory functions */ +PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr read_user_transform_fn)); +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr write_user_transform_fn)); +#endif + +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr, + png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); +/* Return the user pointer associated with the user transform functions */ +PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, + (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED +/* Return information about the row currently being processed. Note that these + * APIs do not fail but will return unexpected results if called outside a user + * transform callback. Also note that when transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp)); +PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp)); +#endif + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +/* This callback is called only for *unknown* chunks. If + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED is set then it is possible to set known + * chunks to be treated as unknown, however in this case the callback must do + * any processing required by the chunk (e.g. by calling the appropriate + * png_set_ APIs.) + * + * There is no write support - on write, by default, all the chunks in the + * 'unknown' list are written in the specified position. + * + * The integer return from the callback function is interpreted thus: + * + * negative: An error occured, png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be saved. A critical + * chunk will cause an error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + * + * See "INTERACTION WTIH USER CHUNK CALLBACKS" below for important notes about + * how this behavior will change in libpng 1.7 + */ +PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +/* Sets the function callbacks for the push reader, and a pointer to a + * user-defined structure available to the callback functions. + */ +PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr, + png_voidp progressive_ptr, png_progressive_info_ptr info_fn, + png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn)); + +/* Returns the user pointer associated with the push read functions */ +PNG_EXPORT(91, png_voidp, png_get_progressive_ptr, + (png_const_structrp png_ptr)); + +/* Function to be called when data becomes available */ +PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr, + png_inforp info_ptr, png_bytep buffer, png_size_t buffer_size)); + +/* A function which may be called *only* within png_process_data to stop the + * processing of any more data. The function returns the number of bytes + * remaining, excluding any that libpng has cached internally. A subsequent + * call to png_process_data must supply these bytes again. If the argument + * 'save' is set to true the routine will first save all the pending data and + * will always return 0. + */ +PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structrp, int save)); + +/* A function which may be called *only* outside (after) a call to + * png_process_data. It returns the number of bytes of data to skip in the + * input. Normally it will return 0, but if it returns a non-zero value the + * application must skip than number of bytes of input data and pass the + * following data to the next call to png_process_data. + */ +PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp)); + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Function that combines rows. 'new_row' is a flag that should come from + * the callback and be non-NULL if anything needs to be done; the library + * stores its own version of the new data internally and ignores the passed + * in value. + */ +PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr, + png_bytep old_row, png_const_bytep new_row)); +#endif /* PNG_READ_INTERLACING_SUPPORTED */ +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); +/* Added at libpng version 1.4.0 */ +PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); + +/* Added at libpng version 1.2.4 */ +PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); + +/* Frees a pointer allocated by png_malloc() */ +PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr)); + +/* Free data that was allocated internally */ +PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 free_me, int num)); + +/* Reassign responsibility for freeing existing data, whether allocated + * by libpng or by the application; this works on the png_info structure passed + * in, it does not change the state for other png_info structures. + * + * It is unlikely that this function works correctly as of 1.6.0 and using it + * may result either in memory leaks or double free of allocated data. + */ +PNG_EXPORTA(99, void, png_data_freer, (png_const_structrp png_ptr, + png_inforp info_ptr, int freer, png_uint_32 mask), PNG_DEPRECATED); + +/* Assignments for png_data_freer */ +#define PNG_DESTROY_WILL_FREE_DATA 1 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 +/* Flags for png_ptr->free_me and info_ptr->free_me */ +#define PNG_FREE_HIST 0x0008 +#define PNG_FREE_ICCP 0x0010 +#define PNG_FREE_SPLT 0x0020 +#define PNG_FREE_ROWS 0x0040 +#define PNG_FREE_PCAL 0x0080 +#define PNG_FREE_SCAL 0x0100 +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_FREE_UNKN 0x0200 +#endif +/* PNG_FREE_LIST 0x0400 removed in 1.6.0 because it is ignored */ +#define PNG_FREE_PLTE 0x1000 +#define PNG_FREE_TRNS 0x2000 +#define PNG_FREE_TEXT 0x4000 +#define PNG_FREE_ALL 0x7fff +#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ + +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED); +PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr, + png_voidp ptr), PNG_DEPRECATED); +#endif + +#ifdef PNG_ERROR_TEXT_SUPPORTED +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); + +/* The same, but the chunk name is prepended to the error string. */ +PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); + +#else +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN); +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* Non-fatal error in libpng. Can continue, but may have a problem. */ +PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); + +/* Non-fatal error in libpng, chunk name is prepended to message. */ +PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); +#endif + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Benign error in libpng. Can continue, but may have a problem. + * User can choose whether to handle as a fatal error or as a warning. */ +PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); + +#ifdef PNG_READ_SUPPORTED +/* Same, chunk name is prepended to message (only during read) */ +PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); +#endif + +PNG_EXPORT(109, void, png_set_benign_errors, + (png_structrp png_ptr, int allowed)); +#else +# ifdef PNG_ALLOW_BENIGN_ERRORS +# define png_benign_error png_warning +# define png_chunk_benign_error png_chunk_warning +# else +# define png_benign_error png_error +# define png_chunk_benign_error png_chunk_error +# endif +#endif + +/* The png_set_ functions are for storing values in the png_info_struct. + * Similarly, the png_get_ calls are used to read values from the + * png_info_struct, either storing the parameters in the passed variables, or + * setting pointers into the png_info_struct where the data is stored. The + * png_get_ functions return a non-zero value if the data was available + * in info_ptr, or return zero and do not change any of the parameters if the + * data was not available. + * + * These functions should be used instead of directly accessing png_info + * to avoid problems with future changes in the size and internal layout of + * png_info_struct. + */ +/* Returns "flag" if chunk data is valid in info_ptr. */ +PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 flag)); + +/* Returns number of bytes needed to hold a transformed row. */ +PNG_EXPORT(111, png_size_t, png_get_rowbytes, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* Returns row_pointers, which is an array of pointers to scanlines that was + * returned from png_read_png(). + */ +PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Set row_pointers, which is an array of pointers to scanlines for use + * by png_write_png(). + */ +PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytepp row_pointers)); +#endif + +/* Returns number of color channels in image. */ +PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Returns image width in pixels. */ +PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image height in pixels. */ +PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image bit_depth. */ +PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image color_type. */ +PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image filter_type. */ +PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image interlace_type. */ +PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image compression_type. */ +PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image resolution in pixels per meter, from pHYs chunk data. */ +PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +/* Returns pixel aspect ratio, computed from pHYs chunk data. */ +PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) + +/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ +PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(128, png_int_32, png_get_x_offset_microns, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(129, png_int_32, png_get_y_offset_microns, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +#ifdef PNG_READ_SUPPORTED +/* Returns pointer to signature string read from PNG header */ +PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_16p *background)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_16p background)); +#endif + +#ifdef PNG_cHRM_SUPPORTED +PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)) +PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z, + double *green_X, double *green_Y, double *green_Z, double *blue_X, + double *blue_Y, double *blue_Z)) +PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_white_x, png_fixed_point *int_white_y, + png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, + png_fixed_point *int_blue_x, png_fixed_point *int_blue_y)) +PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z)) +#endif + +#ifdef PNG_cHRM_SUPPORTED +PNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, + double white_x, double white_y, double red_x, double red_y, double green_x, + double green_y, double blue_x, double blue_y)) +PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr, + png_inforp info_ptr, double red_X, double red_Y, double red_Z, + double green_X, double green_Y, double green_Z, double blue_X, + double blue_Y, double blue_Z)) +PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_white_x, + png_fixed_point int_white_y, png_fixed_point int_red_x, + png_fixed_point int_red_y, png_fixed_point int_green_x, + png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)) +PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z)) +#endif + +#ifdef PNG_gAMA_SUPPORTED +PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *file_gamma)) +PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_file_gamma)) +#endif + +#ifdef PNG_gAMA_SUPPORTED +PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr, + png_inforp info_ptr, double file_gamma)) +PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_file_gamma)) +#endif + +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_16p *hist)); +#endif + +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_uint_16p hist)); +#endif + +PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); + +PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); +#endif + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charp *purpose, png_int_32 *X0, + png_int_32 *X1, int *type, int *nparams, png_charp *units, + png_charpp *params)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_const_charp units, png_charpp params)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +#endif + +PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr, + png_inforp info_ptr, png_colorp *palette, int *num_palette)); + +PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr, + png_inforp info_ptr, png_const_colorp palette, int num_palette)); + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_8p *sig_bit)); +#endif + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_8p sig_bit)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *file_srgb_intent)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); +PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charpp name, int *compression_type, + png_bytepp profile, png_uint_32 *proflen)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp name, int compression_type, + png_const_bytep profile, png_uint_32 proflen)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_sPLT_tpp entries)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)); +#endif + +#ifdef PNG_TEXT_SUPPORTED +/* png_get_text also returns the number of text chunks in *num_text */ +PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_textp *text_ptr, int *num_text)); +#endif + +/* Note while png_set_text() will accept a structure whose text, + * language, and translated keywords are NULL pointers, the structure + * returned by png_get_text will always contain regular + * zero-terminated C strings. They might be empty strings but + * they will never be NULL pointers. + */ + +#ifdef PNG_TEXT_SUPPORTED +PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_timep *mod_time)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_timep mod_time)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, + png_color_16p *trans_color)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr, + png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, + png_const_color_16p trans_color)); +#endif + +#ifdef PNG_sCAL_SUPPORTED +PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *unit, double *width, double *height)) +#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ + defined(PNG_FLOATING_POINT_SUPPORTED) +/* NOTE: this API is currently implemented using floating point arithmetic, + * consequently it can only be used on systems with floating point support. + * In any case the range of values supported by png_fixed_point is small and it + * is highly recommended that png_get_sCAL_s be used instead. + */ +PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_fixed_point *width, png_fixed_point *height)) +#endif +PNG_EXPORT(169, png_uint_32, png_get_sCAL_s, + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_charpp swidth, png_charpp sheight)); + +PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, double width, double height)) +PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, png_fixed_point width, + png_fixed_point height)) +PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, + png_const_charp swidth, png_const_charp sheight)); +#endif /* PNG_sCAL_SUPPORTED */ + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +/* Provide the default handling for all unknown chunks or, optionally, for + * specific unknown chunks. + * + * NOTE: prior to 1.6.0 the handling specified for particular chunks on read was + * ignored and the default was used, the per-chunk setting only had an effect on + * write. If you wish to have chunk-specific handling on read in code that must + * work on earlier versions you must use a user chunk callback to specify the + * desired handling (keep or discard.) + * + * The 'keep' parameter is a PNG_HANDLE_CHUNK_ value as listed below. The + * parameter is interpreted as follows: + * + * READ: + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Known chunks: do normal libpng processing, do not keep the chunk (but + * see the comments below about PNG_HANDLE_AS_UNKNOWN_SUPPORTED) + * Unknown chunks: for a specific chunk use the global default, when used + * as the default discard the chunk data. + * PNG_HANDLE_CHUNK_NEVER: + * Discard the chunk data. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Keep the chunk data if the chunk is not critical else raise a chunk + * error. + * PNG_HANDLE_CHUNK_ALWAYS: + * Keep the chunk data. + * + * If the chunk data is saved it can be retrieved using png_get_unknown_chunks, + * below. Notice that specifying "AS_DEFAULT" as a global default is equivalent + * to specifying "NEVER", however when "AS_DEFAULT" is used for specific chunks + * it simply resets the behavior to the libpng default. + * + * INTERACTION WTIH USER CHUNK CALLBACKS: + * The per-chunk handling is always used when there is a png_user_chunk_ptr + * callback and the callback returns 0; the chunk is then always stored *unless* + * it is critical and the per-chunk setting is other than ALWAYS. Notice that + * the global default is *not* used in this case. (In effect the per-chunk + * value is incremented to at least IF_SAFE.) + * + * IMPORTANT NOTE: this behavior will change in libpng 1.7 - the global and + * per-chunk defaults will be honored. If you want to preserve the current + * behavior when your callback returns 0 you must set PNG_HANDLE_CHUNK_IF_SAFE + * as the default - if you don't do this libpng 1.6 will issue a warning. + * + * If you want unhandled unknown chunks to be discarded in libpng 1.6 and + * earlier simply return '1' (handled). + * + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED: + * If this is *not* set known chunks will always be handled by libpng and + * will never be stored in the unknown chunk list. Known chunks listed to + * png_set_keep_unknown_chunks will have no effect. If it is set then known + * chunks listed with a keep other than AS_DEFAULT will *never* be processed + * by libpng, in addition critical chunks must either be processed by the + * callback or saved. + * + * The IHDR and IEND chunks must not be listed. Because this turns off the + * default handling for chunks that would otherwise be recognized the + * behavior of libpng transformations may well become incorrect! + * + * WRITE: + * When writing chunks the options only apply to the chunks specified by + * png_set_unknown_chunks (below), libpng will *always* write known chunks + * required by png_set_ calls and will always write the core critical chunks + * (as required for PLTE). + * + * Each chunk in the png_set_unknown_chunks list is looked up in the + * png_set_keep_unknown_chunks list to find the keep setting, this is then + * interpreted as follows: + * + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Write safe-to-copy chunks and write other chunks if the global + * default is set to _ALWAYS, otherwise don't write this chunk. + * PNG_HANDLE_CHUNK_NEVER: + * Do not write the chunk. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Write the chunk if it is safe-to-copy, otherwise do not write it. + * PNG_HANDLE_CHUNK_ALWAYS: + * Write the chunk. + * + * Note that the default behavior is effectively the opposite of the read case - + * in read unknown chunks are not stored by default, in write they are written + * by default. Also the behavior of PNG_HANDLE_CHUNK_IF_SAFE is very different + * - on write the safe-to-copy bit is checked, on read the critical bit is + * checked and on read if the chunk is critical an error will be raised. + * + * num_chunks: + * =========== + * If num_chunks is positive, then the "keep" parameter specifies the manner + * for handling only those chunks appearing in the chunk_list array, + * otherwise the chunk list array is ignored. + * + * If num_chunks is 0 the "keep" parameter specifies the default behavior for + * unknown chunks, as described above. + * + * If num_chunks is negative, then the "keep" parameter specifies the manner + * for handling all unknown chunks plus all chunks recognized by libpng + * except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to + * be processed by libpng. + */ +PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr, + int keep, png_const_bytep chunk_list, int num_chunks)); + +/* The "keep" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned; + * the result is therefore true (non-zero) if special handling is required, + * false for the default handling. + */ +PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr, + png_const_bytep chunk_name)); +#endif + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, + int num_unknowns)); + /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added + * unknowns to the location currently stored in the png_struct. This is + * invariably the wrong value on write. To fix this call the following API + * for each chunk in the list with the correct location. If you know your + * code won't be compiled on earlier versions you can rely on + * png_set_unknown_chunks(write-ptr, png_get_unknown_chunks(read-ptr)) doing + * the correct thing. + */ + +PNG_EXPORT(175, void, png_set_unknown_chunk_location, + (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location)); + +PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_unknown_chunkpp entries)); +#endif + +/* Png_free_data() will turn off the "valid" flag for anything it frees. + * If you need to turn it off for a chunk that your application has freed, + * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); + */ +PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr, + png_inforp info_ptr, int mask)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* The "params" pointer is currently not used and is for future expansion. */ +PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr, + int transforms, png_voidp params)); +PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr, + int transforms, png_voidp params)); +#endif + +PNG_EXPORT(180, png_const_charp, png_get_copyright, + (png_const_structrp png_ptr)); +PNG_EXPORT(181, png_const_charp, png_get_header_ver, + (png_const_structrp png_ptr)); +PNG_EXPORT(182, png_const_charp, png_get_header_version, + (png_const_structrp png_ptr)); +PNG_EXPORT(183, png_const_charp, png_get_libpng_ver, + (png_const_structrp png_ptr)); + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr, + png_uint_32 mng_features_permitted)); +#endif + +/* For use in png_set_keep_unknown, added to version 1.2.6 */ +#define PNG_HANDLE_CHUNK_AS_DEFAULT 0 +#define PNG_HANDLE_CHUNK_NEVER 1 +#define PNG_HANDLE_CHUNK_IF_SAFE 2 +#define PNG_HANDLE_CHUNK_ALWAYS 3 +#define PNG_HANDLE_CHUNK_LAST 4 + +/* Strip the prepended error numbers ("#nnn ") from error and warning + * messages before passing them to the error or warning handler. + */ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr, + png_uint_32 strip_mode)); +#endif + +/* Added in libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr, + png_uint_32 user_width_max, png_uint_32 user_height_max)); +PNG_EXPORT(187, png_uint_32, png_get_user_width_max, + (png_const_structrp png_ptr)); +PNG_EXPORT(188, png_uint_32, png_get_user_height_max, + (png_const_structrp png_ptr)); +/* Added in libpng-1.4.0 */ +PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr, + png_uint_32 user_chunk_cache_max)); +PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max, + (png_const_structrp png_ptr)); +/* Added in libpng-1.4.1 */ +PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr, + png_alloc_size_t user_chunk_cache_max)); +PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max, + (png_const_structrp png_ptr)); +#endif + +#if defined(PNG_INCH_CONVERSIONS_SUPPORTED) +PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_FP_EXPORT(196, float, png_get_x_offset_inches, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#endif + +PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr, + png_const_inforp info_ptr)) +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#endif + +# ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); +# endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ + +/* Added in libpng-1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED +PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr)); + +/* Removed from libpng 1.6; use png_get_io_chunk_type. */ +PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr), + PNG_DEPRECATED) + +PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, + (png_const_structrp png_ptr)); + +/* The flags returned by png_get_io_state() are the following: */ +# define PNG_IO_NONE 0x0000 /* no I/O at this moment */ +# define PNG_IO_READING 0x0001 /* currently reading */ +# define PNG_IO_WRITING 0x0002 /* currently writing */ +# define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */ +# define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ +# define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ +# define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ +# define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ +# define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ +#endif /* ?PNG_IO_STATE_SUPPORTED */ + +/* Interlace support. The following macros are always defined so that if + * libpng interlace handling is turned off the macros may be used to handle + * interlaced images within the application. + */ +#define PNG_INTERLACE_ADAM7_PASSES 7 + +/* Two macros to return the first row and first column of the original, + * full, image which appears in a given pass. 'pass' is in the range 0 + * to 6 and the result is in the range 0 to 7. + */ +#define PNG_PASS_START_ROW(pass) (((1&~(pass))<<(3-((pass)>>1)))&7) +#define PNG_PASS_START_COL(pass) (((1& (pass))<<(3-(((pass)+1)>>1)))&7) + +/* A macro to return the offset between pixels in the output row for a pair of + * pixels in the input - effectively the inverse of the 'COL_SHIFT' macro that + * follows. Note that ROW_OFFSET is the offset from one row to the next whereas + * COL_OFFSET is from one column to the next, within a row. + */ +#define PNG_PASS_ROW_OFFSET(pass) ((pass)>2?(8>>(((pass)-1)>>1)):8) +#define PNG_PASS_COL_OFFSET(pass) (1<<((7-(pass))>>1)) + +/* Two macros to help evaluate the number of rows or columns in each + * pass. This is expressed as a shift - effectively log2 of the number or + * rows or columns in each 8x8 tile of the original image. + */ +#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) +#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) + +/* Hence two macros to determine the number of rows or columns in a given + * pass of an image given its height or width. In fact these macros may + * return non-zero even though the sub-image is empty, because the other + * dimension may be empty for a small image. + */ +#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) +#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) + +/* For the reader row callbacks (both progressive and sequential) it is + * necessary to find the row in the output image given a row in an interlaced + * image, so two more macros: + */ +#define PNG_ROW_FROM_PASS_ROW(y_in, pass) \ + (((y_in)<>(((7-(off))-(pass))<<2)) & 0xF) | \ + ((0x01145AF0>>(((7-(off))-(pass))<<2)) & 0xF0)) + +#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ + ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) +#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ + ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) + +#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED +/* With these routines we avoid an integer divide, which will be slower on + * most machines. However, it does take more operations than the corresponding + * divide method, so it may be slower on a few RISC systems. There are two + * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. + * + * Note that the rounding factors are NOT supposed to be the same! 128 and + * 32768 are correct for the NODIV code; 127 and 32767 are correct for the + * standard method. + * + * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] + */ + + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + +# define png_composite(composite, fg, alpha, bg) \ + { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \ + * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 \ + - (png_uint_16)(alpha)) + 128); \ + (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } + +# define png_composite_16(composite, fg, alpha, bg) \ + { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ + * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(65535 \ + - (png_uint_32)(alpha)) + 32768); \ + (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } + +#else /* Standard method using integer division */ + +# define png_composite(composite, fg, alpha, bg) \ + (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + 127) / 255) + +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ + 32767) / 65535) +#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ + +#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf)); +PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf)); +PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf)); +#endif + +PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr, + png_const_bytep buf)); +/* No png_get_int_16 -- may be added if there's a real need for it. */ + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i)); +#endif +#ifdef PNG_SAVE_INT_32_SUPPORTED +PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i)); +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); +/* No png_save_int_16 -- may be added if there's a real need for it. */ +#endif + +#ifdef PNG_USE_READ_MACROS +/* Inline macros to do direct reads of bytes from the input buffer. + * The png_get_int_32() routine assumes we are using two's complement + * format for negative values, which is almost certainly true. + */ +# define PNG_get_uint_32(buf) \ + (((png_uint_32)(*(buf)) << 24) + \ + ((png_uint_32)(*((buf) + 1)) << 16) + \ + ((png_uint_32)(*((buf) + 2)) << 8) + \ + ((png_uint_32)(*((buf) + 3)))) + + /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the + * function) incorrectly returned a value of type png_uint_32. + */ +# define PNG_get_uint_16(buf) \ + ((png_uint_16) \ + (((unsigned int)(*(buf)) << 8) + \ + ((unsigned int)(*((buf) + 1))))) + +# define PNG_get_int_32(buf) \ + ((png_int_32)((*(buf) & 0x80) \ + ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffffL) + 1)) \ + : (png_int_32)png_get_uint_32(buf))) + + /* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h, + * but defining a macro name prefixed with PNG_PREFIX. + */ +# ifndef PNG_PREFIX +# define png_get_uint_32(buf) PNG_get_uint_32(buf) +# define png_get_uint_16(buf) PNG_get_uint_16(buf) +# define png_get_int_32(buf) PNG_get_int_32(buf) +# endif +#else +# ifdef PNG_PREFIX + /* No macros; revert to the (redefined) function */ +# define PNG_get_uint_32 (png_get_uint_32) +# define PNG_get_uint_16 (png_get_uint_16) +# define PNG_get_int_32 (png_get_int_32) +# endif +#endif + +/******************************************************************************* + * SIMPLIFIED API + ******************************************************************************* + * + * Please read the documentation in libpng-manual.txt (TODO: write said + * documentation) if you don't understand what follows. + * + * The simplified API hides the details of both libpng and the PNG file format + * itself. It allows PNG files to be read into a very limited number of + * in-memory bitmap formats or to be written from the same formats. If these + * formats do not accomodate your needs then you can, and should, use the more + * sophisticated APIs above - these support a wide variety of in-memory formats + * and a wide variety of sophisticated transformations to those formats as well + * as a wide variety of APIs to manipulate ancillary information. + * + * To read a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure (see below) on the stack and set the + * version field to PNG_IMAGE_VERSION. + * 2) Call the appropriate png_image_begin_read... function. + * 3) Set the png_image 'format' member to the required sample format. + * 4) Allocate a buffer for the image and, if required, the color-map. + * 5) Call png_image_finish_read to read the image and, if required, the + * color-map into your buffers. + * + * There are no restrictions on the format of the PNG input itself; all valid + * color types, bit depths, and interlace methods are acceptable, and the + * input image is transformed as necessary to the requested in-memory format + * during the png_image_finish_read() step. The only caveat is that if you + * request a color-mapped image from a PNG that is full-color or makes + * complex use of an alpha channel the transformation is extremely lossy and the + * result may look terrible. + * + * To write a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure on the stack and memset() it to all zero. + * 2) Initialize the members of the structure that describe the image, setting + * the 'format' member to the format of the image samples. + * 3) Call the appropriate png_image_write... function with a pointer to the + * image and, if necessary, the color-map to write the PNG data. + * + * png_image is a structure that describes the in-memory format of an image + * when it is being read or defines the in-memory format of an image that you + * need to write: + */ +#define PNG_IMAGE_VERSION 1 + +typedef struct png_control *png_controlp; +typedef struct +{ + png_controlp opaque; /* Initialize to NULL, free with png_image_free */ + png_uint_32 version; /* Set to PNG_IMAGE_VERSION */ + png_uint_32 width; /* Image width in pixels (columns) */ + png_uint_32 height; /* Image height in pixels (rows) */ + png_uint_32 format; /* Image format as defined below */ + png_uint_32 flags; /* A bit mask containing informational flags */ + png_uint_32 colormap_entries; + /* Number of entries in the color-map */ + + /* In the event of an error or warning the following field will be set to a + * non-zero value and the 'message' field will contain a '\0' terminated + * string with the libpng error or warning message. If both warnings and + * an error were encountered, only the error is recorded. If there + * are multiple warnings, only the first one is recorded. + * + * The upper 30 bits of this value are reserved, the low two bits contain + * a value as follows: + */ +# define PNG_IMAGE_WARNING 1 +# define PNG_IMAGE_ERROR 2 + /* + * The result is a two bit code such that a value more than 1 indicates + * a failure in the API just called: + * + * 0 - no warning or error + * 1 - warning + * 2 - error + * 3 - error preceded by warning + */ +# define PNG_IMAGE_FAILED(png_cntrl) ((((png_cntrl).warning_or_error)&0x03)>1) + + png_uint_32 warning_or_error; + + char message[64]; +} png_image, *png_imagep; + +/* The samples of the image have one to four channels whose components have + * original values in the range 0 to 1.0: + * + * 1: A single gray or luminance channel (G). + * 2: A gray/luminance channel and an alpha channel (GA). + * 3: Three red, green, blue color channels (RGB). + * 4: Three color channels and an alpha channel (RGBA). + * + * The components are encoded in one of two ways: + * + * a) As a small integer, value 0..255, contained in a single byte. For the + * alpha channel the original value is simply value/255. For the color or + * luminance channels the value is encoded according to the sRGB specification + * and matches the 8-bit format expected by typical display devices. + * + * The color/gray channels are not scaled (pre-multiplied) by the alpha + * channel and are suitable for passing to color management software. + * + * b) As a value in the range 0..65535, contained in a 2-byte integer. All + * channels can be converted to the original value by dividing by 65535; all + * channels are linear. Color channels use the RGB encoding (RGB end-points) of + * the sRGB specification. This encoding is identified by the + * PNG_FORMAT_FLAG_LINEAR flag below. + * + * When the simplified API needs to convert between sRGB and linear colorspaces, + * the actual sRGB transfer curve defined in the sRGB specification (see the + * article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 + * approximation used elsewhere in libpng. + * + * When an alpha channel is present it is expected to denote pixel coverage + * of the color or luminance channels and is returned as an associated alpha + * channel: the color/gray channels are scaled (pre-multiplied) by the alpha + * value. + * + * The samples are either contained directly in the image data, between 1 and 8 + * bytes per pixel according to the encoding, or are held in a color-map indexed + * by bytes in the image data. In the case of a color-map the color-map entries + * are individual samples, encoded as above, and the image data has one byte per + * pixel to select the relevant sample from the color-map. + */ + +/* PNG_FORMAT_* + * + * #defines to be used in png_image::format. Each #define identifies a + * particular layout of sample data and, if present, alpha values. There are + * separate defines for each of the two component encodings. + * + * A format is built up using single bit flag values. All combinations are + * valid. Formats can be built up from the flag values or you can use one of + * the predefined values below. When testing formats always use the FORMAT_FLAG + * macros to test for individual features - future versions of the library may + * add new flags. + * + * When reading or writing color-mapped images the format should be set to the + * format of the entries in the color-map then png_image_{read,write}_colormap + * called to read or write the color-map and set the format correctly for the + * image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! + * + * NOTE: libpng can be built with particular features disabled, if you see + * compiler errors because the definition of one of the following flags has been + * compiled out it is because libpng does not have the required support. It is + * possible, however, for the libpng configuration to enable the format on just + * read or just write; in that case you may see an error at run time. You can + * guard against this by checking for the definition of the appropriate + * "_SUPPORTED" macro, one of: + * + * PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED + */ +#define PNG_FORMAT_FLAG_ALPHA 0x01U /* format with an alpha channel */ +#define PNG_FORMAT_FLAG_COLOR 0x02U /* color format: otherwise grayscale */ +#define PNG_FORMAT_FLAG_LINEAR 0x04U /* 2 byte channels else 1 byte */ +#define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */ + +#ifdef PNG_FORMAT_BGR_SUPPORTED +# define PNG_FORMAT_FLAG_BGR 0x10U /* BGR colors, else order is RGB */ +#endif + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED +# define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */ +#endif + +/* Commonly used formats have predefined macros. + * + * First the single byte (sRGB) formats: + */ +#define PNG_FORMAT_GRAY 0 +#define PNG_FORMAT_GA PNG_FORMAT_FLAG_ALPHA +#define PNG_FORMAT_AG (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_RGB PNG_FORMAT_FLAG_COLOR +#define PNG_FORMAT_BGR (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR) +#define PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST) + +/* Then the linear 2-byte formats. When naming these "Y" is used to + * indicate a luminance (gray) channel. + */ +#define PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR +#define PNG_FORMAT_LINEAR_Y_ALPHA (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_LINEAR_RGB (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR) +#define PNG_FORMAT_LINEAR_RGB_ALPHA \ + (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA) + +/* With color-mapped formats the image data is one byte for each pixel, the byte + * is an index into the color-map which is formatted as above. To obtain a + * color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP + * to one of the above definitions, or you can use one of the definitions below. + */ +#define PNG_FORMAT_RGB_COLORMAP (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGR_COLORMAP (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_RGBA_COLORMAP (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ARGB_COLORMAP (PNG_FORMAT_ARGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGRA_COLORMAP (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ABGR_COLORMAP (PNG_FORMAT_ABGR|PNG_FORMAT_FLAG_COLORMAP) + +/* PNG_IMAGE macros + * + * These are convenience macros to derive information from a png_image + * structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the + * actual image sample values - either the entries in the color-map or the + * pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values + * for the pixels and will always return 1 for color-mapped formats. The + * remaining macros return information about the rows in the image and the + * complete image. + * + * NOTE: All the macros that take a png_image::format parameter are compile time + * constants if the format parameter is, itself, a constant. Therefore these + * macros can be used in array declarations and case labels where required. + * Similarly the macros are also pre-processor constants (sizeof is not used) so + * they can be used in #if tests. + * + * First the information about the samples. + */ +#define PNG_IMAGE_SAMPLE_CHANNELS(fmt)\ + (((fmt)&(PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA))+1) + /* Return the total number of channels in a given format: 1..4 */ + +#define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)\ + ((((fmt) & PNG_FORMAT_FLAG_LINEAR) >> 2)+1) + /* Return the size in bytes of a single component of a pixel or color-map + * entry (as appropriate) in the image: 1 or 2. + */ + +#define PNG_IMAGE_SAMPLE_SIZE(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)) + /* This is the size of the sample data for one sample. If the image is + * color-mapped it is the size of one color-map entry (and image pixels are + * one byte in size), otherwise it is the size of one image pixel. + */ + +#define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256) + /* The maximum size of the color-map required by the format expressed in a + * count of components. This can be used to compile-time allocate a + * color-map: + * + * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)]; + * + * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)]; + * + * Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the + * information from one of the png_image_begin_read_ APIs and dynamically + * allocate the required memory. + */ + +/* Corresponding information about the pixels */ +#define PNG_IMAGE_PIXEL_(test,fmt)\ + (((fmt)&PNG_FORMAT_FLAG_COLORMAP)?1:test(fmt)) + +#define PNG_IMAGE_PIXEL_CHANNELS(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS,fmt) + /* The number of separate channels (components) in a pixel; 1 for a + * color-mapped image. + */ + +#define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE,fmt) + /* The size, in bytes, of each component in a pixel; 1 for a color-mapped + * image. + */ + +#define PNG_IMAGE_PIXEL_SIZE(fmt) PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_SIZE,fmt) + /* The size, in bytes, of a complete pixel; 1 for a color-mapped image. */ + +/* Information about the whole row, or whole image */ +#define PNG_IMAGE_ROW_STRIDE(image)\ + (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width) + /* Return the total number of components in a single row of the image; this + * is the minimum 'row stride', the minimum count of components between each + * row. For a color-mapped image this is the minimum number of bytes in a + * row. + */ + +#define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\ + (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride)) + /* Return the size, in bytes, of an image buffer given a png_image and a row + * stride - the number of components to leave space for in each row. + */ + +#define PNG_IMAGE_SIZE(image)\ + PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image)) + /* Return the size, in bytes, of the image in memory given just a png_image; + * the row stride is the minimum stride required for the image. + */ + +#define PNG_IMAGE_COLORMAP_SIZE(image)\ + (PNG_IMAGE_SAMPLE_SIZE((image).format) * (image).colormap_entries) + /* Return the size, in bytes, of the color-map of this image. If the image + * format is not a color-map format this will return a size sufficient for + * 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if + * you don't want to allocate a color-map in this case. + */ + +/* PNG_IMAGE_FLAG_* + * + * Flags containing additional information about the image are held in the + * 'flags' field of png_image. + */ +#define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01 + /* This indicates the the RGB values of the in-memory bitmap do not + * correspond to the red, green and blue end-points defined by sRGB. + */ + +#define PNG_IMAGE_FLAG_FAST 0x02 + /* On write emphasise speed over compression; the resultant PNG file will be + * larger but will be produced significantly faster, particular for large + * images. Do not use this option for images which will be distributed, only + * used it when producing intermediate files that will be read back in + * repeatedly. For a typical 24-bit image the option will double the read + * speed at the cost of increasing the image size by 25%, however for many + * more compressible images the PNG file can be 10 times larger with only a + * slight speed gain. + */ + +#define PNG_IMAGE_FLAG_16BIT_sRGB 0x04 + /* On read if the image is a 16-bit per component image and there is no gAMA + * or sRGB chunk assume that the components are sRGB encoded. Notice that + * images output by the simplified API always have gamma information; setting + * this flag only affects the interpretation of 16-bit images from an + * external source. It is recommended that the application expose this flag + * to the user; the user can normally easily recognize the difference between + * linear and sRGB encoding. This flag has no effect on write - the data + * passed to the write APIs must have the correct encoding (as defined + * above.) + * + * If the flag is not set (the default) input 16-bit per component data is + * assumed to be linear. + * + * NOTE: the flag can only be set after the png_image_begin_read_ call, + * because that call initializes the 'flags' field. + */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* READ APIs + * --------- + * + * The png_image passed to the read APIs must have been initialized by setting + * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.) + */ +#ifdef PNG_STDIO_SUPPORTED +PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image, + const char *file_name)); + /* The named file is opened for read and the image header is filled in + * from the PNG header in the file. + */ + +PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image, + FILE* file)); + /* The PNG header is read from the stdio FILE object. */ +#endif /* PNG_STDIO_SUPPORTED */ + +PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image, + png_const_voidp memory, png_size_t size)); + /* The PNG header is read from the given memory buffer. */ + +PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image, + png_const_colorp background, void *buffer, png_int_32 row_stride, + void *colormap)); + /* Finish reading the image into the supplied buffer and clean up the + * png_image structure. + * + * row_stride is the step, in byte or 2-byte units as appropriate, + * between adjacent rows. A positive stride indicates that the top-most row + * is first in the buffer - the normal top-down arrangement. A negative + * stride indicates that the bottom-most row is first in the buffer. + * + * background need only be supplied if an alpha channel must be removed from + * a png_byte format and the removal is to be done by compositing on a solid + * color; otherwise it may be NULL and any composition will be done directly + * onto the buffer. The value is an sRGB color to use for the background, + * for grayscale output the green channel is used. + * + * background must be supplied when an alpha channel must be removed from a + * single byte color-mapped output format, in other words if: + * + * 1) The original format from png_image_begin_read_from_* had + * PNG_FORMAT_FLAG_ALPHA set. + * 2) The format set by the application does not. + * 3) The format set by the application has PNG_FORMAT_FLAG_COLORMAP set and + * PNG_FORMAT_FLAG_LINEAR *not* set. + * + * For linear output removing the alpha channel is always done by compositing + * on black and background is ignored. + * + * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set. It must + * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE. + * image->colormap_entries will be updated to the actual number of entries + * written to the colormap; this may be less than the original value. + */ + +PNG_EXPORT(238, void, png_image_free, (png_imagep image)); + /* Free any data allocated by libpng in image->opaque, setting the pointer to + * NULL. May be called at any time after the structure is initialized. + */ +#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED +/* WRITE APIS + * ---------- + * For write you must initialize a png_image structure to describe the image to + * be written. To do this use memset to set the whole structure to 0 then + * initialize fields describing your image. + * + * version: must be set to PNG_IMAGE_VERSION + * opaque: must be initialized to NULL + * width: image width in pixels + * height: image height in rows + * format: the format of the data (image and color-map) you wish to write + * flags: set to 0 unless one of the defined flags applies; set + * PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images where the RGB + * values do not correspond to the colors in sRGB. + * colormap_entries: set to the number of entries in the color-map (0 to 256) + */ +PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image, + const char *file, int convert_to_8bit, const void *buffer, + png_int_32 row_stride, const void *colormap)); + /* Write the image to the named file. */ + +PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, + int convert_to_8_bit, const void *buffer, png_int_32 row_stride, + const void *colormap)); + /* Write the image to the given (FILE*). */ + +/* With both write APIs if image is in one of the linear formats with 16-bit + * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG + * gamma encoded according to the sRGB specification, otherwise a 16-bit linear + * encoded PNG file is written. + * + * With color-mapped data formats the colormap parameter point to a color-map + * with at least image->colormap_entries encoded in the specified format. If + * the format is linear the written PNG color-map will be converted to sRGB + * regardless of the convert_to_8_bit flag. + * + * With all APIs row_stride is handled as in the read APIs - it is the spacing + * from one row to the next in component sized units (1 or 2 bytes) and if + * negative indicates a bottom-up row layout in the buffer. + * + * Note that the write API does not support interlacing or sub-8-bit pixels. + */ +#endif /* PNG_STDIO_SUPPORTED */ +#endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */ +/******************************************************************************* + * END OF SIMPLIFIED API + ******************************************************************************/ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +PNG_EXPORT(242, void, png_set_check_for_invalid_index, + (png_structrp png_ptr, int allowed)); +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr, + png_const_infop info_ptr)); +# endif +#endif /* CHECK_FOR_INVALID_INDEX */ + +/******************************************************************************* + * IMPLEMENTATION OPTIONS + ******************************************************************************* + * + * Support for arbitrary implementation-specific optimizations. The API allows + * particular options to be turned on or off. 'Option' is the number of the + * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given + * by the PNG_OPTION_ defines below. + * + * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions, + * are detected at run time, however sometimes it may be impossible + * to do this in user mode, in which case it is necessary to discover + * the capabilities in an OS specific way. Such capabilities are + * listed here when libpng has support for them and must be turned + * ON by the application if present. + * + * SOFTWARE: sometimes software optimizations actually result in performance + * decrease on some architectures or systems, or with some sets of + * PNG images. 'Software' options allow such optimizations to be + * selected at run time. + */ +#ifdef PNG_SET_OPTION_SUPPORTED +#ifdef PNG_ARM_NEON_API_SUPPORTED +# define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */ +#endif +#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ +#define PNG_OPTION_NEXT 4 /* Next option - numbers must be even */ + +/* Return values: NOTE: there are four values and 'off' is *not* zero */ +#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ +#define PNG_OPTION_INVALID 1 /* Option number out of range */ +#define PNG_OPTION_OFF 2 +#define PNG_OPTION_ON 3 + +PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, + int onoff)); +#endif + +/******************************************************************************* + * END OF HARDWARE OPTIONS + ******************************************************************************/ + +/* Maintainer: Put new public prototypes here ^, in libpng.3, and project + * defs, scripts/pnglibconf.h, and scripts/pnglibconf.h.prebuilt + */ + +/* The last ordinal number (this is the *last* one already used; the next + * one to use is one more than this.) Maintainer, remember to add an entry to + * scripts/symbols.def as well. + */ +#ifdef PNG_EXPORT_LAST_ORDINAL + PNG_EXPORT_LAST_ORDINAL(244); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +/* Do not put anything past this line */ +#endif /* PNG_H */ diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pngconf.h b/core/src/fxcodec/fx_lpng/lpng_v163/pngconf.h new file mode 100644 index 0000000000..02f74e2639 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/pngconf.h @@ -0,0 +1,617 @@ + +/* pngconf.h - machine configurable file for libpng + * + * libpng version 1.6.3 - July 18, 2013 + * + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + */ + +/* Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifndef PNGCONF_H +#define PNGCONF_H + +/* To do: Do all of this in scripts/pnglibconf.dfa */ +#ifdef PNG_SAFE_LIMITS_SUPPORTED +# ifdef PNG_USER_WIDTH_MAX +# undef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 1000000L +# endif +# ifdef PNG_USER_HEIGHT_MAX +# undef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 1000000L +# endif +# ifdef PNG_USER_CHUNK_MALLOC_MAX +# undef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 4000000L +# endif +# ifdef PNG_USER_CHUNK_CACHE_MAX +# undef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 128 +# endif +#endif + +#ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */ + +/* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C + * compiler for correct compilation. The following header files are required by + * the standard. If your compiler doesn't provide these header files, or they + * do not match the standard, you will need to provide/improve them. + */ +#include +#include + +/* Library header files. These header files are all defined by ISOC90; libpng + * expects conformant implementations, however, an ISOC90 conformant system need + * not provide these header files if the functionality cannot be implemented. + * In this case it will be necessary to disable the relevant parts of libpng in + * the build of pnglibconf.h. + * + * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not + * include this unnecessary header file. + */ + +#ifdef PNG_STDIO_SUPPORTED + /* Required for the definition of FILE: */ +# include +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* Required for the definition of jmp_buf and the declaration of longjmp: */ +# include +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED + /* Required for struct tm: */ +# include +#endif + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +/* Prior to 1.6.0 it was possible to turn off 'const' in declarations using + * PNG_NO_CONST; this is no longer supported except for data declarations which + * apparently still cause problems in 2011 on some compilers. + */ +#define PNG_CONST const /* backward compatibility only */ + +/* This controls optimization of the reading of 16 and 32 bit values + * from PNG files. It can be set on a per-app-file basis - it + * just changes whether a macro is used when the function is called. + * The library builder sets the default; if read functions are not + * built into the library the macro implementation is forced on. + */ +#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED +# define PNG_USE_READ_MACROS +#endif +#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS) +# if PNG_DEFAULT_READ_MACROS +# define PNG_USE_READ_MACROS +# endif +#endif + +/* COMPILER SPECIFIC OPTIONS. + * + * These options are provided so that a variety of difficult compilers + * can be used. Some are fixed at build time (e.g. PNG_API_RULE + * below) but still have compiler specific implementations, others + * may be changed on a per-file basis when compiling against libpng. + */ + +/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect + * against legacy (pre ISOC90) compilers that did not understand function + * prototypes. It is not required for modern C compilers. + */ +#ifndef PNGARG +# define PNGARG(arglist) arglist +#endif + +/* Function calling conventions. + * ============================= + * Normally it is not necessary to specify to the compiler how to call + * a function - it just does it - however on x86 systems derived from + * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems + * and some others) there are multiple ways to call a function and the + * default can be changed on the compiler command line. For this reason + * libpng specifies the calling convention of every exported function and + * every function called via a user supplied function pointer. This is + * done in this file by defining the following macros: + * + * PNGAPI Calling convention for exported functions. + * PNGCBAPI Calling convention for user provided (callback) functions. + * PNGCAPI Calling convention used by the ANSI-C library (required + * for longjmp callbacks and sometimes used internally to + * specify the calling convention for zlib). + * + * These macros should never be overridden. If it is necessary to + * change calling convention in a private build this can be done + * by setting PNG_API_RULE (which defaults to 0) to one of the values + * below to select the correct 'API' variants. + * + * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout. + * This is correct in every known environment. + * PNG_API_RULE=1 Use the operating system convention for PNGAPI and + * the 'C' calling convention (from PNGCAPI) for + * callbacks (PNGCBAPI). This is no longer required + * in any known environment - if it has to be used + * please post an explanation of the problem to the + * libpng mailing list. + * + * These cases only differ if the operating system does not use the C + * calling convention, at present this just means the above cases + * (x86 DOS/Windows sytems) and, even then, this does not apply to + * Cygwin running on those systems. + * + * Note that the value must be defined in pnglibconf.h so that what + * the application uses to call the library matches the conventions + * set when building the library. + */ + +/* Symbol export + * ============= + * When building a shared library it is almost always necessary to tell + * the compiler which symbols to export. The png.h macro 'PNG_EXPORT' + * is used to mark the symbols. On some systems these symbols can be + * extracted at link time and need no special processing by the compiler, + * on other systems the symbols are flagged by the compiler and just + * the declaration requires a special tag applied (unfortunately) in a + * compiler dependent way. Some systems can do either. + * + * A small number of older systems also require a symbol from a DLL to + * be flagged to the program that calls it. This is a problem because + * we do not know in the header file included by application code that + * the symbol will come from a shared library, as opposed to a statically + * linked one. For this reason the application must tell us by setting + * the magic flag PNG_USE_DLL to turn on the special processing before + * it includes png.h. + * + * Four additional macros are used to make this happen: + * + * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from + * the build or imported if PNG_USE_DLL is set - compiler + * and system specific. + * + * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to + * 'type', compiler specific. + * + * PNG_DLL_EXPORT Set to the magic to use during a libpng build to + * make a symbol exported from the DLL. Not used in the + * public header files; see pngpriv.h for how it is used + * in the libpng build. + * + * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come + * from a DLL - used to define PNG_IMPEXP when + * PNG_USE_DLL is set. + */ + +/* System specific discovery. + * ========================== + * This code is used at build time to find PNG_IMPEXP, the API settings + * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL + * import processing is possible. On Windows systems it also sets + * compiler-specific macros to the values required to change the calling + * conventions of the various functions. + */ +#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ + defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) + /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or + * MinGW on any architecture currently supported by Windows. Also includes + * Watcom builds but these need special treatment because they are not + * compatible with GCC or Visual C because of different calling conventions. + */ +# if PNG_API_RULE == 2 + /* If this line results in an error, either because __watcall is not + * understood or because of a redefine just below you cannot use *this* + * build of the library with the compiler you are using. *This* build was + * build using Watcom and applications must also be built using Watcom! + */ +# define PNGCAPI __watcall +# endif + +# if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800)) +# define PNGCAPI __cdecl +# if PNG_API_RULE == 1 + /* If this line results in an error __stdcall is not understood and + * PNG_API_RULE should not have been set to '1'. + */ +# define PNGAPI __stdcall +# endif +# else + /* An older compiler, or one not detected (erroneously) above, + * if necessary override on the command line to get the correct + * variants for the compiler. + */ +# ifndef PNGCAPI +# define PNGCAPI _cdecl +# endif +# if PNG_API_RULE == 1 && !defined(PNGAPI) +# define PNGAPI _stdcall +# endif +# endif /* compiler/api */ + + /* NOTE: PNGCBAPI always defaults to PNGCAPI. */ + +# if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD) +# error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed" +# endif + +# if (defined(_MSC_VER) && _MSC_VER < 800) ||\ + (defined(__BORLANDC__) && __BORLANDC__ < 0x500) + /* older Borland and MSC + * compilers used '__export' and required this to be after + * the type. + */ +# ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP +# endif +# define PNG_DLL_EXPORT __export +# else /* newer compiler */ +# define PNG_DLL_EXPORT __declspec(dllexport) +# ifndef PNG_DLL_IMPORT +# define PNG_DLL_IMPORT __declspec(dllimport) +# endif +# endif /* compiler */ + +#else /* !Windows */ +# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) +# define PNGAPI _System +# else /* !Windows/x86 && !OS/2 */ + /* Use the defaults, or define PNG*API on the command line (but + * this will have to be done for every compile!) + */ +# endif /* other system, !OS/2 */ +#endif /* !Windows/x86 */ + +/* Now do all the defaulting . */ +#ifndef PNGCAPI +# define PNGCAPI +#endif +#ifndef PNGCBAPI +# define PNGCBAPI PNGCAPI +#endif +#ifndef PNGAPI +# define PNGAPI PNGCAPI +#endif + +/* PNG_IMPEXP may be set on the compilation system command line or (if not set) + * then in an internal header file when building the library, otherwise (when + * using the library) it is set here. + */ +#ifndef PNG_IMPEXP +# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT) + /* This forces use of a DLL, disallowing static linking */ +# define PNG_IMPEXP PNG_DLL_IMPORT +# endif + +# ifndef PNG_IMPEXP +# define PNG_IMPEXP +# endif +#endif + +/* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat + * 'attributes' as a storage class - the attributes go at the start of the + * function definition, and attributes are always appended regardless of the + * compiler. This considerably simplifies these macros but may cause problems + * if any compilers both need function attributes and fail to handle them as + * a storage class (this is unlikely.) + */ +#ifndef PNG_FUNCTION +# define PNG_FUNCTION(type, name, args, attributes) attributes type name args +#endif + +#ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) PNG_IMPEXP type +#endif + + /* The ordinal value is only relevant when preprocessing png.h for symbol + * table entries, so we discard it here. See the .dfn files in the + * scripts directory. + */ +#ifndef PNG_EXPORTA + +# define PNG_EXPORTA(ordinal, type, name, args, attributes)\ + PNG_FUNCTION(PNG_EXPORT_TYPE(type),(PNGAPI name),PNGARG(args), \ + extern attributes) +#endif + +/* ANSI-C (C90) does not permit a macro to be invoked with an empty argument, + * so make something non-empty to satisfy the requirement: + */ +#define PNG_EMPTY /*empty list*/ + +#define PNG_EXPORT(ordinal, type, name, args)\ + PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY) + +/* Use PNG_REMOVED to comment out a removed interface. */ +#ifndef PNG_REMOVED +# define PNG_REMOVED(ordinal, type, name, args, attributes) +#endif + +#ifndef PNG_CALLBACK +# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args) +#endif + +/* Support for compiler specific function attributes. These are used + * so that where compiler support is available incorrect use of API + * functions in png.h will generate compiler warnings. + * + * Added at libpng-1.2.41. + */ + +#ifndef PNG_NO_PEDANTIC_WARNINGS +# ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED +# define PNG_PEDANTIC_WARNINGS_SUPPORTED +# endif +#endif + +#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED + /* Support for compiler specific function attributes. These are used + * so that where compiler support is available, incorrect use of API + * functions in png.h will generate compiler warnings. Added at libpng + * version 1.2.41. Disabling these removes the warnings but may also produce + * less efficient code. + */ +# if defined(__GNUC__) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# if __GNUC__ >= 3 +# ifndef PNG_ALLOCATED +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# ifndef PNG_PRIVATE +# if 0 /* Doesn't work so we use deprecated instead*/ +# define PNG_PRIVATE \ + __attribute__((warning("This function is not exported by libpng."))) +# else +# define PNG_PRIVATE \ + __attribute__((__deprecated__)) +# endif +# endif +# if ((__GNUC__ != 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1)) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif /* __GNUC__ == 3.0 */ +# endif /* __GNUC__ >= 3 */ + +# elif defined(_MSC_VER) && (_MSC_VER >= 1300) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* not supported */ +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __declspec(noreturn) +# endif +# ifndef PNG_ALLOCATED +# if (_MSC_VER >= 1400) +# define PNG_ALLOCATED __declspec(restrict) +# endif +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __declspec(deprecated) +# endif +# ifndef PNG_PRIVATE +# define PNG_PRIVATE __declspec(deprecated) +# endif +# ifndef PNG_RESTRICT +# if (_MSC_VER >= 1400) +# define PNG_RESTRICT __restrict +# endif +# endif + +# elif defined(__WATCOMC__) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif /* _MSC_VER */ +#endif /* PNG_PEDANTIC_WARNINGS */ + +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED /* Use of this function is deprecated */ +#endif +#ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* The result of this function must be checked */ +#endif +#ifndef PNG_NORETURN +# define PNG_NORETURN /* This function does not return */ +#endif +#ifndef PNG_ALLOCATED +# define PNG_ALLOCATED /* The result of the function is new memory */ +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE /* This is a private libpng function */ +#endif +#ifndef PNG_RESTRICT +# define PNG_RESTRICT /* The C99 "restrict" feature */ +#endif +#ifndef PNG_FP_EXPORT /* A floating point API. */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No floating point APIs */ +# define PNG_FP_EXPORT(ordinal, type, name, args) +# endif +#endif +#ifndef PNG_FIXED_EXPORT /* A fixed point API. */ +# ifdef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No fixed point APIs */ +# define PNG_FIXED_EXPORT(ordinal, type, name, args) +# endif +#endif + +#ifndef PNG_BUILDING_SYMBOL_TABLE +/* Some typedefs to get us started. These should be safe on most of the common + * platforms. + * + * png_uint_32 and png_int_32 may, currently, be larger than required to hold a + * 32-bit value however this is not normally advisable. + * + * png_uint_16 and png_int_16 should always be two bytes in size - this is + * verified at library build time. + * + * png_byte must always be one byte in size. + * + * The checks below use constants from limits.h, as defined by the ISOC90 + * standard. + */ +#if CHAR_BIT == 8 && UCHAR_MAX == 255 + typedef unsigned char png_byte; +#else +# error "libpng requires 8 bit bytes" +#endif + +#if INT_MIN == -32768 && INT_MAX == 32767 + typedef int png_int_16; +#elif SHRT_MIN == -32768 && SHRT_MAX == 32767 + typedef short png_int_16; +#else +# error "libpng requires a signed 16 bit type" +#endif + +#if UINT_MAX == 65535 + typedef unsigned int png_uint_16; +#elif USHRT_MAX == 65535 + typedef unsigned short png_uint_16; +#else +# error "libpng requires an unsigned 16 bit type" +#endif + +#if INT_MIN < -2147483646 && INT_MAX > 2147483646 + typedef int png_int_32; +#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646 + typedef long int png_int_32; +#else +# error "libpng requires a signed 32 bit (or more) type" +#endif + +#if UINT_MAX > 4294967294 + typedef unsigned int png_uint_32; +#elif ULONG_MAX > 4294967294 + typedef unsigned long int png_uint_32; +#else +# error "libpng requires an unsigned 32 bit (or more) type" +#endif + +/* Prior to 1.6.0 it was possible to disable the use of size_t, 1.6.0, however, + * requires an ISOC90 compiler and relies on consistent behavior of sizeof. + */ +typedef size_t png_size_t; +typedef ptrdiff_t png_ptrdiff_t; + +/* libpng needs to know the maximum value of 'size_t' and this controls the + * definition of png_alloc_size_t, below. This maximum value of size_t limits + * but does not control the maximum allocations the library makes - there is + * direct application control of this through png_set_user_limits(). + */ +#ifndef PNG_SMALL_SIZE_T + /* Compiler specific tests for systems where size_t is known to be less than + * 32 bits (some of these systems may no longer work because of the lack of + * 'far' support; see above.) + */ +# if (defined(__TURBOC__) && !defined(__FLAT__)) ||\ + (defined(_MSC_VER) && defined(MAXSEG_64K)) +# define PNG_SMALL_SIZE_T +# endif +#endif + +/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, and no + * smaller than png_uint_32. Casts from png_size_t or png_uint_32 to + * png_alloc_size_t are not necessary; in fact, it is recommended not to use + * them at all so that the compiler can complain when something turns out to be + * problematic. + * + * Casts in the other direction (from png_alloc_size_t to png_size_t or + * png_uint_32) should be explicitly applied; however, we do not expect to + * encounter practical situations that require such conversions. + * + * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than + * 4294967295 - i.e. less than the maximum value of png_uint_32. + */ +#ifdef PNG_SMALL_SIZE_T + typedef png_uint_32 png_alloc_size_t; +#else + typedef png_size_t png_alloc_size_t; +#endif + +/* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler + * implementations of Intel CPU specific support of user-mode segmented address + * spaces, where 16-bit pointers address more than 65536 bytes of memory using + * separate 'segment' registers. The implementation requires two different + * types of pointer (only one of which includes the segment value.) + * + * If required this support is available in version 1.2 of libpng and may be + * available in versions through 1.5, although the correctness of the code has + * not been verified recently. + */ + +/* Typedef for floating-point numbers that are converted to fixed-point with a + * multiple of 100,000, e.g., gamma + */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void * png_voidp; +typedef const void * png_const_voidp; +typedef png_byte * png_bytep; +typedef const png_byte * png_const_bytep; +typedef png_uint_32 * png_uint_32p; +typedef const png_uint_32 * png_const_uint_32p; +typedef png_int_32 * png_int_32p; +typedef const png_int_32 * png_const_int_32p; +typedef png_uint_16 * png_uint_16p; +typedef const png_uint_16 * png_const_uint_16p; +typedef png_int_16 * png_int_16p; +typedef const png_int_16 * png_const_int_16p; +typedef char * png_charp; +typedef const char * png_const_charp; +typedef png_fixed_point * png_fixed_point_p; +typedef const png_fixed_point * png_const_fixed_point_p; +typedef png_size_t * png_size_tp; +typedef const png_size_t * png_const_size_tp; + +#ifdef PNG_STDIO_SUPPORTED +typedef FILE * png_FILE_p; +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * png_doublep; +typedef const double * png_const_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte * * png_bytepp; +typedef png_uint_32 * * png_uint_32pp; +typedef png_int_32 * * png_int_32pp; +typedef png_uint_16 * * png_uint_16pp; +typedef png_int_16 * * png_int_16pp; +typedef const char * * png_const_charpp; +typedef char * * png_charpp; +typedef png_fixed_point * * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char * * * png_charppp; + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +#endif /* PNGCONF_H */ diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pngdebug.h b/core/src/fxcodec/fx_lpng/lpng_v163/pngdebug.h new file mode 100644 index 0000000000..96c1ea42b3 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/pngdebug.h @@ -0,0 +1,157 @@ + +/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c + * + * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.5.0 [January 6, 2011] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* Define PNG_DEBUG at compile time for debugging information. Higher + * numbers for PNG_DEBUG mean more debugging information. This has + * only been added since version 0.95 so it is not implemented throughout + * libpng yet, but more support will be added as needed. + * + * png_debug[1-2]?(level, message ,arg{0-2}) + * Expands to a statement (either a simple expression or a compound + * do..while(0) statement) that outputs a message with parameter + * substitution if PNG_DEBUG is defined to 2 or more. If PNG_DEBUG + * is undefined, 0 or 1 every png_debug expands to a simple expression + * (actually ((void)0)). + * + * level: level of detail of message, starting at 0. A level 'n' + * message is preceded by 'n' tab characters (not implemented + * on Microsoft compilers unless PNG_DEBUG_FILE is also + * defined, to allow debug DLL compilation with no standard IO). + * message: a printf(3) style text string. A trailing '\n' is added + * to the message. + * arg: 0 to 2 arguments for printf(3) style substitution in message. + */ +#ifndef PNGDEBUG_H +#define PNGDEBUG_H +/* These settings control the formatting of messages in png.c and pngerror.c */ +/* Moved to pngdebug.h at 1.5.0 */ +# ifndef PNG_LITERAL_SHARP +# define PNG_LITERAL_SHARP 0x23 +# endif +# ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET +# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b +# endif +# ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET +# define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d +# endif +# ifndef PNG_STRING_NEWLINE +# define PNG_STRING_NEWLINE "\n" +# endif + +#ifdef PNG_DEBUG +# if (PNG_DEBUG > 0) +# if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) +# include +# if (PNG_DEBUG > 1) +# ifndef _DEBUG +# define _DEBUG +# endif +# ifndef png_debug +# define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2) +# endif +# endif +# else /* PNG_DEBUG_FILE || !_MSC_VER */ +# ifndef PNG_STDIO_SUPPORTED +# include /* not included yet */ +# endif +# ifndef PNG_DEBUG_FILE +# define PNG_DEBUG_FILE stderr +# endif /* PNG_DEBUG_FILE */ + +# if (PNG_DEBUG > 1) +/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on + * non-ISO compilers + */ +# ifdef __STDC__ +# ifndef png_debug +# define png_debug(l,m) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ + } while (0) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ + } while (0) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ + } while (0) +# endif +# else /* __STDC __ */ +# ifndef png_debug +# define png_debug(l,m) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format); \ + } while (0) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1); \ + } while (0) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1,p2); \ + } while (0) +# endif +# endif /* __STDC __ */ +# endif /* (PNG_DEBUG > 1) */ + +# endif /* _MSC_VER */ +# endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ +#ifndef png_debug +# define png_debug(l, m) ((void)0) +#endif +#ifndef png_debug1 +# define png_debug1(l, m, p1) ((void)0) +#endif +#ifndef png_debug2 +# define png_debug2(l, m, p1, p2) ((void)0) +#endif +#endif /* PNGDEBUG_H */ diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pnginfo.h b/core/src/fxcodec/fx_lpng/lpng_v163/pnginfo.h new file mode 100644 index 0000000000..683b7ea177 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/pnginfo.h @@ -0,0 +1,260 @@ + +/* pnginfo.h - header file for PNG reference library + * + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + + /* png_info is a structure that holds the information in a PNG file so + * that the application can find out the characteristics of the image. + * If you are reading the file, this structure will tell you what is + * in the PNG file. If you are writing the file, fill in the information + * you want to put into the PNG file, using png_set_*() functions, then + * call png_write_info(). + * + * The names chosen should be very close to the PNG specification, so + * consult that document for information about the meaning of each field. + * + * With libpng < 0.95, it was only possible to directly set and read the + * the values in the png_info_struct, which meant that the contents and + * order of the values had to remain fixed. With libpng 0.95 and later, + * however, there are now functions that abstract the contents of + * png_info_struct from the application, so this makes it easier to use + * libpng with dynamic libraries, and even makes it possible to use + * libraries that don't have all of the libpng ancillary chunk-handing + * functionality. In libpng-1.5.0 this was moved into a separate private + * file that is not visible to applications. + * + * The following members may have allocated storage attached that should be + * cleaned up before the structure is discarded: palette, trans, text, + * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile, + * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these + * are automatically freed when the info structure is deallocated, if they were + * allocated internally by libpng. This behavior can be changed by means + * of the png_data_freer() function. + * + * More allocation details: all the chunk-reading functions that + * change these members go through the corresponding png_set_* + * functions. A function to clear these members is available: see + * png_free_data(). The png_set_* functions do not depend on being + * able to point info structure members to any of the storage they are + * passed (they make their own copies), EXCEPT that the png_set_text + * functions use the same storage passed to them in the text_ptr or + * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns + * functions do not make their own copies. + */ +#ifndef PNGINFO_H +#define PNGINFO_H + +struct png_info_def +{ + /* The following are necessary for every PNG file */ + png_uint_32 width; /* width of image in pixels (from IHDR) */ + png_uint_32 height; /* height of image in pixels (from IHDR) */ + png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ + png_size_t rowbytes; /* bytes needed to hold an untransformed row */ + png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ + png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ + png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ + png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ + png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ + /* The following three should have been named *_method not *_type */ + png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ + png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ + png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + + /* The following are set by png_set_IHDR, called from the application on + * write, but the are never actually used by the write code. + */ + png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte spare_byte; /* to align the data, and for future use */ + +#ifdef PNG_READ_SUPPORTED + /* This is never set during write */ + png_byte signature[8]; /* magic bytes read by libpng from start of file */ +#endif + + /* The rest of the data is optional. If you are reading, check the + * valid field to see if the information in these are valid. If you + * are writing, set the valid field to those chunks you want written, + * and initialize the appropriate fields below. + */ + +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are + * defined. When COLORSPACE is switched on all the colorspace-defining + * chunks should be enabled, when GAMMA is switched on all the gamma-defining + * chunks should be enabled. If this is not done it becomes possible to read + * inconsistent PNG files and assign a probably incorrect interpretation to + * the information. (In other words, by carefully choosing which chunks to + * recognize the system configuration can select an interpretation for PNG + * files containing ambiguous data and this will result in inconsistent + * behavior between different libpng builds!) + */ + png_colorspace colorspace; +#endif + +#ifdef PNG_iCCP_SUPPORTED + /* iCCP chunk data. */ + png_charp iccp_name; /* profile name */ + png_bytep iccp_profile; /* International Color Consortium profile data */ + png_uint_32 iccp_proflen; /* ICC profile data length */ +#endif + +#ifdef PNG_TEXT_SUPPORTED + /* The tEXt, and zTXt chunks contain human-readable textual data in + * uncompressed, compressed, and optionally compressed forms, respectively. + * The data in "text" is an array of pointers to uncompressed, + * null-terminated C strings. Each chunk has a keyword that describes the + * textual data contained in that chunk. Keywords are not required to be + * unique, and the text string may be empty. Any number of text chunks may + * be in an image. + */ + int num_text; /* number of comments read or comments to write */ + int max_text; /* current size of text array */ + png_textp text; /* array of comments read or comments to write */ +#endif /* PNG_TEXT_SUPPORTED */ + +#ifdef PNG_tIME_SUPPORTED + /* The tIME chunk holds the last time the displayed image data was + * modified. See the png_time struct for the contents of this struct. + */ + png_time mod_time; +#endif + +#ifdef PNG_sBIT_SUPPORTED + /* The sBIT chunk specifies the number of significant high-order bits + * in the pixel data. Values are in the range [1, bit_depth], and are + * only specified for the channels in the pixel data. The contents of + * the low-order bits is not specified. Data is valid if + * (valid & PNG_INFO_sBIT) is non-zero. + */ + png_color_8 sig_bit; /* significant bits in color channels */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \ +defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The tRNS chunk supplies transparency data for paletted images and + * other image types that don't need a full alpha channel. There are + * "num_trans" transparency values for a paletted image, stored in the + * same order as the palette colors, starting from index 0. Values + * for the data are in the range [0, 255], ranging from fully transparent + * to fully opaque, respectively. For non-paletted images, there is a + * single color specified that should be treated as fully transparent. + * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. + */ + png_bytep trans_alpha; /* alpha values for paletted image */ + png_color_16 trans_color; /* transparent color for non-palette image */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The bKGD chunk gives the suggested image background color if the + * display program does not have its own background color and the image + * is needs to composited onto a background before display. The colors + * in "background" are normally in the same color space/depth as the + * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. + */ + png_color_16 background; +#endif + +#ifdef PNG_oFFs_SUPPORTED + /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards + * and downwards from the top-left corner of the display, page, or other + * application-specific co-ordinate space. See the PNG_OFFSET_ defines + * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. + */ + png_int_32 x_offset; /* x offset on page */ + png_int_32 y_offset; /* y offset on page */ + png_byte offset_unit_type; /* offset units type */ +#endif + +#ifdef PNG_pHYs_SUPPORTED + /* The pHYs chunk gives the physical pixel density of the image for + * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ + * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. + */ + png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ + png_uint_32 y_pixels_per_unit; /* vertical pixel density */ + png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ +#endif + +#ifdef PNG_hIST_SUPPORTED + /* The hIST chunk contains the relative frequency or importance of the + * various palette entries, so that a viewer can intelligently select a + * reduced-color palette, if required. Data is an array of "num_palette" + * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) + * is non-zero. + */ + png_uint_16p hist; +#endif + +#ifdef PNG_pCAL_SUPPORTED + /* The pCAL chunk describes a transformation between the stored pixel + * values and original physical data values used to create the image. + * The integer range [0, 2^bit_depth - 1] maps to the floating-point + * range given by [pcal_X0, pcal_X1], and are further transformed by a + * (possibly non-linear) transformation function given by "pcal_type" + * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ + * defines below, and the PNG-Group's PNG extensions document for a + * complete description of the transformations and how they should be + * implemented, and for a description of the ASCII parameter strings. + * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. + */ + png_charp pcal_purpose; /* pCAL chunk description string */ + png_int_32 pcal_X0; /* minimum value */ + png_int_32 pcal_X1; /* maximum value */ + png_charp pcal_units; /* Latin-1 string giving physical units */ + png_charpp pcal_params; /* ASCII strings containing parameter values */ + png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ + png_byte pcal_nparams; /* number of parameters given in pcal_params */ +#endif + +/* New members added in libpng-1.0.6 */ + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + /* Storage for unknown chunks that the library doesn't recognize. */ + png_unknown_chunkp unknown_chunks; + + /* The type of this field is limited by the type of + * png_struct::user_chunk_cache_max, else overflow can occur. + */ + int unknown_chunks_num; +#endif + +#ifdef PNG_sPLT_SUPPORTED + /* Data on sPLT chunks (there may be more than one). */ + png_sPLT_tp splt_palettes; + int splt_palettes_num; /* Match type returned by png_get API */ +#endif + +#ifdef PNG_sCAL_SUPPORTED + /* The sCAL chunk describes the actual physical dimensions of the + * subject matter of the graphic. The chunk contains a unit specification + * a byte value, and two ASCII strings representing floating-point + * values. The values are width and height corresponsing to one pixel + * in the image. Data values are valid if (valid & PNG_INFO_sCAL) is + * non-zero. + */ + png_byte scal_unit; /* unit of physical scale */ + png_charp scal_s_width; /* string containing height */ + png_charp scal_s_height; /* string containing width */ +#endif + +#ifdef PNG_INFO_IMAGE_SUPPORTED + /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) + non-zero */ + /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ + png_bytepp row_pointers; /* the image bits */ +#endif + +}; +#endif /* PNGINFO_H */ diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pnglibconf.h b/core/src/fxcodec/fx_lpng/lpng_v163/pnglibconf.h new file mode 100644 index 0000000000..ececc38fc2 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/pnglibconf.h @@ -0,0 +1,211 @@ +/* libpng 1.6.3 STANDARD API DEFINITION */ + +/* pnglibconf.h - library build configuration */ + +/* Libpng version 1.6.3 - July 18, 2013 */ + +/* Copyright (c) 1998-2013 Glenn Randers-Pehrson */ + +/* This code is released under the libpng license. */ +/* For conditions of distribution and use, see the disclaimer */ +/* and license in png.h */ + +/* pnglibconf.h */ +/* Machine generated file: DO NOT EDIT */ +/* Derived from: scripts/pnglibconf.dfa */ +#ifndef PNGLCONF_H +#define PNGLCONF_H +/* options */ +#define PNG_16BIT_SUPPORTED +#define PNG_ALIGNED_MEMORY_SUPPORTED +/*#undef PNG_ARM_NEON_API_SUPPORTED*/ +/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/ +#define PNG_BENIGN_ERRORS_SUPPORTED +#define PNG_BENIGN_READ_ERRORS_SUPPORTED +/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/ +#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_COLORSPACE_SUPPORTED +#define PNG_CONSOLE_IO_SUPPORTED +#define PNG_CONVERT_tIME_SUPPORTED +#define PNG_EASY_ACCESS_SUPPORTED +/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ +#define PNG_ERROR_TEXT_SUPPORTED +#define PNG_FIXED_POINT_SUPPORTED +#define PNG_FLOATING_ARITHMETIC_SUPPORTED +#define PNG_FLOATING_POINT_SUPPORTED +#define PNG_FORMAT_AFIRST_SUPPORTED +#define PNG_FORMAT_BGR_SUPPORTED +#define PNG_GAMMA_SUPPORTED +#define PNG_GET_PALETTE_MAX_SUPPORTED +#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +#define PNG_INCH_CONVERSIONS_SUPPORTED +#define PNG_INFO_IMAGE_SUPPORTED +#define PNG_IO_STATE_SUPPORTED +#define PNG_MNG_FEATURES_SUPPORTED +#define PNG_POINTER_INDEXING_SUPPORTED +#define PNG_PROGRESSIVE_READ_SUPPORTED +#define PNG_READ_16BIT_SUPPORTED +#define PNG_READ_ALPHA_MODE_SUPPORTED +#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_READ_BACKGROUND_SUPPORTED +#define PNG_READ_BGR_SUPPORTED +#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_READ_COMPOSITE_NODIV_SUPPORTED +#define PNG_READ_COMPRESSED_TEXT_SUPPORTED +#define PNG_READ_EXPAND_16_SUPPORTED +#define PNG_READ_EXPAND_SUPPORTED +#define PNG_READ_FILLER_SUPPORTED +#define PNG_READ_GAMMA_SUPPORTED +#define PNG_READ_GET_PALETTE_MAX_SUPPORTED +#define PNG_READ_GRAY_TO_RGB_SUPPORTED +#define PNG_READ_INTERLACING_SUPPORTED +#define PNG_READ_INT_FUNCTIONS_SUPPORTED +#define PNG_READ_INVERT_ALPHA_SUPPORTED +#define PNG_READ_INVERT_SUPPORTED +#define PNG_READ_OPT_PLTE_SUPPORTED +#define PNG_READ_PACKSWAP_SUPPORTED +#define PNG_READ_PACK_SUPPORTED +#define PNG_READ_QUANTIZE_SUPPORTED +#define PNG_READ_RGB_TO_GRAY_SUPPORTED +#define PNG_READ_SCALE_16_TO_8_SUPPORTED +#define PNG_READ_SHIFT_SUPPORTED +#define PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_STRIP_ALPHA_SUPPORTED +#define PNG_READ_SUPPORTED +#define PNG_READ_SWAP_ALPHA_SUPPORTED +#define PNG_READ_SWAP_SUPPORTED +#define PNG_READ_TEXT_SUPPORTED +#define PNG_READ_TRANSFORMS_SUPPORTED +#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_READ_USER_CHUNKS_SUPPORTED +#define PNG_READ_USER_TRANSFORM_SUPPORTED +#define PNG_READ_bKGD_SUPPORTED +#define PNG_READ_cHRM_SUPPORTED +#define PNG_READ_gAMA_SUPPORTED +#define PNG_READ_hIST_SUPPORTED +#define PNG_READ_iCCP_SUPPORTED +#define PNG_READ_iTXt_SUPPORTED +#define PNG_READ_oFFs_SUPPORTED +#define PNG_READ_pCAL_SUPPORTED +#define PNG_READ_pHYs_SUPPORTED +#define PNG_READ_sBIT_SUPPORTED +#define PNG_READ_sCAL_SUPPORTED +#define PNG_READ_sPLT_SUPPORTED +#define PNG_READ_sRGB_SUPPORTED +#define PNG_READ_tEXt_SUPPORTED +#define PNG_READ_tIME_SUPPORTED +#define PNG_READ_tRNS_SUPPORTED +#define PNG_READ_zTXt_SUPPORTED +/*#undef PNG_SAFE_LIMITS_SUPPORTED*/ +#define PNG_SAVE_INT_32_SUPPORTED +#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SEQUENTIAL_READ_SUPPORTED +#define PNG_SETJMP_SUPPORTED +#define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED +#define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED +#define PNG_SET_OPTION_SUPPORTED +#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SET_USER_LIMITS_SUPPORTED +#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED +#define PNG_SIMPLIFIED_READ_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_SUPPORTED +#define PNG_STDIO_SUPPORTED +#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_TEXT_SUPPORTED +#define PNG_TIME_RFC1123_SUPPORTED +#define PNG_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_USER_CHUNKS_SUPPORTED +#define PNG_USER_LIMITS_SUPPORTED +#define PNG_USER_MEM_SUPPORTED +#define PNG_USER_TRANSFORM_INFO_SUPPORTED +#define PNG_USER_TRANSFORM_PTR_SUPPORTED +#define PNG_WARNINGS_SUPPORTED +#define PNG_WRITE_16BIT_SUPPORTED +#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_WRITE_BGR_SUPPORTED +#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +#define PNG_WRITE_FILLER_SUPPORTED +#define PNG_WRITE_FILTER_SUPPORTED +#define PNG_WRITE_FLUSH_SUPPORTED +#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED +#define PNG_WRITE_INTERLACING_SUPPORTED +#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED +#define PNG_WRITE_INVERT_ALPHA_SUPPORTED +#define PNG_WRITE_INVERT_SUPPORTED +#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED +#define PNG_WRITE_PACKSWAP_SUPPORTED +#define PNG_WRITE_PACK_SUPPORTED +#define PNG_WRITE_SHIFT_SUPPORTED +#define PNG_WRITE_SUPPORTED +#define PNG_WRITE_SWAP_ALPHA_SUPPORTED +#define PNG_WRITE_SWAP_SUPPORTED +#define PNG_WRITE_TEXT_SUPPORTED +#define PNG_WRITE_TRANSFORMS_SUPPORTED +#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_WRITE_USER_TRANSFORM_SUPPORTED +#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#define PNG_WRITE_bKGD_SUPPORTED +#define PNG_WRITE_cHRM_SUPPORTED +#define PNG_WRITE_gAMA_SUPPORTED +#define PNG_WRITE_hIST_SUPPORTED +#define PNG_WRITE_iCCP_SUPPORTED +#define PNG_WRITE_iTXt_SUPPORTED +#define PNG_WRITE_oFFs_SUPPORTED +#define PNG_WRITE_pCAL_SUPPORTED +#define PNG_WRITE_pHYs_SUPPORTED +#define PNG_WRITE_sBIT_SUPPORTED +#define PNG_WRITE_sCAL_SUPPORTED +#define PNG_WRITE_sPLT_SUPPORTED +#define PNG_WRITE_sRGB_SUPPORTED +#define PNG_WRITE_tEXt_SUPPORTED +#define PNG_WRITE_tIME_SUPPORTED +#define PNG_WRITE_tRNS_SUPPORTED +#define PNG_WRITE_zTXt_SUPPORTED +#define PNG_bKGD_SUPPORTED +#define PNG_cHRM_SUPPORTED +#define PNG_gAMA_SUPPORTED +#define PNG_hIST_SUPPORTED +#define PNG_iCCP_SUPPORTED +#define PNG_iTXt_SUPPORTED +#define PNG_oFFs_SUPPORTED +#define PNG_pCAL_SUPPORTED +#define PNG_pHYs_SUPPORTED +#define PNG_sBIT_SUPPORTED +#define PNG_sCAL_SUPPORTED +#define PNG_sPLT_SUPPORTED +#define PNG_sRGB_SUPPORTED +#define PNG_tEXt_SUPPORTED +#define PNG_tIME_SUPPORTED +#define PNG_tRNS_SUPPORTED +#define PNG_zTXt_SUPPORTED +/* end of options */ +/* settings */ +#define PNG_API_RULE 0 +#define PNG_CALLOC_SUPPORTED +#define PNG_COST_SHIFT 3 +#define PNG_DEFAULT_READ_MACROS 1 +#define PNG_GAMMA_THRESHOLD_FIXED 5000 +#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE +#define PNG_INFLATE_BUF_SIZE 1024 +#define PNG_MAX_GAMMA_8 11 +#define PNG_QUANTIZE_BLUE_BITS 5 +#define PNG_QUANTIZE_GREEN_BITS 5 +#define PNG_QUANTIZE_RED_BITS 5 +#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1) +#define PNG_TEXT_Z_DEFAULT_STRATEGY 0 +#define PNG_WEIGHT_SHIFT 8 +#define PNG_ZBUF_SIZE 8192 +#define PNG_ZLIB_VERNUM 0 /* unknown */ +#define PNG_Z_DEFAULT_COMPRESSION (-1) +#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0 +#define PNG_Z_DEFAULT_STRATEGY 1 +#define PNG_sCAL_PRECISION 5 +#define PNG_sRGB_PROFILE_CHECKS 2 +/* end of settings */ +#endif /* PNGLCONF_H */ diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pngpriv.h b/core/src/fxcodec/fx_lpng/lpng_v163/pngpriv.h new file mode 100644 index 0000000000..7fa3d6059c --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/pngpriv.h @@ -0,0 +1,2006 @@ + +/* pngpriv.h - private declarations for use inside libpng + * + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.6.3 [July 18, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* The symbols declared in this file (including the functions declared + * as extern) are PRIVATE. They are not part of the libpng public + * interface, and are not recommended for use by regular applications. + * Some of them may become public in the future; others may stay private, + * change in an incompatible way, or even disappear. + * Although the libpng users are not forbidden to include this header, + * they should be well aware of the issues that may arise from doing so. + */ + +#ifndef PNGPRIV_H +#define PNGPRIV_H + +/* Feature Test Macros. The following are defined here to ensure that correctly + * implemented libraries reveal the APIs libpng needs to build and hide those + * that are not needed and potentially damaging to the compilation. + * + * Feature Test Macros must be defined before any system header is included (see + * POSIX 1003.1 2.8.2 "POSIX Symbols." + * + * These macros only have an effect if the operating system supports either + * POSIX 1003.1 or C99, or both. On other operating systems (particularly + * Windows/Visual Studio) there is no effect; the OS specific tests below are + * still required (as of 2011-05-02.) + */ +#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ + +#ifndef PNG_VERSION_INFO_ONLY +/* Standard library headers not required by png.h: */ +# include +# include +#endif + +#define PNGLIB_BUILD /*libpng is being built, not used*/ + +/* If HAVE_CONFIG_H is defined during the build then the build system must + * provide an appropriate "config.h" file on the include path. The header file + * must provide definitions as required below (search for "HAVE_CONFIG_H"); + * see configure.ac for more details of the requirements. The macro + * "PNG_NO_CONFIG_H" is provided for maintainers to test for dependencies on + * 'configure'; define this macro to prevent the configure build including the + * configure generated config.h. Libpng is expected to compile without *any* + * special build system support on a reasonably ANSI-C compliant system. + */ +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include + + /* Pick up the definition of 'restrict' from config.h if it was read: */ +# define PNG_RESTRICT restrict +#endif + +/* To support symbol prefixing it is necessary to know *before* including png.h + * whether the fixed point (and maybe other) APIs are exported, because if they + * are not internal definitions may be required. This is handled below just + * before png.h is included, but load the configuration now if it is available. + */ +#ifndef PNGLCONF_H +# include "pnglibconf.h" +#endif + +/* Local renames may change non-exported API functions from png.h */ +#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H) +# include "pngprefix.h" +#endif + +#ifdef PNG_USER_CONFIG +# include "pngusr.h" + /* These should have been defined in pngusr.h */ +# ifndef PNG_USER_PRIVATEBUILD +# define PNG_USER_PRIVATEBUILD "Custom libpng build" +# endif +# ifndef PNG_USER_DLLFNAME_POSTFIX +# define PNG_USER_DLLFNAME_POSTFIX "Cb" +# endif +#endif + +/* Compile time options. + * ===================== + * In a multi-arch build the compiler may compile the code several times for the + * same object module, producing different binaries for different architectures. + * When this happens configure-time setting of the target host options cannot be + * done and this interferes with the handling of the ARM NEON optimizations, and + * possibly other similar optimizations. Put additional tests here; in general + * this is needed when the same option can be changed at both compile time and + * run time depending on the target OS (i.e. iOS vs Android.) + * + * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because + * this is not possible with certain compilers (Oracle SUN OS CC), as a result + * it is necessary to ensure that all extern functions that *might* be used + * regardless of $(CFLAGS) get declared in this file. The test on __ARM_NEON__ + * below is one example of this behavior because it is controlled by the + * presence or not of -mfpu=neon on the GCC command line, it is possible to do + * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely + * do this. + */ +#ifndef PNG_ARM_NEON_OPT + /* ARM NEON optimizations are being controlled by the compiler settings, + * typically the target FPU. If the FPU has been set to NEON (-mfpu=neon + * with GCC) then the compiler will define __ARM_NEON__ and we can rely + * unconditionally on NEON instructions not crashing, otherwise we must + * disable use of NEON instructions: + */ +# ifdef __ARM_NEON__ +# define PNG_ARM_NEON_OPT 2 +# else +# define PNG_ARM_NEON_OPT 0 +# endif +#endif + +#if PNG_ARM_NEON_OPT > 0 + /* NEON optimizations are to be at least considered by libpng, so enable the + * callbacks to do this. + */ +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon +#endif + +/* Is this a build of a DLL where compilation of the object modules requires + * different preprocessor settings to those required for a simple library? If + * so PNG_BUILD_DLL must be set. + * + * If libpng is used inside a DLL but that DLL does not export the libpng APIs + * PNG_BUILD_DLL must not be set. To avoid the code below kicking in build a + * static library of libpng then link the DLL against that. + */ +#ifndef PNG_BUILD_DLL +# ifdef DLL_EXPORT + /* This is set by libtool when files are compiled for a DLL; libtool + * always compiles twice, even on systems where it isn't necessary. Set + * PNG_BUILD_DLL in case it is necessary: + */ +# define PNG_BUILD_DLL +# else +# ifdef _WINDLL + /* This is set by the Microsoft Visual Studio IDE in projects that + * build a DLL. It can't easily be removed from those projects (it + * isn't visible in the Visual Studio UI) so it is a fairly reliable + * indication that PNG_IMPEXP needs to be set to the DLL export + * attributes. + */ +# define PNG_BUILD_DLL +# else +# ifdef __DLL__ + /* This is set by the Borland C system when compiling for a DLL + * (as above.) + */ +# define PNG_BUILD_DLL +# else + /* Add additional compiler cases here. */ +# endif +# endif +# endif +#endif /* Setting PNG_BUILD_DLL if required */ + +/* See pngconf.h for more details: the builder of the library may set this on + * the command line to the right thing for the specific compilation system or it + * may be automagically set above (at present we know of no system where it does + * need to be set on the command line.) + * + * PNG_IMPEXP must be set here when building the library to prevent pngconf.h + * setting it to the "import" setting for a DLL build. + */ +#ifndef PNG_IMPEXP +# ifdef PNG_BUILD_DLL +# define PNG_IMPEXP PNG_DLL_EXPORT +# else + /* Not building a DLL, or the DLL doesn't require specific export + * definitions. + */ +# define PNG_IMPEXP +# endif +#endif + +/* No warnings for private or deprecated functions in the build: */ +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE +#endif + +/* Symbol preprocessing support. + * + * To enable listing global, but internal, symbols the following macros should + * always be used to declare an extern data or function object in this file. + */ +#ifndef PNG_INTERNAL_DATA +# define PNG_INTERNAL_DATA(type, name, array) extern type name array +#endif + +#ifndef PNG_INTERNAL_FUNCTION +# define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\ + extern PNG_FUNCTION(type, name, args, PNG_EMPTY attributes) +#endif + +/* If floating or fixed point APIs are disabled they may still be compiled + * internally. To handle this make sure they are declared as the appropriate + * internal extern function (otherwise the symbol prefixing stuff won't work and + * the functions will be used without definitions.) + * + * NOTE: although all the API functions are declared here they are not all + * actually built! Because the declarations are still made it is necessary to + * fake out types that they depend on. + */ +#ifndef PNG_FP_EXPORT +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); +# ifndef PNG_VERSION_INFO_ONLY + typedef struct png_incomplete png_double; + typedef png_double* png_doublep; + typedef const png_double* png_const_doublep; + typedef png_double** png_doublepp; +# endif +# endif +#endif +#ifndef PNG_FIXED_EXPORT +# ifndef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); +# endif +#endif + +#include "png.h" + +/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */ +#ifndef PNG_DLL_EXPORT +# define PNG_DLL_EXPORT +#endif + +/* SECURITY and SAFETY: + * + * By default libpng is built without any internal limits on image size, + * individual heap (png_malloc) allocations or the total amount of memory used. + * If PNG_SAFE_LIMITS_SUPPORTED is defined, however, the limits below are used + * (unless individually overridden). These limits are believed to be fairly + * safe, but builders of secure systems should verify the values against the + * real system capabilities. + */ +#ifdef PNG_SAFE_LIMITS_SUPPORTED + /* 'safe' limits */ +# ifndef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 1000000 +# endif +# ifndef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 1000000 +# endif +# ifndef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 128 +# endif +# ifndef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 8000000 +# endif +#else + /* values for no limits */ +# ifndef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 0x7fffffff +# endif +# ifndef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 0x7fffffff +# endif +# ifndef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 0 +# endif +# ifndef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 0 +# endif +#endif + +/* Moved to pngpriv.h at libpng-1.5.0 */ +/* NOTE: some of these may have been used in external applications as + * these definitions were exposed in pngconf.h prior to 1.5. + */ + +/* If you are running on a machine where you cannot allocate more + * than 64K of memory at once, uncomment this. While libpng will not + * normally need that much memory in a chunk (unless you load up a very + * large file), zlib needs to know how big of a chunk it can use, and + * libpng thus makes sure to check any memory allocation to verify it + * will fit into memory. + * + * zlib provides 'MAXSEG_64K' which, if defined, indicates the + * same limit and pngconf.h (already included) sets the limit + * if certain operating systems are detected. + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) +# define PNG_MAX_MALLOC_64K +#endif + +#ifndef PNG_UNUSED +/* Unused formal parameter warnings are silenced using the following macro + * which is expected to have no bad effects on performance (optimizing + * compilers will probably remove it entirely). Note that if you replace + * it with something other than whitespace, you must include the terminating + * semicolon. + */ +# define PNG_UNUSED(param) (void)param; +#endif + +/* Just a little check that someone hasn't tried to define something + * contradictory. + */ +#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) +# undef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 65536L +#endif + +/* If warnings or errors are turned off the code is disabled or redirected here. + * From 1.5.4 functions have been added to allow very limited formatting of + * error and warning messages - this code will also be disabled here. + */ +#ifdef PNG_WARNINGS_SUPPORTED +# define PNG_WARNING_PARAMETERS(p) png_warning_parameters p; +#else +# define png_warning(s1,s2) ((void)(s1)) +# define png_chunk_warning(s1,s2) ((void)(s1)) +# define png_warning_parameter(p,number,string) ((void)0) +# define png_warning_parameter_unsigned(p,number,format,value) ((void)0) +# define png_warning_parameter_signed(p,number,format,value) ((void)0) +# define png_formatted_warning(pp,p,message) ((void)(pp)) +# define PNG_WARNING_PARAMETERS(p) +#endif +#ifndef PNG_ERROR_TEXT_SUPPORTED +# define png_error(s1,s2) png_err(s1) +# define png_chunk_error(s1,s2) png_err(s1) +# define png_fixed_error(s1,s2) png_err(s1) +#endif + +/* C allows up-casts from (void*) to any pointer and (const void*) to any + * pointer to a const object. C++ regards this as a type error and requires an + * explicit, static, cast and provides the static_cast<> rune to ensure that + * const is not cast away. + */ +#ifdef __cplusplus +# define png_voidcast(type, value) static_cast(value) +# define png_constcast(type, value) const_cast(value) +# define png_aligncast(type, value) \ + static_cast(static_cast(value)) +# define png_aligncastconst(type, value) \ + static_cast(static_cast(value)) +#else +# define png_voidcast(type, value) (value) +# define png_constcast(type, value) ((type)(value)) +# define png_aligncast(type, value) ((void*)(value)) +# define png_aligncastconst(type, value) ((const void*)(value)) +#endif /* __cplusplus */ + +/* Some fixed point APIs are still required even if not exported because + * they get used by the corresponding floating point APIs. This magic + * deals with this: + */ +#ifdef PNG_FIXED_POINT_SUPPORTED +# define PNGFAPI PNGAPI +#else +# define PNGFAPI /* PRIVATE */ +#endif + +#ifndef PNG_VERSION_INFO_ONLY +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ +#if defined(PNG_FLOATING_POINT_SUPPORTED) ||\ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) + /* png.c requires the following ANSI-C constants if the conversion of + * floating point to ASCII is implemented therein: + * + * DBL_DIG Maximum number of decimal digits (can be set to any constant) + * DBL_MIN Smallest normalized fp number (can be set to an arbitrary value) + * DBL_MAX Maximum floating point number (can be set to an arbitrary value) + */ +# include + +# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ + defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) + /* We need to check that hasn't already been included earlier + * as it seems it doesn't agree with , yet we should really use + * if possible. + */ +# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) +# include +# endif +# else +# include +# endif +# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) + /* Amiga SAS/C: We must include builtin FPU functions when compiling using + * MATH=68881 + */ +# include +# endif +#endif + +/* This provides the non-ANSI (far) memory allocation routines. */ +#if defined(__TURBOC__) && defined(__MSDOS__) +# include +# include +#endif + +#if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \ + defined(_WIN32) || defined(__WIN32__) +# include /* defines _WINDOWS_ macro */ +#endif +#endif /* PNG_VERSION_INFO_ONLY */ + +/* Moved here around 1.5.0beta36 from pngconf.h */ +/* Users may want to use these so they are not private. Any library + * functions that are passed far data must be model-independent. + */ + +/* Memory model/platform independent fns */ +#ifndef PNG_ABORT +# ifdef _WINDOWS_ +# define PNG_ABORT() ExitProcess(0) +# else +# define PNG_ABORT() abort() +# endif +#endif + +/* These macros may need to be architecture dependent. */ +#define PNG_ALIGN_NONE 0 /* do not use data alignment */ +#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ +#ifdef offsetof +# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */ +#else +# define PNG_ALIGN_OFFSET -1 /* prevent the use of this */ +#endif +#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */ + +#ifndef PNG_ALIGN_TYPE + /* Default to using aligned access optimizations and requiring alignment to a + * multiple of the data type size. Override in a compiler specific fashion + * if necessary by inserting tests here: + */ +# define PNG_ALIGN_TYPE PNG_ALIGN_SIZE +#endif + +#if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE + /* This is used because in some compiler implementations non-aligned + * structure members are supported, so the offsetof approach below fails. + * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access + * is good for performance. Do not do this unless you have tested the result + * and understand it. + */ +# define png_alignof(type) (sizeof (type)) +#else +# if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET +# define png_alignof(type) offsetof(struct{char c; type t;}, t) +# else +# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS +# define png_alignof(type) (1) +# endif + /* Else leave png_alignof undefined to prevent use thereof */ +# endif +#endif + +/* This implicitly assumes alignment is always to a power of 2. */ +#ifdef png_alignof +# define png_isaligned(ptr, type)\ + ((((const char*)ptr-(const char*)0) & (png_alignof(type)-1)) == 0) +#else +# define png_isaligned(ptr, type) 0 +#endif + +/* End of memory model/platform independent support */ +/* End of 1.5.0beta36 move from pngconf.h */ + +/* CONSTANTS and UTILITY MACROS + * These are used internally by libpng and not exposed in the API + */ + +/* Various modes of operation. Note that after an init, mode is set to + * zero automatically when the structure is created. Three of these + * are defined in png.h because they need to be visible to applications + * that call png_set_unknown_chunk(). + */ +/* #define PNG_HAVE_IHDR 0x01 (defined in png.h) */ +/* #define PNG_HAVE_PLTE 0x02 (defined in png.h) */ +#define PNG_HAVE_IDAT 0x04 +/* #define PNG_AFTER_IDAT 0x08 (defined in png.h) */ +#define PNG_HAVE_IEND 0x10 + /* 0x20 (unused) */ + /* 0x40 (unused) */ + /* 0x80 (unused) */ +#define PNG_HAVE_CHUNK_HEADER 0x100 +#define PNG_WROTE_tIME 0x200 +#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 +#define PNG_BACKGROUND_IS_GRAY 0x800 +#define PNG_HAVE_PNG_SIGNATURE 0x1000 +#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ + /* 0x4000 (unused) */ +#define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */ + +/* Flags for the transformations the PNG library does on the image data */ +#define PNG_BGR 0x0001 +#define PNG_INTERLACE 0x0002 +#define PNG_PACK 0x0004 +#define PNG_SHIFT 0x0008 +#define PNG_SWAP_BYTES 0x0010 +#define PNG_INVERT_MONO 0x0020 +#define PNG_QUANTIZE 0x0040 +#define PNG_COMPOSE 0x0080 /* Was PNG_BACKGROUND */ +#define PNG_BACKGROUND_EXPAND 0x0100 +#define PNG_EXPAND_16 0x0200 /* Added to libpng 1.5.2 */ +#define PNG_16_TO_8 0x0400 /* Becomes 'chop' in 1.5.4 */ +#define PNG_RGBA 0x0800 +#define PNG_EXPAND 0x1000 +#define PNG_GAMMA 0x2000 +#define PNG_GRAY_TO_RGB 0x4000 +#define PNG_FILLER 0x8000 +#define PNG_PACKSWAP 0x10000 +#define PNG_SWAP_ALPHA 0x20000 +#define PNG_STRIP_ALPHA 0x40000 +#define PNG_INVERT_ALPHA 0x80000 +#define PNG_USER_TRANSFORM 0x100000 +#define PNG_RGB_TO_GRAY_ERR 0x200000 +#define PNG_RGB_TO_GRAY_WARN 0x400000 +#define PNG_RGB_TO_GRAY 0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */ +#define PNG_ENCODE_ALPHA 0x800000 /* Added to libpng-1.5.4 */ +#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */ +#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */ +#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ +/* Flags for png_create_struct */ +#define PNG_STRUCT_PNG 0x0001 +#define PNG_STRUCT_INFO 0x0002 + +/* Scaling factor for filter heuristic weighting calculations */ +#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) +#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) + +/* Flags for the png_ptr->flags rather than declaring a byte for each one */ +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 +#define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002 /* Added to libpng-1.6.0 */ + /* 0x0004 unused */ +#define PNG_FLAG_ZSTREAM_ENDED 0x0008 /* Added to libpng-1.6.0 */ + /* 0x0010 unused */ + /* 0x0020 unused */ +#define PNG_FLAG_ROW_INIT 0x0040 +#define PNG_FLAG_FILLER_AFTER 0x0080 +#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 +#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 +#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 +#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 +#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */ +/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000 */ +/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000 */ +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000 +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000 +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000 +#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000 /* Added to libpng-1.4.0 */ +#define PNG_FLAG_APP_WARNINGS_WARN 0x200000 /* Added to libpng-1.6.0 */ +#define PNG_FLAG_APP_ERRORS_WARN 0x400000 /* Added to libpng-1.6.0 */ + /* 0x800000 unused */ + /* 0x1000000 unused */ + /* 0x2000000 unused */ + /* 0x4000000 unused */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ + +#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ + PNG_FLAG_CRC_ANCILLARY_NOWARN) + +#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ + PNG_FLAG_CRC_CRITICAL_IGNORE) + +#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ + PNG_FLAG_CRC_CRITICAL_MASK) + +/* Save typing and make code easier to understand */ + +#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ + abs((int)((c1).green) - (int)((c2).green)) + \ + abs((int)((c1).blue) - (int)((c2).blue))) + +/* Added to libpng-1.6.0: scale a 16-bit value in the range 0..65535 to 0..255 + * by dividing by 257 *with rounding*. This macro is exact for the given range. + * See the discourse in pngrtran.c png_do_scale_16_to_8. The values in the + * macro were established by experiment (modifying the added value). The macro + * has a second variant that takes a value already scaled by 255 and divides by + * 65535 - this has a maximum error of .502. Over the range 0..65535*65535 it + * only gives off-by-one errors and only for 0.5% (1 in 200) of the values. + */ +#define PNG_DIV65535(v24) (((v24) + 32895) >> 16) +#define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255) + +/* Added to libpng-1.2.6 JB */ +#define PNG_ROWBYTES(pixel_bits, width) \ + ((pixel_bits) >= 8 ? \ + ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \ + (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) ) + +/* PNG_OUT_OF_RANGE returns true if value is outside the range + * ideal-delta..ideal+delta. Each argument is evaluated twice. + * "ideal" and "delta" should be constants, normally simple + * integers, "value" a variable. Added to libpng-1.2.6 JB + */ +#define PNG_OUT_OF_RANGE(value, ideal, delta) \ + ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) + +/* Conversions between fixed and floating point, only defined if + * required (to make sure the code doesn't accidentally use float + * when it is supposedly disabled.) + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +/* The floating point conversion can't overflow, though it can and + * does lose accuracy relative to the original fixed point value. + * In practice this doesn't matter because png_fixed_point only + * stores numbers with very low precision. The png_ptr and s + * arguments are unused by default but are there in case error + * checking becomes a requirement. + */ +#define png_float(png_ptr, fixed, s) (.00001 * (fixed)) + +/* The fixed point conversion performs range checking and evaluates + * its argument multiple times, so must be used with care. The + * range checking uses the PNG specification values for a signed + * 32 bit fixed point value except that the values are deliberately + * rounded-to-zero to an integral value - 21474 (21474.83 is roughly + * (2^31-1) * 100000). 's' is a string that describes the value being + * converted. + * + * NOTE: this macro will raise a png_error if the range check fails, + * therefore it is normally only appropriate to use this on values + * that come from API calls or other sources where an out of range + * error indicates a programming error, not a data error! + * + * NOTE: by default this is off - the macro is not used - because the + * function call saves a lot of code. + */ +#ifdef PNG_FIXED_POINT_MACRO_SUPPORTED +#define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\ + ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0)) +#endif +/* else the corresponding function is defined below, inside the scope of the + * cplusplus test. + */ +#endif + +/* Constants for known chunk types. If you need to add a chunk, define the name + * here. For historical reasons these constants have the form png_; i.e. + * the prefix is lower case. Please use decimal values as the parameters to + * match the ISO PNG specification and to avoid relying on the C locale + * interpretation of character values. + * + * Prior to 1.5.6 these constants were strings, as of 1.5.6 png_uint_32 values + * are computed and a new macro (PNG_STRING_FROM_CHUNK) added to allow a string + * to be generated if required. + * + * PNG_32b correctly produces a value shifted by up to 24 bits, even on + * architectures where (int) is only 16 bits. + */ +#define PNG_32b(b,s) ((png_uint_32)(b) << (s)) +#define PNG_U32(b1,b2,b3,b4) \ + (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) + +/* Constants for known chunk types. + * + * MAINTAINERS: If you need to add a chunk, define the name here. + * For historical reasons these constants have the form png_; i.e. + * the prefix is lower case. Please use decimal values as the parameters to + * match the ISO PNG specification and to avoid relying on the C locale + * interpretation of character values. Please keep the list sorted. + * + * Notice that PNG_U32 is used to define a 32-bit value for the 4 byte chunk + * type. In fact the specification does not express chunk types this way, + * however using a 32-bit value means that the chunk type can be read from the + * stream using exactly the same code as used for a 32-bit unsigned value and + * can be examined far more efficiently (using one arithmetic compare). + * + * Prior to 1.5.6 the chunk type constants were expressed as C strings. The + * libpng API still uses strings for 'unknown' chunks and a macro, + * PNG_STRING_FROM_CHUNK, allows a string to be generated if required. Notice + * that for portable code numeric values must still be used; the string "IHDR" + * is not portable and neither is PNG_U32('I', 'H', 'D', 'R'). + * + * In 1.7.0 the definitions will be made public in png.h to avoid having to + * duplicate the same definitions in application code. + */ +#define png_IDAT PNG_U32( 73, 68, 65, 84) +#define png_IEND PNG_U32( 73, 69, 78, 68) +#define png_IHDR PNG_U32( 73, 72, 68, 82) +#define png_PLTE PNG_U32( 80, 76, 84, 69) +#define png_bKGD PNG_U32( 98, 75, 71, 68) +#define png_cHRM PNG_U32( 99, 72, 82, 77) +#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ +#define png_gAMA PNG_U32(103, 65, 77, 65) +#define png_gIFg PNG_U32(103, 73, 70, 103) +#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */ +#define png_gIFx PNG_U32(103, 73, 70, 120) +#define png_hIST PNG_U32(104, 73, 83, 84) +#define png_iCCP PNG_U32(105, 67, 67, 80) +#define png_iTXt PNG_U32(105, 84, 88, 116) +#define png_oFFs PNG_U32(111, 70, 70, 115) +#define png_pCAL PNG_U32(112, 67, 65, 76) +#define png_pHYs PNG_U32(112, 72, 89, 115) +#define png_sBIT PNG_U32(115, 66, 73, 84) +#define png_sCAL PNG_U32(115, 67, 65, 76) +#define png_sPLT PNG_U32(115, 80, 76, 84) +#define png_sRGB PNG_U32(115, 82, 71, 66) +#define png_sTER PNG_U32(115, 84, 69, 82) +#define png_tEXt PNG_U32(116, 69, 88, 116) +#define png_tIME PNG_U32(116, 73, 77, 69) +#define png_tRNS PNG_U32(116, 82, 78, 83) +#define png_zTXt PNG_U32(122, 84, 88, 116) + +/* The following will work on (signed char*) strings, whereas the get_uint_32 + * macro will fail on top-bit-set values because of the sign extension. + */ +#define PNG_CHUNK_FROM_STRING(s)\ + PNG_U32(0xff&(s)[0], 0xff&(s)[1], 0xff&(s)[2], 0xff&(s)[3]) + +/* This uses (char), not (png_byte) to avoid warnings on systems where (char) is + * signed and the argument is a (char[]) This macro will fail miserably on + * systems where (char) is more than 8 bits. + */ +#define PNG_STRING_FROM_CHUNK(s,c)\ + (void)(((char*)(s))[0]=(char)((c)>>24), ((char*)(s))[1]=(char)((c)>>16),\ + ((char*)(s))[2]=(char)((c)>>8), ((char*)(s))[3]=(char)((c))) + +/* Do the same but terminate with a null character. */ +#define PNG_CSTRING_FROM_CHUNK(s,c)\ + (void)(PNG_STRING_FROM_CHUNK(s,c), ((char*)(s))[4] = 0) + +/* Test on flag values as defined in the spec (section 5.4): */ +#define PNG_CHUNK_ANCILLARY(c) (1 & ((c) >> 29)) +#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c)) +#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) +#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) +#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) + +/* Gamma values (new at libpng-1.5.4): */ +#define PNG_GAMMA_MAC_OLD 151724 /* Assume '1.8' is really 2.2/1.45! */ +#define PNG_GAMMA_MAC_INVERSE 65909 +#define PNG_GAMMA_sRGB_INVERSE 45455 + +/* Almost everything below is C specific; the #defines above can be used in + * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot. + */ +#ifndef PNG_VERSION_INFO_ONLY + +#include "pngstruct.h" +#include "pnginfo.h" + +/* Validate the include paths - the include path used to generate pnglibconf.h + * must match that used in the build, or we must be using pnglibconf.h.prebuilt: + */ +#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM +# error ZLIB_VERNUM != PNG_ZLIB_VERNUM \ + "-I (include path) error: see the notes in pngpriv.h" + /* This means that when pnglibconf.h was built the copy of zlib.h that it + * used is not the same as the one being used here. Because the build of + * libpng makes decisions to use inflateInit2 and inflateReset2 based on the + * zlib version number and because this affects handling of certain broken + * PNG files the -I directives must match. + * + * The most likely explanation is that you passed a -I in CFLAGS, this will + * not work; all the preprocessor directories and in particular all the -I + * directives must be in CPPFLAGS. + */ +#endif + +/* This is used for 16 bit gamma tables -- only the top level pointers are + * const; this could be changed: + */ +typedef const png_uint_16p * png_const_uint_16pp; + +/* Added to libpng-1.5.7: sRGB conversion tables */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]); + /* Convert from an sRGB encoded value 0..255 to a 16-bit linear value, + * 0..65535. This table gives the closest 16-bit answers (no errors). + */ +#endif + +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]); +PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]); + +#define PNG_sRGB_FROM_LINEAR(linear) ((png_byte)((png_sRGB_base[(linear)>>15] +\ + ((((linear)&0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8)) + /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB + * encoded value with maximum error 0.646365. Note that the input is not a + * 16-bit value; it has been multiplied by 255! */ +#endif /* PNG_SIMPLIFIED_READ/WRITE */ + + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Internal functions; these are not exported from a DLL however because they + * are used within several of the C source files they have to be C extern. + * + * All of these functions must be declared with PNG_INTERNAL_FUNCTION. + */ + +/* Zlib support */ +#define PNG_UNEXPECTED_ZLIB_RETURN (-7) +PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret), + PNG_EMPTY); + /* Used by the zlib handling functions to ensure that z_stream::msg is always + * set before they return. + */ + +#ifdef PNG_WRITE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr, + png_compression_bufferp *list),PNG_EMPTY); + /* Free the buffer list used by the compressed write code. */ +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ + defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ + (defined(PNG_sCAL_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) +PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr, + double fp, png_const_charp text),PNG_EMPTY); +#endif + +/* Check the user version string for compatibility, returns false if the version + * numbers aren't compatible. + */ +PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr, + png_const_charp user_png_ver),PNG_EMPTY); + +/* Internal base allocator - no messages, NULL on failure to allocate. This + * does, however, call the application provided allocator and that could call + * png_error (although that would be a bug in the application implementation.) + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr, + png_alloc_size_t size),PNG_ALLOCATED); + +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ + defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) +/* Internal array allocator, outputs no error or warning messages on failure, + * just returns NULL. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr, + int nelements, size_t element_size),PNG_ALLOCATED); + +/* The same but an existing array is extended by add_elements. This function + * also memsets the new elements to 0 and copies the old elements. The old + * array is not freed or altered. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr, + png_const_voidp array, int old_elements, int add_elements, + size_t element_size),PNG_ALLOCATED); +#endif /* text, sPLT or unknown chunks */ + +/* Magic to create a struct when there is no struct to call the user supplied + * memory allocators. Because error handling has not been set up the memory + * handlers can't safely call png_error, but this is an obscure and undocumented + * restriction so libpng has to assume that the 'free' handler, at least, might + * call png_error. + */ +PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, + png_free_ptr free_fn),PNG_ALLOCATED); + +/* Free memory from internal libpng struct */ +PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr), + PNG_EMPTY); + +/* Free an allocated jmp_buf (always succeeds) */ +PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY); + +/* Function to allocate memory for zlib. PNGAPI is disallowed. */ +PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size), + PNG_ALLOCATED); + +/* Function to free memory for zlib. PNGAPI is disallowed. */ +PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY); + +/* Next four functions are used internally as callbacks. PNGCBAPI is required + * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3, changed to + * PNGCBAPI at 1.5.0 + */ + +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr, + png_bytep buffer, png_size_t length),PNG_EMPTY); +#endif + +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_STDIO_SUPPORTED +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr), + PNG_EMPTY); +# endif +#endif + +/* Reset the CRC variable */ +PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY); + +/* Write the "data" buffer to whatever output you are using */ +PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr, + png_const_bytep data, png_size_t length),PNG_EMPTY); + +/* Read and check the PNG file signature */ +PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); + +/* Read the chunk header (length + type name) */ +PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr), + PNG_EMPTY); + +/* Read data from whatever input you are using into the "data" buffer */ +PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data, + png_size_t length),PNG_EMPTY); + +/* Read bytes into buf, and update png_ptr->crc */ +PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf, + png_uint_32 length),PNG_EMPTY); + +/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ +PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr, + png_uint_32 skip),PNG_EMPTY); + +/* Read the CRC from the file and compare it to the libpng calculated CRC */ +PNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY); + +/* Calculate the CRC over a section of data. Note that we are only + * passing a maximum of 64K on systems that have this as a memory limit, + * since this is the maximum buffer size we can specify. + */ +PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr, + png_const_bytep ptr, png_size_t length),PNG_EMPTY); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY); +#endif + +/* Write various chunks */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. + */ +PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, + int compression_method, int filter_method, int interlace_method),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr, + png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr, + png_const_bytep row_data, png_alloc_size_t row_data_length, int flush), + PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY); + +#ifdef PNG_WRITE_gAMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr, + png_fixed_point file_gamma),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr, + png_const_color_8p sbit, int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_cHRM_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr, + const png_xy *xy), PNG_EMPTY); + /* The xy value must have been previously validated */ +#endif + +#ifdef PNG_WRITE_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr, + int intent),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr, + png_const_charp name, png_const_bytep profile), PNG_EMPTY); + /* The profile must have been previously validated for correctness, the + * length comes from the first four bytes. Only the base, deflate, + * compression is supported. + */ +#endif + +#ifdef PNG_WRITE_sPLT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr, + png_const_sPLT_tp palette),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_tRNS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr, + png_const_bytep trans, png_const_color_16p values, int number, + int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_bKGD_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr, + png_const_color_16p values, int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr, + png_const_uint_16p hist, int num_hist),PNG_EMPTY); +#endif + +/* Chunks that have keywords */ +#ifdef PNG_WRITE_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr, + png_const_charp key, png_const_charp text, png_size_t text_len),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp + key, png_const_charp text, png_size_t text_len, int compression),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr, + int compression, png_const_charp key, png_const_charp lang, + png_const_charp lang_key, png_const_charp text),PNG_EMPTY); +#endif + +#ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ +PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_pCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr, + png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, + png_const_charp units, png_charpp params),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_pHYs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr, + png_const_timep mod_time),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, + int unit, png_const_charp width, png_const_charp height),PNG_EMPTY); +#endif + +/* Called when finished processing a row of data */ +PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr), + PNG_EMPTY); + +/* Internal use only. Called before first row of data */ +PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr), + PNG_EMPTY); + +/* Combine a row of data, dealing with alpha, etc. if requested. 'row' is an + * array of png_ptr->width pixels. If the image is not interlaced or this + * is the final pass this just does a memcpy, otherwise the "display" flag + * is used to determine whether to copy pixels that are not in the current pass. + * + * Because 'png_do_read_interlace' (below) replicates pixels this allows this + * function to achieve the documented 'blocky' appearance during interlaced read + * if display is 1 and the 'sparkle' appearance, where existing pixels in 'row' + * are not changed if they are not in the current pass, when display is 0. + * + * 'display' must be 0 or 1, otherwise the memcpy will be done regardless. + * + * The API always reads from the png_struct row buffer and always assumes that + * it is full width (png_do_read_interlace has already been called.) + * + * This function is only ever used to write to row buffers provided by the + * caller of the relevant libpng API and the row must have already been + * transformed by the read transformations. + * + * The PNG_USE_COMPILE_TIME_MASKS option causes generation of pre-computed + * bitmasks for use within the code, otherwise runtime generated masks are used. + * The default is compile time masks. + */ +#ifndef PNG_USE_COMPILE_TIME_MASKS +# define PNG_USE_COMPILE_TIME_MASKS 1 +#endif +PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr, + png_bytep row, int display),PNG_EMPTY); + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Expand an interlaced row: the 'row_info' describes the pass data that has + * been read in and must correspond to the pixels in 'row', the pixels are + * expanded (moved apart) in 'row' to match the final layout, when doing this + * the pixels are *replicated* to the intervening space. This is essential for + * the correct operation of png_combine_row, above. + */ +PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY); +#endif + +/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Grab pixels out of a row for an interlaced pass */ +PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info, + png_bytep row, int pass),PNG_EMPTY); +#endif + +/* Unfilter a row: check the filter value before calling this, there is no point + * calling it for PNG_FILTER_VALUE_NONE. + */ +PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop + row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); + +/* Choose the best filter to use and filter the row data */ +PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr, + png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY); + /* Read 'avail_out' bytes of data from the IDAT stream. If the output buffer + * is NULL the function checks, instead, for the end of the stream. In this + * case a benign error will be issued if the stream end is not found or if + * extra data has to be consumed. + */ +PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr), + PNG_EMPTY); + /* This cleans up when the IDAT LZ stream does not end when the last image + * byte is read; there is still some pending input. + */ + +PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr), + PNG_EMPTY); + /* Finish a row while reading, dealing with interlacing passes, etc. */ +#endif + +/* Initialize the row buffers, etc. */ +PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY); + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* Optional call to update the users info structure */ +PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +#endif + +/* These are the functions that do the transformations */ +#ifdef PNG_READ_FILLER_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_filler,(png_row_infop row_info, + png_bytep row, png_uint_32 filler, png_uint_32 flags),PNG_EMPTY); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_swap_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_write_swap_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_invert_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_write_invert_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info, + png_bytep row, int at_start),PNG_EMPTY); +#endif + +#ifdef PNG_16BIT_SUPPORTED +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ + defined(PNG_WRITE_PACKSWAP_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_do_rgb_to_gray,(png_structrp png_ptr, + png_row_infop row_info, png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_gray_to_rgb,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_unpack,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_unshift,(png_row_infop row_info, + png_bytep row, png_const_color_8p sig_bits),PNG_EMPTY); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_scale_16_to_8,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_chop,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_quantize,(png_row_infop row_info, + png_bytep row, png_const_bytep palette_lookup, + png_const_bytep quantize_lookup),PNG_EMPTY); + +# ifdef PNG_CORRECT_PALETTE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_correct_palette,(png_structrp png_ptr, + png_colorp palette, int num_palette),PNG_EMPTY); +# endif +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_pack,(png_row_infop row_info, + png_bytep row, png_uint_32 bit_depth),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_shift,(png_row_infop row_info, + png_bytep row, png_const_color_8p bit_depth),PNG_EMPTY); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_compose,(png_row_infop row_info, + png_bytep row, png_structrp png_ptr),PNG_EMPTY); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_gamma,(png_row_infop row_info, + png_bytep row, png_structrp png_ptr),PNG_EMPTY); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_encode_alpha,(png_row_infop row_info, + png_bytep row, png_structrp png_ptr),PNG_EMPTY); +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_expand_palette,(png_row_infop row_info, + png_bytep row, png_const_colorp palette, png_const_bytep trans, + int num_trans),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_expand,(png_row_infop row_info, + png_bytep row, png_const_color_16p trans_color),PNG_EMPTY); +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_expand_16,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +/* The following decodes the appropriate chunks, and does error correction, + * then calls the appropriate callback for the chunk if it is valid. + */ + +/* Decode the IHDR chunk */ +PNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); + +#ifdef PNG_READ_bKGD_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_hIST_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#ifdef PNG_READ_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#ifdef PNG_READ_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tIME_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_structrp png_ptr, + png_uint_32 chunk_name),PNG_EMPTY); + +#ifdef PNG_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY); + /* This is the function that gets called for unknown chunks. The 'keep' + * argument is either non-zero for a known chunk that has been set to be + * handled as unknown or zero for an unknown chunk. By default the function + * just skips the chunk or errors out if it is critical. + */ + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling, + (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY); + /* Exactly as the API png_handle_as_unknown() except that the argument is a + * 32-bit chunk name, not a string. + */ +#endif +#endif /* PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED */ + +/* Handle the transformations for reading and writing */ +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); +#endif +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr), + PNG_EMPTY); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_crc_skip,(png_structrp png_ptr, + png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_crc_finish,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr, + png_bytep row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr), + PNG_EMPTY); +# ifdef PNG_READ_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif +# ifdef PNG_READ_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif +# ifdef PNG_READ_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_intrapixel,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_write_intrapixel,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +/* Added at libpng version 1.6.0 */ +#ifdef PNG_GAMMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY); + /* Set the colorspace gamma with a value provided by the application or by + * the gAMA chunk on read. The value will override anything set by an ICC + * profile. + */ + +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Synchronize the info 'valid' flags with the colorspace */ + +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Copy the png_struct colorspace to the info_struct and call the above to + * synchronize the flags. Checks for NULL info_ptr and does nothing. + */ +#endif + +/* Added at libpng version 1.4.0 */ +#ifdef PNG_COLORSPACE_SUPPORTED +/* These internal functions are for maintaining the colorspace structure within + * a png_info or png_struct (or, indeed, both). + */ +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy, + int preferred), PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ, + int preferred), PNG_EMPTY); + +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr, + png_colorspacerp colorspace, int intent), PNG_EMPTY); + /* This does set the colorspace gAMA and cHRM values too, but doesn't set the + * flags to write them, if it returns false there was a problem and an error + * message has already been output (but the colorspace may still need to be + * synced to record the invalid flag). + */ +#endif /* sRGB */ + +#ifdef PNG_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, png_const_bytep profile, int color_type), + PNG_EMPTY); + /* The 'name' is used for information only */ + +/* Routines for checking parts of an ICC profile. */ +PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length), PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* first 132 bytes only */, int color_type), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY); +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,( + png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_bytep profile, uLong adler), PNG_EMPTY); + /* 'adler' is the Adler32 checksum of the uncompressed profile data. It may + * be zero to indicate that it is not available. It is used, if provided, + * as a fast check on the profile when checking to see if it is sRGB. + */ +#endif +#endif /* iCCP */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients, + (png_structrp png_ptr), PNG_EMPTY); + /* Set the rgb_to_gray coefficients from the colorspace Y values */ +#endif /* READ_RGB_TO_GRAY */ +#endif /* COLORSPACE */ + +/* Added at libpng version 1.4.0 */ +PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type),PNG_EMPTY); + +/* Added at libpng version 1.5.10 */ +#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ + defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes, + (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr, + png_const_charp name),PNG_NORETURN); +#endif + +/* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite + * the end. Always leaves the buffer nul terminated. Never errors out (and + * there is no error code.) + */ +PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize, + size_t pos, png_const_charp string),PNG_EMPTY); + +/* Various internal functions to handle formatted warning messages, currently + * only implemented for warnings. + */ +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) +/* Utility to dump an unsigned value into a buffer, given a start pointer and + * and end pointer (which should point just *beyond* the end of the buffer!) + * Returns the pointer to the start of the formatted string. This utility only + * does unsigned values. + */ +PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start, + png_charp end, int format, png_alloc_size_t number),PNG_EMPTY); + +/* Convenience macro that takes an array: */ +#define PNG_FORMAT_NUMBER(buffer,format,number) \ + png_format_number(buffer, buffer + (sizeof buffer), format, number) + +/* Suggested size for a number buffer (enough for 64 bits and a sign!) */ +#define PNG_NUMBER_BUFFER_SIZE 24 + +/* These are the integer formats currently supported, the name is formed from + * the standard printf(3) format string. + */ +#define PNG_NUMBER_FORMAT_u 1 /* chose unsigned API! */ +#define PNG_NUMBER_FORMAT_02u 2 +#define PNG_NUMBER_FORMAT_d 1 /* chose signed API! */ +#define PNG_NUMBER_FORMAT_02d 2 +#define PNG_NUMBER_FORMAT_x 3 +#define PNG_NUMBER_FORMAT_02x 4 +#define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */ +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* New defines and members adding in libpng-1.5.4 */ +# define PNG_WARNING_PARAMETER_SIZE 32 +# define PNG_WARNING_PARAMETER_COUNT 8 /* Maximum 9; see pngerror.c */ + +/* An l-value of this type has to be passed to the APIs below to cache the + * values of the parameters to a formatted warning message. + */ +typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][ + PNG_WARNING_PARAMETER_SIZE]; + +PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p, + int number, png_const_charp string),PNG_EMPTY); + /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters, + * including the trailing '\0'. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned, + (png_warning_parameters p, int number, int format, png_alloc_size_t value), + PNG_EMPTY); + /* Use png_alloc_size_t because it is an unsigned type as big as any we + * need to output. Use the following for a signed value. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed, + (png_warning_parameters p, int number, int format, png_int_32 value), + PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr, + png_warning_parameters p, png_const_charp message),PNG_EMPTY); + /* 'message' follows the X/Open approach of using @1, @2 to insert + * parameters previously supplied using the above functions. Errors in + * specifying the parameters will simply result in garbage substitutions. + */ +#endif + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Application errors (new in 1.6); use these functions (declared below) for + * errors in the parameters or order of API function calls on read. The + * 'warning' should be used for an error that can be handled completely; the + * 'error' for one which can be handled safely but which may lose application + * information or settings. + * + * By default these both result in a png_error call prior to release, while in a + * released version the 'warning' is just a warning. However if the application + * explicitly disables benign errors (explicitly permitting the code to lose + * information) they both turn into warnings. + * + * If benign errors aren't supported they end up as the corresponding base call + * (png_warning or png_error.) + */ +PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* The application provided invalid parameters to an API function or called + * an API function at the wrong time, libpng can completely recover. + */ + +PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* As above but libpng will ignore the call, or attempt some other partial + * recovery from the error. + */ +#else +# define png_app_warning(pp,s) png_warning(pp,s) +# define png_app_error(pp,s) png_error(pp,s) +#endif + +PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr, + png_const_charp message, int error),PNG_EMPTY); + /* Report a recoverable issue in chunk data. On read this is used to report + * a problem found while reading a particular chunk and the + * png_chunk_benign_error or png_chunk_warning function is used as + * appropriate. On write this is used to report an error that comes from + * data set via an application call to a png_set_ API and png_app_error or + * png_app_warning is used as appropriate. + * + * The 'error' parameter must have one of the following values: + */ +#define PNG_CHUNK_WARNING 0 /* never an error */ +#define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */ +#define PNG_CHUNK_ERROR 2 /* always an error */ + +/* ASCII to FP interfaces, currently only implemented if sCAL + * support is required. + */ +#if defined(PNG_sCAL_SUPPORTED) +/* MAX_DIGITS is actually the maximum number of characters in an sCAL + * width or height, derived from the precision (number of significant + * digits - a build time settable option) and assumptions about the + * maximum ridiculous exponent. + */ +#define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/) + +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, double fp, unsigned int precision), + PNG_EMPTY); +#endif /* FLOATING_POINT */ + +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, png_fixed_point fp),PNG_EMPTY); +#endif /* FIXED_POINT */ +#endif /* sCAL */ + +#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) +/* An internal API to validate the format of a floating point number. + * The result is the index of the next character. If the number is + * not valid it will be the index of a character in the supposed number. + * + * The format of a number is defined in the PNG extensions specification + * and this API is strictly conformant to that spec, not anyone elses! + * + * The format as a regular expression is: + * + * [+-]?[0-9]+.?([Ee][+-]?[0-9]+)? + * + * or: + * + * [+-]?.[0-9]+(.[0-9]+)?([Ee][+-]?[0-9]+)? + * + * The complexity is that either integer or fraction must be present and the + * fraction is permitted to have no digits only if the integer is present. + * + * NOTE: The dangling E problem. + * There is a PNG valid floating point number in the following: + * + * PNG floating point numbers are not greedy. + * + * Working this out requires *TWO* character lookahead (because of the + * sign), the parser does not do this - it will fail at the 'r' - this + * doesn't matter for PNG sCAL chunk values, but it requires more care + * if the value were ever to be embedded in something more complex. Use + * ANSI-C strtod if you need the lookahead. + */ +/* State table for the parser. */ +#define PNG_FP_INTEGER 0 /* before or in integer */ +#define PNG_FP_FRACTION 1 /* before or in fraction */ +#define PNG_FP_EXPONENT 2 /* before or in exponent */ +#define PNG_FP_STATE 3 /* mask for the above */ +#define PNG_FP_SAW_SIGN 4 /* Saw +/- in current state */ +#define PNG_FP_SAW_DIGIT 8 /* Saw a digit in current state */ +#define PNG_FP_SAW_DOT 16 /* Saw a dot in current state */ +#define PNG_FP_SAW_E 32 /* Saw an E (or e) in current state */ +#define PNG_FP_SAW_ANY 60 /* Saw any of the above 4 */ + +/* These three values don't affect the parser. They are set but not used. + */ +#define PNG_FP_WAS_VALID 64 /* Preceding substring is a valid fp number */ +#define PNG_FP_NEGATIVE 128 /* A negative number, including "-0" */ +#define PNG_FP_NONZERO 256 /* A non-zero value */ +#define PNG_FP_STICKY 448 /* The above three flags */ + +/* This is available for the caller to store in 'state' if required. Do not + * call the parser after setting it (the parser sometimes clears it.) + */ +#define PNG_FP_INVALID 512 /* Available for callers as a distinct value */ + +/* Result codes for the parser (boolean - true meants ok, false means + * not ok yet.) + */ +#define PNG_FP_MAYBE 0 /* The number may be valid in the future */ +#define PNG_FP_OK 1 /* The number is valid */ + +/* Tests on the sticky non-zero and negative flags. To pass these checks + * the state must also indicate that the whole number is valid - this is + * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this + * is equivalent to PNG_FP_OK above.) + */ +#define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO) + /* NZ_MASK: the string is valid and a non-zero negative value */ +#define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO) + /* Z MASK: the string is valid and a non-zero value. */ + /* PNG_FP_SAW_DIGIT: the string is valid. */ +#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT) +#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK) +#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK) + +/* The actual parser. This can be called repeatedly. It updates + * the index into the string and the state variable (which must + * be initialized to 0). It returns a result code, as above. There + * is no point calling the parser any more if it fails to advance to + * the end of the string - it is stuck on an invalid character (or + * terminated by '\0'). + * + * Note that the pointer will consume an E or even an E+ and then leave + * a 'maybe' state even though a preceding integer.fraction is valid. + * The PNG_FP_WAS_VALID flag indicates that a preceding substring was + * a valid number. It's possible to recover from this by calling + * the parser again (from the start, with state 0) but with a string + * that omits the last character (i.e. set the size to the index of + * the problem character.) This has not been tested within libpng. + */ +PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string, + png_size_t size, int *statep, png_size_tp whereami),PNG_EMPTY); + +/* This is the same but it checks a complete string and returns true + * only if it just contains a floating point number. As of 1.5.4 this + * function also returns the state at the end of parsing the number if + * it was valid (otherwise it returns 0.) This can be used for testing + * for negative or zero values using the sticky flag. + */ +PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string, + png_size_t size),PNG_EMPTY); +#endif /* pCAL || sCAL */ + +#if defined(PNG_READ_GAMMA_SUPPORTED) ||\ + defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) +/* Added at libpng version 1.5.0 */ +/* This is a utility to provide a*times/div (rounded) and indicate + * if there is an overflow. The result is a boolean - false (0) + * for overflow, true (1) if no overflow, in which case *res + * holds the result. + */ +PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a, + png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) +/* Same deal, but issue a warning on overflow and return 0. */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn, + (png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by, + png_int_32 divided_by),PNG_EMPTY); +#endif + +#ifdef PNG_GAMMA_SUPPORTED +/* Calculate a reciprocal - used for gamma values. This returns + * 0 if the argument is 0 in order to maintain an undefined value; + * there are no warnings. + */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a), + PNG_EMPTY); + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* The same but gives a reciprocal of the product of two fixed point + * values. Accuracy is suitable for gamma calculations but this is + * not exact - use png_muldiv for that. Only required at present on read. + */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a, + png_fixed_point b),PNG_EMPTY); +#endif + +/* Return true if the gamma value is significantly different from 1.0 */ +PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value), + PNG_EMPTY); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Internal fixed point gamma correction. These APIs are called as + * required to convert single values - they don't need to be fast, + * they are not used when processing image pixel values. + * + * While the input is an 'unsigned' value it must actually be the + * correct bit value - 0..255 or 0..65535 as required. + */ +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr, + unsigned int value, png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr, + int bit_depth),PNG_EMPTY); +#endif + +/* SIMPLIFIED READ/WRITE SUPPORT */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/* The internal structure that png_image::opaque points to. */ +typedef struct png_control +{ + png_structp png_ptr; + png_infop info_ptr; + png_voidp error_buf; /* Always a jmp_buf at present. */ + + png_const_bytep memory; /* Memory buffer. */ + png_size_t size; /* Size of the memory buffer. */ + + unsigned int for_write :1; /* Otherwise it is a read structure */ + unsigned int owned_file :1; /* We own the file in io_ptr */ +} png_control; + +/* Return the pointer to the jmp_buf from a png_control: necessary because C + * does not reveal the type of the elements of jmp_buf. + */ +#ifdef __cplusplus +# define png_control_jmp_buf(pc) (((jmp_buf*)((pc)->error_buf))[0]) +#else +# define png_control_jmp_buf(pc) ((pc)->error_buf) +#endif + +/* Utility to safely execute a piece of libpng code catching and logging any + * errors that might occur. Returns true on success, false on failure (either + * of the function or as a result of a png_error.) + */ +PNG_INTERNAL_FUNCTION(void,png_safe_error,(png_structp png_ptr, + png_const_charp error_message),PNG_NORETURN); + +#ifdef PNG_WARNINGS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_safe_warning,(png_structp png_ptr, + png_const_charp warning_message),PNG_EMPTY); +#else +# define png_safe_warning 0/*dummy argument*/ +#endif + +PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image, + int (*function)(png_voidp), png_voidp arg),PNG_EMPTY); + +/* Utility to log an error; this also cleans up the png_image; the function + * always returns 0 (false). + */ +PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image, + png_const_charp error_message),PNG_EMPTY); + +#ifndef PNG_SIMPLIFIED_READ_SUPPORTED +/* png_image_free is used by the write code but not exported */ +PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY); +#endif /* !SIMPLIFIED_READ */ + +#endif /* SIMPLIFIED READ/WRITE */ + +/* These are initialization functions for hardware specific PNG filter + * optimizations; list these here then select the appropriate one at compile + * time using the macro PNG_FILTER_OPTIMIZATIONS. If the macro is not defined + * the generic code is used. + */ +#ifdef PNG_FILTER_OPTIMIZATIONS +PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr, + unsigned int bpp), PNG_EMPTY); + /* Just declare the optimization that will be used */ +#else + /* List *all* the possible optimizations here - this branch is required if + * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in + * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing. + */ +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon, + (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); +#endif + +/* Maintainer: Put new private prototypes here ^ */ + +#include "pngdebug.h" + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +#endif /* PNGPRIV_H */ diff --git a/core/src/fxcodec/fx_lpng/lpng_v163/pngstruct.h b/core/src/fxcodec/fx_lpng/lpng_v163/pngstruct.h new file mode 100644 index 0000000000..269470531e --- /dev/null +++ b/core/src/fxcodec/fx_lpng/lpng_v163/pngstruct.h @@ -0,0 +1,489 @@ + +/* pngstruct.h - header file for PNG reference library + * + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* The structure that holds the information to read and write PNG files. + * The only people who need to care about what is inside of this are the + * people who will be modifying the library for their own special needs. + * It should NOT be accessed directly by an application. + */ + +#ifndef PNGSTRUCT_H +#define PNGSTRUCT_H +/* zlib.h defines the structure z_stream, an instance of which is included + * in this structure and is required for decompressing the LZ compressed + * data in PNG files. + */ +#ifndef ZLIB_CONST + /* We must ensure that zlib uses 'const' in declarations. */ +# define ZLIB_CONST +#endif +#include "../../fx_zlib/include/fx_zlib.h" +#ifdef const + /* zlib.h sometimes #defines const to nothing, undo this. */ +# undef const +#endif + +/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility + * with older builds. + */ +#if ZLIB_VERNUM < 0x1260 +# define PNGZ_MSG_CAST(s) png_constcast(char*,s) +# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b) +#else +# define PNGZ_MSG_CAST(s) (s) +# define PNGZ_INPUT_CAST(b) (b) +#endif + +/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib + * can handle at once. This type need be no larger than 16 bits (so maximum of + * 65535), this define allows us to discover how big it is, but limited by the + * maximuum for png_size_t. The value can be overriden in a library build + * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably + * lower value (e.g. 255 works). A lower value may help memory usage (slightly) + * and may even improve performance on some systems (and degrade it on others.) + */ +#ifndef ZLIB_IO_MAX +# define ZLIB_IO_MAX ((uInt)-1) +#endif + +#ifdef PNG_WRITE_SUPPORTED +/* The type of a compression buffer list used by the write code. */ +typedef struct png_compression_buffer +{ + struct png_compression_buffer *next; + png_byte output[1]; /* actually zbuf_size */ +} png_compression_buffer, *png_compression_bufferp; + +#define PNG_COMPRESSION_BUFFER_SIZE(pp)\ + (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size) +#endif + +/* Colorspace support; structures used in png_struct, png_info and in internal + * functions to hold and communicate information about the color space. + * + * PNG_COLORSPACE_SUPPORTED is only required if the application will perform + * colorspace corrections, otherwise all the colorspace information can be + * skipped and the size of libpng can be reduced (significantly) by compiling + * out the colorspace support. + */ +#ifdef PNG_COLORSPACE_SUPPORTED +/* The chromaticities of the red, green and blue colorants and the chromaticity + * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)). + */ +typedef struct png_xy +{ + png_fixed_point redx, redy; + png_fixed_point greenx, greeny; + png_fixed_point bluex, bluey; + png_fixed_point whitex, whitey; +} png_xy; + +/* The same data as above but encoded as CIE XYZ values. When this data comes + * from chromaticities the sum of the Y values is assumed to be 1.0 + */ +typedef struct png_XYZ +{ + png_fixed_point red_X, red_Y, red_Z; + png_fixed_point green_X, green_Y, green_Z; + png_fixed_point blue_X, blue_Y, blue_Z; +} png_XYZ; +#endif /* COLORSPACE */ + +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) +/* A colorspace is all the above plus, potentially, profile information, + * however at present libpng does not use the profile internally so it is only + * stored in the png_info struct (if iCCP is supported.) The rendering intent + * is retained here and is checked. + * + * The file gamma encoding information is also stored here and gamma correction + * is done by libpng, whereas color correction must currently be done by the + * application. + */ +typedef struct png_colorspace +{ +#ifdef PNG_GAMMA_SUPPORTED + png_fixed_point gamma; /* File gamma */ +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED + png_xy end_points_xy; /* End points as chromaticities */ + png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */ + png_uint_16 rendering_intent; /* Rendering intent of a profile */ +#endif + + /* Flags are always defined to simplify the code. */ + png_uint_16 flags; /* As defined below */ +} png_colorspace, * PNG_RESTRICT png_colorspacerp; + +typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp; + +/* General flags for the 'flags' field */ +#define PNG_COLORSPACE_HAVE_GAMMA 0x0001 +#define PNG_COLORSPACE_HAVE_ENDPOINTS 0x0002 +#define PNG_COLORSPACE_HAVE_INTENT 0x0004 +#define PNG_COLORSPACE_FROM_gAMA 0x0008 +#define PNG_COLORSPACE_FROM_cHRM 0x0010 +#define PNG_COLORSPACE_FROM_sRGB 0x0020 +#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040 +#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */ +#define PNG_COLORSPACE_INVALID 0x8000 +#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags)) +#endif /* COLORSPACE || GAMMA */ + +struct png_struct_def +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */ + png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */ + jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */ + size_t jmp_buf_size; /* size of the above, if allocated */ +#endif + png_error_ptr error_fn; /* function for printing errors and aborting */ +#ifdef PNG_WARNINGS_SUPPORTED + png_error_ptr warning_fn; /* function for printing warnings */ +#endif + png_voidp error_ptr; /* user supplied struct for error functions */ + png_rw_ptr write_data_fn; /* function for writing output data */ + png_rw_ptr read_data_fn; /* function for reading input data */ + png_voidp io_ptr; /* ptr to application struct for I/O functions */ + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr read_user_transform_fn; /* user read transform */ +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr write_user_transform_fn; /* user write transform */ +#endif + +/* These were added in libpng-1.0.2 */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_voidp user_transform_ptr; /* user supplied struct for user transform */ + png_byte user_transform_depth; /* bit depth of user transformed pixels */ + png_byte user_transform_channels; /* channels in user transformed pixels */ +#endif +#endif + + png_uint_32 mode; /* tells us where we are in the PNG file */ + png_uint_32 flags; /* flags indicating various things to libpng */ + png_uint_32 transformations; /* which transformations to perform */ + + png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */ + z_stream zstream; /* decompression structure */ + +#ifdef PNG_WRITE_SUPPORTED + png_compression_bufferp zbuffer_list; /* Created on demand during write */ + uInt zbuffer_size; /* size of the actual buffer */ + + int zlib_level; /* holds zlib compression level */ + int zlib_method; /* holds zlib compression method */ + int zlib_window_bits; /* holds zlib compression window bits */ + int zlib_mem_level; /* holds zlib compression memory level */ + int zlib_strategy; /* holds zlib compression strategy */ +#endif +/* Added at libpng 1.5.4 */ +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + int zlib_text_level; /* holds zlib compression level */ + int zlib_text_method; /* holds zlib compression method */ + int zlib_text_window_bits; /* holds zlib compression window bits */ + int zlib_text_mem_level; /* holds zlib compression memory level */ + int zlib_text_strategy; /* holds zlib compression strategy */ +#endif +/* End of material added at libpng 1.5.4 */ +/* Added at libpng 1.6.0 */ +#ifdef PNG_WRITE_SUPPORTED + int zlib_set_level; /* Actual values set into the zstream on write */ + int zlib_set_method; + int zlib_set_window_bits; + int zlib_set_mem_level; + int zlib_set_strategy; +#endif + + png_uint_32 width; /* width of image in pixels */ + png_uint_32 height; /* height of image in pixels */ + png_uint_32 num_rows; /* number of rows in current pass */ + png_uint_32 usr_width; /* width of row at start of write */ + png_size_t rowbytes; /* size of row in bytes */ + png_uint_32 iwidth; /* width of current interlaced row in pixels */ + png_uint_32 row_number; /* current row in interlace pass */ + png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */ + png_bytep prev_row; /* buffer to save previous (unfiltered) row. + * This is a pointer into big_prev_row + */ + png_bytep row_buf; /* buffer to save current (unfiltered) row. + * This is a pointer into big_row_buf + */ +#ifdef PNG_WRITE_SUPPORTED + png_bytep sub_row; /* buffer to save "sub" row when filtering */ + png_bytep up_row; /* buffer to save "up" row when filtering */ + png_bytep avg_row; /* buffer to save "avg" row when filtering */ + png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ +#endif + png_size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ + + png_uint_32 idat_size; /* current IDAT size for read */ + png_uint_32 crc; /* current chunk CRC value */ + png_colorp palette; /* palette from the input file */ + png_uint_16 num_palette; /* number of color entries in palette */ + +/* Added at libpng-1.5.10 */ +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + int num_palette_max; /* maximum palette index found in IDAT */ +#endif + + png_uint_16 num_trans; /* number of transparency values */ + png_byte compression; /* file compression type (always 0) */ + png_byte filter; /* file filter type (always 0) */ + png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + png_byte pass; /* current interlace pass (0 - 6) */ + png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ + png_byte color_type; /* color type of file */ + png_byte bit_depth; /* bit depth of file */ + png_byte usr_bit_depth; /* bit depth of users row: write only */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte channels; /* number of channels in file */ +#ifdef PNG_WRITE_SUPPORTED + png_byte usr_channels; /* channels at start of write: write only */ +#endif + png_byte sig_bytes; /* magic bytes read/written from start of file */ + png_byte maximum_pixel_depth; + /* pixel depth used for the row buffers */ + png_byte transformed_pixel_depth; + /* pixel depth after read/write transforms */ +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) + png_uint_16 filler; /* filler bytes for pixel expansion */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + png_byte background_gamma_type; + png_fixed_point background_gamma; + png_color_16 background; /* background color in screen gamma space */ +#ifdef PNG_READ_GAMMA_SUPPORTED + png_color_16 background_1; /* background normalized to gamma 1.0 */ +#endif +#endif /* PNG_bKGD_SUPPORTED */ + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_flush_ptr output_flush_fn; /* Function for flushing output */ + png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ + png_uint_32 flush_rows; /* number of rows written since last flush */ +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */ + png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */ + + png_bytep gamma_table; /* gamma table for 8-bit depth files */ + png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_bytep gamma_from_1; /* converts from 1.0 to screen */ + png_bytep gamma_to_1; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) + png_color_8 sig_bit; /* significant bits in each available channel */ +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) + png_color_8 shift; /* shift for significant bit tranformation */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ + || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep trans_alpha; /* alpha values for paletted files */ + png_color_16 trans_color; /* transparent color for non-paletted files */ +#endif + + png_read_status_ptr read_row_fn; /* called after each row is decoded */ + png_write_status_ptr write_row_fn; /* called after each row is encoded */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_progressive_info_ptr info_fn; /* called after header data fully read */ + png_progressive_row_ptr row_fn; /* called after a prog. row is decoded */ + png_progressive_end_ptr end_fn; /* called after image is complete */ + png_bytep save_buffer_ptr; /* current location in save_buffer */ + png_bytep save_buffer; /* buffer for previously read data */ + png_bytep current_buffer_ptr; /* current location in current_buffer */ + png_bytep current_buffer; /* buffer for recently used data */ + png_uint_32 push_length; /* size of current input chunk */ + png_uint_32 skip_length; /* bytes to skip in input data */ + png_size_t save_buffer_size; /* amount of data now in save_buffer */ + png_size_t save_buffer_max; /* total size of save_buffer */ + png_size_t buffer_size; /* total amount of available input data */ + png_size_t current_buffer_size; /* amount of data now in current_buffer */ + int process_mode; /* what push library is currently doing */ + int cur_palette; /* current push library palette index */ + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* For the Borland special 64K segment handler */ + png_bytepp offset_table_ptr; + png_bytep offset_table; + png_uint_16 offset_table_number; + png_uint_16 offset_table_count; + png_uint_16 offset_table_count_free; +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + png_bytep palette_lookup; /* lookup table for quantizing */ + png_bytep quantize_index; /* index translation for palette files */ +#endif + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + png_byte heuristic_method; /* heuristic for row filter selection */ + png_byte num_prev_filters; /* number of weights for previous rows */ + png_bytep prev_filters; /* filter type(s) of previous row(s) */ + png_uint_16p filter_weights; /* weight(s) for previous line(s) */ + png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ + png_uint_16p filter_costs; /* relative filter calculation cost */ + png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ +#endif + + /* Options */ +#ifdef PNG_SET_OPTION_SUPPORTED + png_byte options; /* On/off state (up to 4 options) */ +#endif + +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng-1.7 */ +#ifdef PNG_TIME_RFC1123_SUPPORTED + char time_buffer[29]; /* String to hold RFC 1123 time text */ +#endif +#endif + +/* New members added in libpng-1.0.6 */ + + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + +#ifdef PNG_USER_CHUNKS_SUPPORTED + png_voidp user_chunk_ptr; +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ +#endif +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int unknown_default; /* As PNG_HANDLE_* */ + unsigned int num_chunk_list; /* Number of entries in the list */ + png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name + * followed by a PNG_HANDLE_* byte */ +#endif + +/* New members added in libpng-1.0.3 */ +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + png_byte rgb_to_gray_status; + /* Added in libpng 1.5.5 to record setting of coefficients: */ + png_byte rgb_to_gray_coefficients_set; + /* These were changed from png_byte in libpng-1.0.6 */ + png_uint_16 rgb_to_gray_red_coeff; + png_uint_16 rgb_to_gray_green_coeff; + /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */ +#endif + +/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) +/* Changed from png_byte to png_uint_32 at version 1.2.0 */ + png_uint_32 mng_features_permitted; +#endif + +/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_byte filter_type; +#endif + +/* New members added in libpng-1.2.0 */ + +/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ +#ifdef PNG_USER_MEM_SUPPORTED + png_voidp mem_ptr; /* user supplied struct for mem functions */ + png_malloc_ptr malloc_fn; /* function for allocating memory */ + png_free_ptr free_fn; /* function for freeing memory */ +#endif + +/* New member added in libpng-1.0.13 and 1.2.0 */ + png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* The following three members were added at version 1.0.14 and 1.2.4 */ + png_bytep quantize_sort; /* working sort array */ + png_bytep index_to_palette; /* where the original index currently is + in the palette */ + png_bytep palette_to_index; /* which original index points to this + palette color */ +#endif + +/* New members added in libpng-1.0.16 and 1.2.6 */ + png_byte compression_type; + +#ifdef PNG_USER_LIMITS_SUPPORTED + png_uint_32 user_width_max; + png_uint_32 user_height_max; + + /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown + * chunks that can be stored (0 means unlimited). + */ + png_uint_32 user_chunk_cache_max; + + /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk + * can occupy when decompressed. 0 means unlimited. + */ + png_alloc_size_t user_chunk_malloc_max; +#endif + +/* New member added in libpng-1.0.25 and 1.2.17 */ +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + /* Temporary storage for unknown chunk that the library doesn't recognize, + * used while reading the chunk. + */ + png_unknown_chunk unknown_chunk; +#endif + +/* New member added in libpng-1.2.26 */ + png_size_t old_big_row_buf_size; + +#ifdef PNG_READ_SUPPORTED +/* New member added in libpng-1.2.30 */ + png_bytep read_buffer; /* buffer for reading chunk data */ + png_alloc_size_t read_buffer_size; /* current size of the buffer */ +#endif +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED + uInt IDAT_read_size; /* limit on read buffer size for IDAT */ +#endif + +#ifdef PNG_IO_STATE_SUPPORTED +/* New member added in libpng-1.4.0 */ + png_uint_32 io_state; +#endif + +/* New member added in libpng-1.5.6 */ + png_bytep big_prev_row; + +/* New member added in libpng-1.5.7 */ + void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row); + +#ifdef PNG_READ_SUPPORTED +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + png_colorspace colorspace; +#endif +#endif +}; +#endif /* PNGSTRUCT_H */ diff --git a/core/src/fxcodec/fx_lpng/src/fx_png.c b/core/src/fxcodec/fx_lpng/src/fx_png.c new file mode 100644 index 0000000000..7b6582666f --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_png.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_png.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngerror.c b/core/src/fxcodec/fx_lpng/src/fx_pngerror.c new file mode 100644 index 0000000000..7581b99130 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngerror.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngerror.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngget.c b/core/src/fxcodec/fx_lpng/src/fx_pngget.c new file mode 100644 index 0000000000..cc8dc4e6b7 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngget.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngget.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngmem.c b/core/src/fxcodec/fx_lpng/src/fx_pngmem.c new file mode 100644 index 0000000000..9892408d70 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngmem.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngmem.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngpread.c b/core/src/fxcodec/fx_lpng/src/fx_pngpread.c new file mode 100644 index 0000000000..8d53be20a6 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngpread.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngpread.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngread.c b/core/src/fxcodec/fx_lpng/src/fx_pngread.c new file mode 100644 index 0000000000..c612bd533e --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngread.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngread.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngrio.c b/core/src/fxcodec/fx_lpng/src/fx_pngrio.c new file mode 100644 index 0000000000..d324a8e6e5 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngrio.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngrio.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngrtran.c b/core/src/fxcodec/fx_lpng/src/fx_pngrtran.c new file mode 100644 index 0000000000..bec380dc3c --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngrtran.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngrtran.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngrutil.c b/core/src/fxcodec/fx_lpng/src/fx_pngrutil.c new file mode 100644 index 0000000000..a3da3555e3 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngrutil.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngrutil.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngset.c b/core/src/fxcodec/fx_lpng/src/fx_pngset.c new file mode 100644 index 0000000000..76a72223f2 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngset.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngset.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngtrans.c b/core/src/fxcodec/fx_lpng/src/fx_pngtrans.c new file mode 100644 index 0000000000..eac49bf227 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngtrans.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngtrans.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngwio.c b/core/src/fxcodec/fx_lpng/src/fx_pngwio.c new file mode 100644 index 0000000000..3fb21e5b0b --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngwio.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngwio.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngwrite.c b/core/src/fxcodec/fx_lpng/src/fx_pngwrite.c new file mode 100644 index 0000000000..4434fd0cb4 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngwrite.c @@ -0,0 +1,10 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "../lpng_v163/fx_pngwrite.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngwtran.c b/core/src/fxcodec/fx_lpng/src/fx_pngwtran.c new file mode 100644 index 0000000000..8a095d3565 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngwtran.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngwtran.c" diff --git a/core/src/fxcodec/fx_lpng/src/fx_pngwutil.c b/core/src/fxcodec/fx_lpng/src/fx_pngwutil.c new file mode 100644 index 0000000000..b07fb40500 --- /dev/null +++ b/core/src/fxcodec/fx_lpng/src/fx_pngwutil.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../lpng_v163/fx_pngwutil.c" diff --git a/core/src/fxcodec/fx_tiff/include/fx_tiffiop.h b/core/src/fxcodec/fx_tiff/include/fx_tiffiop.h new file mode 100644 index 0000000000..8c78903025 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/include/fx_tiffiop.h @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tiffiop.h" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_aux.c b/core/src/fxcodec/fx_tiff/src/fx_tif_aux.c new file mode 100644 index 0000000000..55d4f650cf --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_aux.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_aux.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_close.c b/core/src/fxcodec/fx_tiff/src/fx_tif_close.c new file mode 100644 index 0000000000..3645bd29bd --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_close.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_close.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_codec.c b/core/src/fxcodec/fx_tiff/src/fx_tif_codec.c new file mode 100644 index 0000000000..183622f659 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_codec.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_codec.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_color.c b/core/src/fxcodec/fx_tiff/src/fx_tif_color.c new file mode 100644 index 0000000000..ce0f6fb252 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_color.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_color.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_compress.c b/core/src/fxcodec/fx_tiff/src/fx_tif_compress.c new file mode 100644 index 0000000000..cdbf26c71e --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_compress.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_compress.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_dir.c b/core/src/fxcodec/fx_tiff/src/fx_tif_dir.c new file mode 100644 index 0000000000..2dc94bb60f --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_dir.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_dir.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_dirinfo.c b/core/src/fxcodec/fx_tiff/src/fx_tif_dirinfo.c new file mode 100644 index 0000000000..5481733e46 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_dirinfo.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_dirinfo.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_dirread.c b/core/src/fxcodec/fx_tiff/src/fx_tif_dirread.c new file mode 100644 index 0000000000..ef57dfde21 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_dirread.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_dirread.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_dirwrite.c b/core/src/fxcodec/fx_tiff/src/fx_tif_dirwrite.c new file mode 100644 index 0000000000..daee77ba0e --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_dirwrite.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_dirwrite.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_dumpmode.c b/core/src/fxcodec/fx_tiff/src/fx_tif_dumpmode.c new file mode 100644 index 0000000000..1ece3b8322 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_dumpmode.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_dumpmode.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_error.c b/core/src/fxcodec/fx_tiff/src/fx_tif_error.c new file mode 100644 index 0000000000..8693e9d359 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_error.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_error.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_extension.c b/core/src/fxcodec/fx_tiff/src/fx_tif_extension.c new file mode 100644 index 0000000000..3b92492098 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_extension.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_extension.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_fax3.c b/core/src/fxcodec/fx_tiff/src/fx_tif_fax3.c new file mode 100644 index 0000000000..68d26de22d --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_fax3.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_fax3.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_fax3sm.c b/core/src/fxcodec/fx_tiff/src/fx_tif_fax3sm.c new file mode 100644 index 0000000000..aa633e7b7e --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_fax3sm.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_fax3sm.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_flush.c b/core/src/fxcodec/fx_tiff/src/fx_tif_flush.c new file mode 100644 index 0000000000..40884c8c37 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_flush.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_flush.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_getimage.c b/core/src/fxcodec/fx_tiff/src/fx_tif_getimage.c new file mode 100644 index 0000000000..15c8ee46fb --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_getimage.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_getimage.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_jpeg.c b/core/src/fxcodec/fx_tiff/src/fx_tif_jpeg.c new file mode 100644 index 0000000000..03ee51fc78 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_jpeg.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_jpeg.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_luv.c b/core/src/fxcodec/fx_tiff/src/fx_tif_luv.c new file mode 100644 index 0000000000..08768e795a --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_luv.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_luv.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_lzw.c b/core/src/fxcodec/fx_tiff/src/fx_tif_lzw.c new file mode 100644 index 0000000000..832311330b --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_lzw.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_lzw.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_next.c b/core/src/fxcodec/fx_tiff/src/fx_tif_next.c new file mode 100644 index 0000000000..a13df45480 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_next.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_next.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_ojpeg.c b/core/src/fxcodec/fx_tiff/src/fx_tif_ojpeg.c new file mode 100644 index 0000000000..fed1911053 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_ojpeg.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_ojpeg.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_open.c b/core/src/fxcodec/fx_tiff/src/fx_tif_open.c new file mode 100644 index 0000000000..682ffe614b --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_open.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_open.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_packbits.c b/core/src/fxcodec/fx_tiff/src/fx_tif_packbits.c new file mode 100644 index 0000000000..349930f7c5 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_packbits.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_packbits.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_pixarlog.c b/core/src/fxcodec/fx_tiff/src/fx_tif_pixarlog.c new file mode 100644 index 0000000000..2812901c84 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_pixarlog.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_pixarlog.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_predict.c b/core/src/fxcodec/fx_tiff/src/fx_tif_predict.c new file mode 100644 index 0000000000..eab405a93b --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_predict.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_predict.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_print.c b/core/src/fxcodec/fx_tiff/src/fx_tif_print.c new file mode 100644 index 0000000000..9a16a921fd --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_print.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_print.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_read.c b/core/src/fxcodec/fx_tiff/src/fx_tif_read.c new file mode 100644 index 0000000000..64289bbddf --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_read.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_read.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_strip.c b/core/src/fxcodec/fx_tiff/src/fx_tif_strip.c new file mode 100644 index 0000000000..e642a4e56f --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_strip.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_strip.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_swab.c b/core/src/fxcodec/fx_tiff/src/fx_tif_swab.c new file mode 100644 index 0000000000..e9c6b10793 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_swab.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_swab.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_thunder.c b/core/src/fxcodec/fx_tiff/src/fx_tif_thunder.c new file mode 100644 index 0000000000..80f523cd2b --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_thunder.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_thunder.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_tile.c b/core/src/fxcodec/fx_tiff/src/fx_tif_tile.c new file mode 100644 index 0000000000..49cd4048a4 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_tile.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_tile.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_version.c b/core/src/fxcodec/fx_tiff/src/fx_tif_version.c new file mode 100644 index 0000000000..6d62e3cd79 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_version.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_version.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_warning.c b/core/src/fxcodec/fx_tiff/src/fx_tif_warning.c new file mode 100644 index 0000000000..cb1921db8d --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_warning.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_warning.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_write.c b/core/src/fxcodec/fx_tiff/src/fx_tif_write.c new file mode 100644 index 0000000000..9ab43fa882 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_write.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_write.c" diff --git a/core/src/fxcodec/fx_tiff/src/fx_tif_zip.c b/core/src/fxcodec/fx_tiff/src/fx_tif_zip.c new file mode 100644 index 0000000000..8460a3fd5b --- /dev/null +++ b/core/src/fxcodec/fx_tiff/src/fx_tif_zip.c @@ -0,0 +1,7 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "../tiff_v403/tif_zip.c" diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/t4.h b/core/src/fxcodec/fx_tiff/tiff_v403/t4.h new file mode 100644 index 0000000000..b908f54f09 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/t4.h @@ -0,0 +1,292 @@ +/* $Id: t4.h,v 1.3 2010-03-10 18:56:48 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _T4_ +#define _T4_ +/* + * CCITT T.4 1D Huffman runlength codes and + * related definitions. Given the small sizes + * of these tables it does not seem + * worthwhile to make code & length 8 bits. + */ +typedef struct tableentry { + unsigned short length; /* bit length of g3 code */ + unsigned short code; /* g3 code */ + short runlen; /* run length in bits */ +} tableentry; + +#define EOL 0x001 /* EOL code value - 0000 0000 0000 1 */ + +/* status values returned instead of a run length */ +#define G3CODE_EOL -1 /* NB: ACT_EOL - ACT_WRUNT */ +#define G3CODE_INVALID -2 /* NB: ACT_INVALID - ACT_WRUNT */ +#define G3CODE_EOF -3 /* end of input data */ +#define G3CODE_INCOMP -4 /* incomplete run code */ + +/* + * Note that these tables are ordered such that the + * index into the table is known to be either the + * run length, or (run length / 64) + a fixed offset. + * + * NB: The G3CODE_INVALID entries are only used + * during state generation (see mkg3states.c). + */ +#ifdef G3CODES +const tableentry TIFFFaxWhiteCodes[] = { + { 8, 0x35, 0 }, /* 0011 0101 */ + { 6, 0x7, 1 }, /* 0001 11 */ + { 4, 0x7, 2 }, /* 0111 */ + { 4, 0x8, 3 }, /* 1000 */ + { 4, 0xB, 4 }, /* 1011 */ + { 4, 0xC, 5 }, /* 1100 */ + { 4, 0xE, 6 }, /* 1110 */ + { 4, 0xF, 7 }, /* 1111 */ + { 5, 0x13, 8 }, /* 1001 1 */ + { 5, 0x14, 9 }, /* 1010 0 */ + { 5, 0x7, 10 }, /* 0011 1 */ + { 5, 0x8, 11 }, /* 0100 0 */ + { 6, 0x8, 12 }, /* 0010 00 */ + { 6, 0x3, 13 }, /* 0000 11 */ + { 6, 0x34, 14 }, /* 1101 00 */ + { 6, 0x35, 15 }, /* 1101 01 */ + { 6, 0x2A, 16 }, /* 1010 10 */ + { 6, 0x2B, 17 }, /* 1010 11 */ + { 7, 0x27, 18 }, /* 0100 111 */ + { 7, 0xC, 19 }, /* 0001 100 */ + { 7, 0x8, 20 }, /* 0001 000 */ + { 7, 0x17, 21 }, /* 0010 111 */ + { 7, 0x3, 22 }, /* 0000 011 */ + { 7, 0x4, 23 }, /* 0000 100 */ + { 7, 0x28, 24 }, /* 0101 000 */ + { 7, 0x2B, 25 }, /* 0101 011 */ + { 7, 0x13, 26 }, /* 0010 011 */ + { 7, 0x24, 27 }, /* 0100 100 */ + { 7, 0x18, 28 }, /* 0011 000 */ + { 8, 0x2, 29 }, /* 0000 0010 */ + { 8, 0x3, 30 }, /* 0000 0011 */ + { 8, 0x1A, 31 }, /* 0001 1010 */ + { 8, 0x1B, 32 }, /* 0001 1011 */ + { 8, 0x12, 33 }, /* 0001 0010 */ + { 8, 0x13, 34 }, /* 0001 0011 */ + { 8, 0x14, 35 }, /* 0001 0100 */ + { 8, 0x15, 36 }, /* 0001 0101 */ + { 8, 0x16, 37 }, /* 0001 0110 */ + { 8, 0x17, 38 }, /* 0001 0111 */ + { 8, 0x28, 39 }, /* 0010 1000 */ + { 8, 0x29, 40 }, /* 0010 1001 */ + { 8, 0x2A, 41 }, /* 0010 1010 */ + { 8, 0x2B, 42 }, /* 0010 1011 */ + { 8, 0x2C, 43 }, /* 0010 1100 */ + { 8, 0x2D, 44 }, /* 0010 1101 */ + { 8, 0x4, 45 }, /* 0000 0100 */ + { 8, 0x5, 46 }, /* 0000 0101 */ + { 8, 0xA, 47 }, /* 0000 1010 */ + { 8, 0xB, 48 }, /* 0000 1011 */ + { 8, 0x52, 49 }, /* 0101 0010 */ + { 8, 0x53, 50 }, /* 0101 0011 */ + { 8, 0x54, 51 }, /* 0101 0100 */ + { 8, 0x55, 52 }, /* 0101 0101 */ + { 8, 0x24, 53 }, /* 0010 0100 */ + { 8, 0x25, 54 }, /* 0010 0101 */ + { 8, 0x58, 55 }, /* 0101 1000 */ + { 8, 0x59, 56 }, /* 0101 1001 */ + { 8, 0x5A, 57 }, /* 0101 1010 */ + { 8, 0x5B, 58 }, /* 0101 1011 */ + { 8, 0x4A, 59 }, /* 0100 1010 */ + { 8, 0x4B, 60 }, /* 0100 1011 */ + { 8, 0x32, 61 }, /* 0011 0010 */ + { 8, 0x33, 62 }, /* 0011 0011 */ + { 8, 0x34, 63 }, /* 0011 0100 */ + { 5, 0x1B, 64 }, /* 1101 1 */ + { 5, 0x12, 128 }, /* 1001 0 */ + { 6, 0x17, 192 }, /* 0101 11 */ + { 7, 0x37, 256 }, /* 0110 111 */ + { 8, 0x36, 320 }, /* 0011 0110 */ + { 8, 0x37, 384 }, /* 0011 0111 */ + { 8, 0x64, 448 }, /* 0110 0100 */ + { 8, 0x65, 512 }, /* 0110 0101 */ + { 8, 0x68, 576 }, /* 0110 1000 */ + { 8, 0x67, 640 }, /* 0110 0111 */ + { 9, 0xCC, 704 }, /* 0110 0110 0 */ + { 9, 0xCD, 768 }, /* 0110 0110 1 */ + { 9, 0xD2, 832 }, /* 0110 1001 0 */ + { 9, 0xD3, 896 }, /* 0110 1001 1 */ + { 9, 0xD4, 960 }, /* 0110 1010 0 */ + { 9, 0xD5, 1024 }, /* 0110 1010 1 */ + { 9, 0xD6, 1088 }, /* 0110 1011 0 */ + { 9, 0xD7, 1152 }, /* 0110 1011 1 */ + { 9, 0xD8, 1216 }, /* 0110 1100 0 */ + { 9, 0xD9, 1280 }, /* 0110 1100 1 */ + { 9, 0xDA, 1344 }, /* 0110 1101 0 */ + { 9, 0xDB, 1408 }, /* 0110 1101 1 */ + { 9, 0x98, 1472 }, /* 0100 1100 0 */ + { 9, 0x99, 1536 }, /* 0100 1100 1 */ + { 9, 0x9A, 1600 }, /* 0100 1101 0 */ + { 6, 0x18, 1664 }, /* 0110 00 */ + { 9, 0x9B, 1728 }, /* 0100 1101 1 */ + { 11, 0x8, 1792 }, /* 0000 0001 000 */ + { 11, 0xC, 1856 }, /* 0000 0001 100 */ + { 11, 0xD, 1920 }, /* 0000 0001 101 */ + { 12, 0x12, 1984 }, /* 0000 0001 0010 */ + { 12, 0x13, 2048 }, /* 0000 0001 0011 */ + { 12, 0x14, 2112 }, /* 0000 0001 0100 */ + { 12, 0x15, 2176 }, /* 0000 0001 0101 */ + { 12, 0x16, 2240 }, /* 0000 0001 0110 */ + { 12, 0x17, 2304 }, /* 0000 0001 0111 */ + { 12, 0x1C, 2368 }, /* 0000 0001 1100 */ + { 12, 0x1D, 2432 }, /* 0000 0001 1101 */ + { 12, 0x1E, 2496 }, /* 0000 0001 1110 */ + { 12, 0x1F, 2560 }, /* 0000 0001 1111 */ + { 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */ + { 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */ + { 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */ + { 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */ + { 12, 0x0, G3CODE_INVALID }, /* 0000 0000 0000 */ +}; + +const tableentry TIFFFaxBlackCodes[] = { + { 10, 0x37, 0 }, /* 0000 1101 11 */ + { 3, 0x2, 1 }, /* 010 */ + { 2, 0x3, 2 }, /* 11 */ + { 2, 0x2, 3 }, /* 10 */ + { 3, 0x3, 4 }, /* 011 */ + { 4, 0x3, 5 }, /* 0011 */ + { 4, 0x2, 6 }, /* 0010 */ + { 5, 0x3, 7 }, /* 0001 1 */ + { 6, 0x5, 8 }, /* 0001 01 */ + { 6, 0x4, 9 }, /* 0001 00 */ + { 7, 0x4, 10 }, /* 0000 100 */ + { 7, 0x5, 11 }, /* 0000 101 */ + { 7, 0x7, 12 }, /* 0000 111 */ + { 8, 0x4, 13 }, /* 0000 0100 */ + { 8, 0x7, 14 }, /* 0000 0111 */ + { 9, 0x18, 15 }, /* 0000 1100 0 */ + { 10, 0x17, 16 }, /* 0000 0101 11 */ + { 10, 0x18, 17 }, /* 0000 0110 00 */ + { 10, 0x8, 18 }, /* 0000 0010 00 */ + { 11, 0x67, 19 }, /* 0000 1100 111 */ + { 11, 0x68, 20 }, /* 0000 1101 000 */ + { 11, 0x6C, 21 }, /* 0000 1101 100 */ + { 11, 0x37, 22 }, /* 0000 0110 111 */ + { 11, 0x28, 23 }, /* 0000 0101 000 */ + { 11, 0x17, 24 }, /* 0000 0010 111 */ + { 11, 0x18, 25 }, /* 0000 0011 000 */ + { 12, 0xCA, 26 }, /* 0000 1100 1010 */ + { 12, 0xCB, 27 }, /* 0000 1100 1011 */ + { 12, 0xCC, 28 }, /* 0000 1100 1100 */ + { 12, 0xCD, 29 }, /* 0000 1100 1101 */ + { 12, 0x68, 30 }, /* 0000 0110 1000 */ + { 12, 0x69, 31 }, /* 0000 0110 1001 */ + { 12, 0x6A, 32 }, /* 0000 0110 1010 */ + { 12, 0x6B, 33 }, /* 0000 0110 1011 */ + { 12, 0xD2, 34 }, /* 0000 1101 0010 */ + { 12, 0xD3, 35 }, /* 0000 1101 0011 */ + { 12, 0xD4, 36 }, /* 0000 1101 0100 */ + { 12, 0xD5, 37 }, /* 0000 1101 0101 */ + { 12, 0xD6, 38 }, /* 0000 1101 0110 */ + { 12, 0xD7, 39 }, /* 0000 1101 0111 */ + { 12, 0x6C, 40 }, /* 0000 0110 1100 */ + { 12, 0x6D, 41 }, /* 0000 0110 1101 */ + { 12, 0xDA, 42 }, /* 0000 1101 1010 */ + { 12, 0xDB, 43 }, /* 0000 1101 1011 */ + { 12, 0x54, 44 }, /* 0000 0101 0100 */ + { 12, 0x55, 45 }, /* 0000 0101 0101 */ + { 12, 0x56, 46 }, /* 0000 0101 0110 */ + { 12, 0x57, 47 }, /* 0000 0101 0111 */ + { 12, 0x64, 48 }, /* 0000 0110 0100 */ + { 12, 0x65, 49 }, /* 0000 0110 0101 */ + { 12, 0x52, 50 }, /* 0000 0101 0010 */ + { 12, 0x53, 51 }, /* 0000 0101 0011 */ + { 12, 0x24, 52 }, /* 0000 0010 0100 */ + { 12, 0x37, 53 }, /* 0000 0011 0111 */ + { 12, 0x38, 54 }, /* 0000 0011 1000 */ + { 12, 0x27, 55 }, /* 0000 0010 0111 */ + { 12, 0x28, 56 }, /* 0000 0010 1000 */ + { 12, 0x58, 57 }, /* 0000 0101 1000 */ + { 12, 0x59, 58 }, /* 0000 0101 1001 */ + { 12, 0x2B, 59 }, /* 0000 0010 1011 */ + { 12, 0x2C, 60 }, /* 0000 0010 1100 */ + { 12, 0x5A, 61 }, /* 0000 0101 1010 */ + { 12, 0x66, 62 }, /* 0000 0110 0110 */ + { 12, 0x67, 63 }, /* 0000 0110 0111 */ + { 10, 0xF, 64 }, /* 0000 0011 11 */ + { 12, 0xC8, 128 }, /* 0000 1100 1000 */ + { 12, 0xC9, 192 }, /* 0000 1100 1001 */ + { 12, 0x5B, 256 }, /* 0000 0101 1011 */ + { 12, 0x33, 320 }, /* 0000 0011 0011 */ + { 12, 0x34, 384 }, /* 0000 0011 0100 */ + { 12, 0x35, 448 }, /* 0000 0011 0101 */ + { 13, 0x6C, 512 }, /* 0000 0011 0110 0 */ + { 13, 0x6D, 576 }, /* 0000 0011 0110 1 */ + { 13, 0x4A, 640 }, /* 0000 0010 0101 0 */ + { 13, 0x4B, 704 }, /* 0000 0010 0101 1 */ + { 13, 0x4C, 768 }, /* 0000 0010 0110 0 */ + { 13, 0x4D, 832 }, /* 0000 0010 0110 1 */ + { 13, 0x72, 896 }, /* 0000 0011 1001 0 */ + { 13, 0x73, 960 }, /* 0000 0011 1001 1 */ + { 13, 0x74, 1024 }, /* 0000 0011 1010 0 */ + { 13, 0x75, 1088 }, /* 0000 0011 1010 1 */ + { 13, 0x76, 1152 }, /* 0000 0011 1011 0 */ + { 13, 0x77, 1216 }, /* 0000 0011 1011 1 */ + { 13, 0x52, 1280 }, /* 0000 0010 1001 0 */ + { 13, 0x53, 1344 }, /* 0000 0010 1001 1 */ + { 13, 0x54, 1408 }, /* 0000 0010 1010 0 */ + { 13, 0x55, 1472 }, /* 0000 0010 1010 1 */ + { 13, 0x5A, 1536 }, /* 0000 0010 1101 0 */ + { 13, 0x5B, 1600 }, /* 0000 0010 1101 1 */ + { 13, 0x64, 1664 }, /* 0000 0011 0010 0 */ + { 13, 0x65, 1728 }, /* 0000 0011 0010 1 */ + { 11, 0x8, 1792 }, /* 0000 0001 000 */ + { 11, 0xC, 1856 }, /* 0000 0001 100 */ + { 11, 0xD, 1920 }, /* 0000 0001 101 */ + { 12, 0x12, 1984 }, /* 0000 0001 0010 */ + { 12, 0x13, 2048 }, /* 0000 0001 0011 */ + { 12, 0x14, 2112 }, /* 0000 0001 0100 */ + { 12, 0x15, 2176 }, /* 0000 0001 0101 */ + { 12, 0x16, 2240 }, /* 0000 0001 0110 */ + { 12, 0x17, 2304 }, /* 0000 0001 0111 */ + { 12, 0x1C, 2368 }, /* 0000 0001 1100 */ + { 12, 0x1D, 2432 }, /* 0000 0001 1101 */ + { 12, 0x1E, 2496 }, /* 0000 0001 1110 */ + { 12, 0x1F, 2560 }, /* 0000 0001 1111 */ + { 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */ + { 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */ + { 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */ + { 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */ + { 12, 0x0, G3CODE_INVALID }, /* 0000 0000 0000 */ +}; +#else +extern const tableentry TIFFFaxWhiteCodes[]; +extern const tableentry TIFFFaxBlackCodes[]; +#endif +#endif /* _T4_ */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_aux.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_aux.c new file mode 100644 index 0000000000..752e8d6ef4 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_aux.c @@ -0,0 +1,360 @@ +/* $Id: tif_aux.c,v 1.26 2010-07-01 15:33:28 dron Exp $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Auxiliary Support Routines. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#include "tif_predict.h" +#include + +uint32 +_TIFFMultiply32(TIFF* tif, uint32 first, uint32 second, const char* where) +{ + uint32 bytes = first * second; + + if (second && bytes / second != first) { + TIFFErrorExt(tif->tif_clientdata, where, "Integer overflow in %s", where); + bytes = 0; + } + + return bytes; +} + +uint64 +_TIFFMultiply64(TIFF* tif, uint64 first, uint64 second, const char* where) +{ + uint64 bytes = first * second; + + if (second && bytes / second != first) { + TIFFErrorExt(tif->tif_clientdata, where, "Integer overflow in %s", where); + bytes = 0; + } + + return bytes; +} + +void* +_TIFFCheckRealloc(TIFF* tif, void* buffer, + tmsize_t nmemb, tmsize_t elem_size, const char* what) +{ + void* cp = NULL; + tmsize_t bytes = nmemb * elem_size; + + /* + * XXX: Check for integer overflow. + */ + if (nmemb && elem_size && bytes / elem_size == nmemb) + cp = _TIFFrealloc(buffer, bytes); + + if (cp == NULL) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Failed to allocate memory for %s " + "(%ld elements of %ld bytes each)", + what,(long) nmemb, (long) elem_size); + } + + return cp; +} + +void* +_TIFFCheckMalloc(TIFF* tif, tmsize_t nmemb, tmsize_t elem_size, const char* what) +{ + return _TIFFCheckRealloc(tif, NULL, nmemb, elem_size, what); +} + +static int +TIFFDefaultTransferFunction(TIFFDirectory* td) +{ + uint16 **tf = td->td_transferfunction; + tmsize_t i, n, nbytes; + + tf[0] = tf[1] = tf[2] = 0; + if (td->td_bitspersample >= sizeof(tmsize_t) * 8 - 2) + return 0; + + n = ((tmsize_t)1)<td_bitspersample; + nbytes = n * sizeof (uint16); + if (!(tf[0] = (uint16 *)_TIFFmalloc(nbytes))) + return 0; + tf[0][0] = 0; + for (i = 1; i < n; i++) { + double t = (double)i/((double) n-1.); + tf[0][i] = (uint16)floor(65535.*pow(t, 2.2) + .5); + } + + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + if (!(tf[1] = (uint16 *)_TIFFmalloc(nbytes))) + goto bad; + _TIFFmemcpy(tf[1], tf[0], nbytes); + if (!(tf[2] = (uint16 *)_TIFFmalloc(nbytes))) + goto bad; + _TIFFmemcpy(tf[2], tf[0], nbytes); + } + return 1; + +bad: + if (tf[0]) + _TIFFfree(tf[0]); + if (tf[1]) + _TIFFfree(tf[1]); + if (tf[2]) + _TIFFfree(tf[2]); + tf[0] = tf[1] = tf[2] = 0; + return 0; +} + +static int +TIFFDefaultRefBlackWhite(TIFFDirectory* td) +{ + int i; + + if (!(td->td_refblackwhite = (float *)_TIFFmalloc(6*sizeof (float)))) + return 0; + if (td->td_photometric == PHOTOMETRIC_YCBCR) { + /* + * YCbCr (Class Y) images must have the ReferenceBlackWhite + * tag set. Fix the broken images, which lacks that tag. + */ + td->td_refblackwhite[0] = 0.0F; + td->td_refblackwhite[1] = td->td_refblackwhite[3] = + td->td_refblackwhite[5] = 255.0F; + td->td_refblackwhite[2] = td->td_refblackwhite[4] = 128.0F; + } else { + /* + * Assume RGB (Class R) + */ + for (i = 0; i < 3; i++) { + td->td_refblackwhite[2*i+0] = 0; + td->td_refblackwhite[2*i+1] = + (float)((1L<td_bitspersample)-1L); + } + } + return 1; +} + +/* + * Like TIFFGetField, but return any default + * value if the tag is not present in the directory. + * + * NB: We use the value in the directory, rather than + * explcit values so that defaults exist only one + * place in the library -- in TIFFDefaultDirectory. + */ +int +TIFFVGetFieldDefaulted(TIFF* tif, uint32 tag, va_list ap) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (TIFFVGetField(tif, tag, ap)) + return (1); + switch (tag) { + case TIFFTAG_SUBFILETYPE: + *va_arg(ap, uint32 *) = td->td_subfiletype; + return (1); + case TIFFTAG_BITSPERSAMPLE: + *va_arg(ap, uint16 *) = td->td_bitspersample; + return (1); + case TIFFTAG_THRESHHOLDING: + *va_arg(ap, uint16 *) = td->td_threshholding; + return (1); + case TIFFTAG_FILLORDER: + *va_arg(ap, uint16 *) = td->td_fillorder; + return (1); + case TIFFTAG_ORIENTATION: + *va_arg(ap, uint16 *) = td->td_orientation; + return (1); + case TIFFTAG_SAMPLESPERPIXEL: + *va_arg(ap, uint16 *) = td->td_samplesperpixel; + return (1); + case TIFFTAG_ROWSPERSTRIP: + *va_arg(ap, uint32 *) = td->td_rowsperstrip; + return (1); + case TIFFTAG_MINSAMPLEVALUE: + *va_arg(ap, uint16 *) = td->td_minsamplevalue; + return (1); + case TIFFTAG_MAXSAMPLEVALUE: + *va_arg(ap, uint16 *) = td->td_maxsamplevalue; + return (1); + case TIFFTAG_PLANARCONFIG: + *va_arg(ap, uint16 *) = td->td_planarconfig; + return (1); + case TIFFTAG_RESOLUTIONUNIT: + *va_arg(ap, uint16 *) = td->td_resolutionunit; + return (1); + case TIFFTAG_PREDICTOR: + { + TIFFPredictorState* sp = (TIFFPredictorState*) tif->tif_data; + *va_arg(ap, uint16*) = (uint16) sp->predictor; + return 1; + } + case TIFFTAG_DOTRANGE: + *va_arg(ap, uint16 *) = 0; + *va_arg(ap, uint16 *) = (1<td_bitspersample)-1; + return (1); + case TIFFTAG_INKSET: + *va_arg(ap, uint16 *) = INKSET_CMYK; + return 1; + case TIFFTAG_NUMBEROFINKS: + *va_arg(ap, uint16 *) = 4; + return (1); + case TIFFTAG_EXTRASAMPLES: + *va_arg(ap, uint16 *) = td->td_extrasamples; + *va_arg(ap, uint16 **) = td->td_sampleinfo; + return (1); + case TIFFTAG_MATTEING: + *va_arg(ap, uint16 *) = + (td->td_extrasamples == 1 && + td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA); + return (1); + case TIFFTAG_TILEDEPTH: + *va_arg(ap, uint32 *) = td->td_tiledepth; + return (1); + case TIFFTAG_DATATYPE: + *va_arg(ap, uint16 *) = td->td_sampleformat-1; + return (1); + case TIFFTAG_SAMPLEFORMAT: + *va_arg(ap, uint16 *) = td->td_sampleformat; + return(1); + case TIFFTAG_IMAGEDEPTH: + *va_arg(ap, uint32 *) = td->td_imagedepth; + return (1); + case TIFFTAG_YCBCRCOEFFICIENTS: + { + /* defaults are from CCIR Recommendation 601-1 */ + static float ycbcrcoeffs[] = { 0.299f, 0.587f, 0.114f }; + *va_arg(ap, float **) = ycbcrcoeffs; + return 1; + } + case TIFFTAG_YCBCRSUBSAMPLING: + *va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[0]; + *va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[1]; + return (1); + case TIFFTAG_YCBCRPOSITIONING: + *va_arg(ap, uint16 *) = td->td_ycbcrpositioning; + return (1); + case TIFFTAG_WHITEPOINT: + { + static float whitepoint[2]; + + /* TIFF 6.0 specification tells that it is no default + value for the WhitePoint, but AdobePhotoshop TIFF + Technical Note tells that it should be CIE D50. */ + whitepoint[0] = D50_X0 / (D50_X0 + D50_Y0 + D50_Z0); + whitepoint[1] = D50_Y0 / (D50_X0 + D50_Y0 + D50_Z0); + *va_arg(ap, float **) = whitepoint; + return 1; + } + case TIFFTAG_TRANSFERFUNCTION: + if (!td->td_transferfunction[0] && + !TIFFDefaultTransferFunction(td)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "No space for \"TransferFunction\" tag"); + return (0); + } + *va_arg(ap, uint16 **) = td->td_transferfunction[0]; + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + *va_arg(ap, uint16 **) = td->td_transferfunction[1]; + *va_arg(ap, uint16 **) = td->td_transferfunction[2]; + } + return (1); + case TIFFTAG_REFERENCEBLACKWHITE: + if (!td->td_refblackwhite && !TIFFDefaultRefBlackWhite(td)) + return (0); + *va_arg(ap, float **) = td->td_refblackwhite; + return (1); + } + return 0; +} + +/* + * Like TIFFGetField, but return any default + * value if the tag is not present in the directory. + */ +int +TIFFGetFieldDefaulted(TIFF* tif, uint32 tag, ...) +{ + int ok; + va_list ap; + + va_start(ap, tag); + ok = TIFFVGetFieldDefaulted(tif, tag, ap); + va_end(ap); + return (ok); +} + +struct _Int64Parts { + int32 low, high; +}; + +typedef union { + struct _Int64Parts part; + int64 value; +} _Int64; + +float +_TIFFUInt64ToFloat(uint64 ui64) +{ + _Int64 i; + + i.value = ui64; + if (i.part.high >= 0) { + return (float)i.value; + } else { + long double df; + df = (long double)i.value; + df += 18446744073709551616.0; /* adding 2**64 */ + return (float)df; + } +} + +double +_TIFFUInt64ToDouble(uint64 ui64) +{ + _Int64 i; + + i.value = ui64; + if (i.part.high >= 0) { + return (double)i.value; + } else { + long double df; + df = (long double)i.value; + df += 18446744073709551616.0; /* adding 2**64 */ + return (double)df; + } +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ + #endif diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_close.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_close.c new file mode 100644 index 0000000000..eebb30a41c --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_close.c @@ -0,0 +1,143 @@ +/* $Id: tif_close.c,v 1.19 2010-03-10 18:56:48 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#include + +/************************************************************************/ +/* TIFFCleanup() */ +/************************************************************************/ + +/** + * Auxiliary function to free the TIFF structure. Given structure will be + * completetly freed, so you should save opened file handle and pointer + * to the close procedure in external variables before calling + * _TIFFCleanup(), if you will need these ones to close the file. + * + * @param tif A TIFF pointer. + */ + +void +TIFFCleanup(TIFF* tif) +{ + /* + * Flush buffered data and directory (if dirty). + */ + if (tif->tif_mode != O_RDONLY) + TIFFFlush(tif); + (*tif->tif_cleanup)(tif); + TIFFFreeDirectory(tif); + + if (tif->tif_dirlist) + _TIFFfree(tif->tif_dirlist); + + /* + * Clean up client info links. + */ + while( tif->tif_clientinfo ) + { + TIFFClientInfoLink *link = tif->tif_clientinfo; + + tif->tif_clientinfo = link->next; + _TIFFfree( link->name ); + _TIFFfree( link ); + } + + if (tif->tif_rawdata && (tif->tif_flags&TIFF_MYBUFFER)) + _TIFFfree(tif->tif_rawdata); + if (isMapped(tif)) + TIFFUnmapFileContents(tif, tif->tif_base, (toff_t)tif->tif_size); + + /* + * Clean up custom fields. + */ + if (tif->tif_fields && tif->tif_nfields > 0) { + uint32 i; + + for (i = 0; i < tif->tif_nfields; i++) { + TIFFField *fld = tif->tif_fields[i]; + if (fld->field_bit == FIELD_CUSTOM && + strncmp("Tag ", fld->field_name, 4) == 0) { + _TIFFfree(fld->field_name); + _TIFFfree(fld); + } + } + + _TIFFfree(tif->tif_fields); + } + + if (tif->tif_nfieldscompat > 0) { + uint32 i; + + for (i = 0; i < tif->tif_nfieldscompat; i++) { + if (tif->tif_fieldscompat[i].allocated_size) + _TIFFfree(tif->tif_fieldscompat[i].fields); + } + _TIFFfree(tif->tif_fieldscompat); + } + + _TIFFfree(tif); +} + +/************************************************************************/ +/* TIFFClose() */ +/************************************************************************/ + +/** + * Close a previously opened TIFF file. + * + * TIFFClose closes a file that was previously opened with TIFFOpen(). + * Any buffered data are flushed to the file, including the contents of + * the current directory (if modified); and all resources are reclaimed. + * + * @param tif A TIFF pointer. + */ + +void +TIFFClose(TIFF* tif) +{ + TIFFCloseProc closeproc = tif->tif_closeproc; + thandle_t fd = tif->tif_clientdata; + + TIFFCleanup(tif); + (void) (*closeproc)(fd); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_codec.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_codec.c new file mode 100644 index 0000000000..16d237f79a --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_codec.c @@ -0,0 +1,168 @@ +/* $Id: tif_codec.c,v 1.15 2010-12-14 12:53:00 dron Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library + * + * Builtin Compression Scheme Configuration Support. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +static int NotConfigured(TIFF*, int); + +#ifndef LZW_SUPPORT +#define TIFFInitLZW NotConfigured +#endif +#ifndef PACKBITS_SUPPORT +#define TIFFInitPackBits NotConfigured +#endif +#ifndef THUNDER_SUPPORT +#define TIFFInitThunderScan NotConfigured +#endif +#ifndef NEXT_SUPPORT +#define TIFFInitNeXT NotConfigured +#endif +#ifndef JPEG_SUPPORT +#define TIFFInitJPEG NotConfigured +#endif +#ifndef OJPEG_SUPPORT +#define TIFFInitOJPEG NotConfigured +#endif +#ifndef CCITT_SUPPORT +#define TIFFInitCCITTRLE NotConfigured +#define TIFFInitCCITTRLEW NotConfigured +#define TIFFInitCCITTFax3 NotConfigured +#define TIFFInitCCITTFax4 NotConfigured +#endif +#ifndef JBIG_SUPPORT +#define TIFFInitJBIG NotConfigured +#endif +#ifndef ZIP_SUPPORT +#define TIFFInitZIP NotConfigured +#endif +#ifndef PIXARLOG_SUPPORT +#define TIFFInitPixarLog NotConfigured +#endif +#ifndef LOGLUV_SUPPORT +#define TIFFInitSGILog NotConfigured +#endif +#ifndef LZMA_SUPPORT +#define TIFFInitLZMA NotConfigured +#endif + +/* + * Compression schemes statically built into the library. + */ +#ifdef VMS +const TIFFCodec _TIFFBuiltinCODECS[] = { +#else +TIFFCodec _TIFFBuiltinCODECS[] = { +#endif + { "None", COMPRESSION_NONE, TIFFInitDumpMode }, + { "LZW", COMPRESSION_LZW, TIFFInitLZW }, + { "PackBits", COMPRESSION_PACKBITS, TIFFInitPackBits }, + { "ThunderScan", COMPRESSION_THUNDERSCAN,TIFFInitThunderScan }, + { "NeXT", COMPRESSION_NEXT, TIFFInitNeXT }, + { "JPEG", COMPRESSION_JPEG, TIFFInitJPEG }, + { "Old-style JPEG", COMPRESSION_OJPEG, TIFFInitOJPEG }, + { "CCITT RLE", COMPRESSION_CCITTRLE, TIFFInitCCITTRLE }, + { "CCITT RLE/W", COMPRESSION_CCITTRLEW, TIFFInitCCITTRLEW }, + { "CCITT Group 3", COMPRESSION_CCITTFAX3, TIFFInitCCITTFax3 }, + { "CCITT Group 4", COMPRESSION_CCITTFAX4, TIFFInitCCITTFax4 }, + { "ISO JBIG", COMPRESSION_JBIG, TIFFInitJBIG }, + { "Deflate", COMPRESSION_DEFLATE, TIFFInitZIP }, + { "AdobeDeflate", COMPRESSION_ADOBE_DEFLATE , TIFFInitZIP }, + { "PixarLog", COMPRESSION_PIXARLOG, TIFFInitPixarLog }, + { "SGILog", COMPRESSION_SGILOG, TIFFInitSGILog }, + { "SGILog24", COMPRESSION_SGILOG24, TIFFInitSGILog }, + { "LZMA", COMPRESSION_LZMA, TIFFInitLZMA }, + { NULL, 0, NULL } +}; + +static int +_notConfigured(TIFF* tif) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + char compression_code[20]; + + sprintf( compression_code, "%d", tif->tif_dir.td_compression ); + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%s compression support is not configured", + c ? c->name : compression_code ); + return (0); +} + +static int +NotConfigured(TIFF* tif, int scheme) +{ + (void) scheme; + + tif->tif_fixuptags = _notConfigured; + tif->tif_decodestatus = FALSE; + tif->tif_setupdecode = _notConfigured; + tif->tif_encodestatus = FALSE; + tif->tif_setupencode = _notConfigured; + return (1); +} + +/************************************************************************/ +/* TIFFIsCODECConfigured() */ +/************************************************************************/ + +/** + * Check whether we have working codec for the specific coding scheme. + * + * @return returns 1 if the codec is configured and working. Otherwise + * 0 will be returned. + */ + +int +TIFFIsCODECConfigured(uint16 scheme) +{ + const TIFFCodec* codec = TIFFFindCODEC(scheme); + + if(codec == NULL) { + return 0; + } + if(codec->init == NULL) { + return 0; + } + if(codec->init != NotConfigured){ + return 1; + } + return 0; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_color.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_color.c new file mode 100644 index 0000000000..71effbce92 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_color.c @@ -0,0 +1,289 @@ +/* $Id: tif_color.c,v 1.19 2010-12-14 02:22:42 faxguy Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * CIE L*a*b* to CIE XYZ and CIE XYZ to RGB conversion routines are taken + * from the VIPS library (http://www.vips.ecs.soton.ac.uk) with + * the permission of John Cupitt, the VIPS author. + */ + +/* + * TIFF Library. + * + * Color space conversion routines. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#include + +/* + * Convert color value from the CIE L*a*b* 1976 space to CIE XYZ. + */ +void +TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32 l, int32 a, int32 b, + float *X, float *Y, float *Z) +{ + float L = (float)l * 100.0F / 255.0F; + float cby, tmp; + + if( L < 8.856F ) { + *Y = (L * cielab->Y0) / 903.292F; + cby = 7.787F * (*Y / cielab->Y0) + 16.0F / 116.0F; + } else { + cby = (L + 16.0F) / 116.0F; + *Y = cielab->Y0 * cby * cby * cby; + } + + tmp = (float)a / 500.0F + cby; + if( tmp < 0.2069F ) + *X = cielab->X0 * (tmp - 0.13793F) / 7.787F; + else + *X = cielab->X0 * tmp * tmp * tmp; + + tmp = cby - (float)b / 200.0F; + if( tmp < 0.2069F ) + *Z = cielab->Z0 * (tmp - 0.13793F) / 7.787F; + else + *Z = cielab->Z0 * tmp * tmp * tmp; +} + +#define RINT(R) ((uint32)((R)>0?((R)+0.5):((R)-0.5))) +/* + * Convert color value from the XYZ space to RGB. + */ +void +TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z, + uint32 *r, uint32 *g, uint32 *b) +{ + int i; + float Yr, Yg, Yb; + float *matrix = &cielab->display.d_mat[0][0]; + + /* Multiply through the matrix to get luminosity values. */ + Yr = matrix[0] * X + matrix[1] * Y + matrix[2] * Z; + Yg = matrix[3] * X + matrix[4] * Y + matrix[5] * Z; + Yb = matrix[6] * X + matrix[7] * Y + matrix[8] * Z; + + /* Clip input */ + Yr = TIFFmax(Yr, cielab->display.d_Y0R); + Yg = TIFFmax(Yg, cielab->display.d_Y0G); + Yb = TIFFmax(Yb, cielab->display.d_Y0B); + + /* Avoid overflow in case of wrong input values */ + Yr = TIFFmin(Yr, cielab->display.d_YCR); + Yg = TIFFmin(Yg, cielab->display.d_YCG); + Yb = TIFFmin(Yb, cielab->display.d_YCB); + + /* Turn luminosity to colour value. */ + i = (int)((Yr - cielab->display.d_Y0R) / cielab->rstep); + i = TIFFmin(cielab->range, i); + *r = RINT(cielab->Yr2r[i]); + + i = (int)((Yg - cielab->display.d_Y0G) / cielab->gstep); + i = TIFFmin(cielab->range, i); + *g = RINT(cielab->Yg2g[i]); + + i = (int)((Yb - cielab->display.d_Y0B) / cielab->bstep); + i = TIFFmin(cielab->range, i); + *b = RINT(cielab->Yb2b[i]); + + /* Clip output. */ + *r = TIFFmin(*r, cielab->display.d_Vrwr); + *g = TIFFmin(*g, cielab->display.d_Vrwg); + *b = TIFFmin(*b, cielab->display.d_Vrwb); +} +#undef RINT + +/* + * Allocate conversion state structures and make look_up tables for + * the Yr,Yb,Yg <=> r,g,b conversions. + */ +int +TIFFCIELabToRGBInit(TIFFCIELabToRGB* cielab, + const TIFFDisplay *display, float *refWhite) +{ + int i; + double gamma; + + cielab->range = CIELABTORGB_TABLE_RANGE; + + _TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay)); + + /* Red */ + gamma = 1.0 / cielab->display.d_gammaR ; + cielab->rstep = + (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; + for(i = 0; i <= cielab->range; i++) { + cielab->Yr2r[i] = cielab->display.d_Vrwr + * ((float)pow((double)i / cielab->range, gamma)); + } + + /* Green */ + gamma = 1.0 / cielab->display.d_gammaG ; + cielab->gstep = + (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; + for(i = 0; i <= cielab->range; i++) { + cielab->Yg2g[i] = cielab->display.d_Vrwg + * ((float)pow((double)i / cielab->range, gamma)); + } + + /* Blue */ + gamma = 1.0 / cielab->display.d_gammaB ; + cielab->bstep = + (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; + for(i = 0; i <= cielab->range; i++) { + cielab->Yb2b[i] = cielab->display.d_Vrwb + * ((float)pow((double)i / cielab->range, gamma)); + } + + /* Init reference white point */ + cielab->X0 = refWhite[0]; + cielab->Y0 = refWhite[1]; + cielab->Z0 = refWhite[2]; + + return 0; +} + +/* + * Convert color value from the YCbCr space to CIE XYZ. + * The colorspace conversion algorithm comes from the IJG v5a code; + * see below for more information on how it works. + */ +#define SHIFT 16 +#define FIX(x) ((int32)((x) * (1L<(max)?(max):(f)) +#define HICLAMP(f,max) ((f)>(max)?(max):(f)) + +void +TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32 Y, int32 Cb, int32 Cr, + uint32 *r, uint32 *g, uint32 *b) +{ + int32 i; + + /* XXX: Only 8-bit YCbCr input supported for now */ + Y = HICLAMP(Y, 255), Cb = CLAMP(Cb, 0, 255), Cr = CLAMP(Cr, 0, 255); + + i = ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr]; + *r = CLAMP(i, 0, 255); + i = ycbcr->Y_tab[Y] + + (int)((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT); + *g = CLAMP(i, 0, 255); + i = ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb]; + *b = CLAMP(i, 0, 255); +} + +/* + * Initialize the YCbCr->RGB conversion tables. The conversion + * is done according to the 6.0 spec: + * + * R = Y + Cr*(2 - 2*LumaRed) + * B = Y + Cb*(2 - 2*LumaBlue) + * G = Y + * - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen + * - LumaRed*Cr*(2-2*LumaRed)/LumaGreen + * + * To avoid floating point arithmetic the fractional constants that + * come out of the equations are represented as fixed point values + * in the range 0...2^16. We also eliminate multiplications by + * pre-calculating possible values indexed by Cb and Cr (this code + * assumes conversion is being done for 8-bit samples). + */ +int +TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, float *luma, float *refBlackWhite) +{ + TIFFRGBValue* clamptab; + int i; + +#define LumaRed luma[0] +#define LumaGreen luma[1] +#define LumaBlue luma[2] + + clamptab = (TIFFRGBValue*)( + (uint8*) ycbcr+TIFFroundup_32(sizeof (TIFFYCbCrToRGB), sizeof (long))); + _TIFFmemset(clamptab, 0, 256); /* v < 0 => 0 */ + ycbcr->clamptab = (clamptab += 256); + for (i = 0; i < 256; i++) + clamptab[i] = (TIFFRGBValue) i; + _TIFFmemset(clamptab+256, 255, 2*256); /* v > 255 => 255 */ + ycbcr->Cr_r_tab = (int*) (clamptab + 3*256); + ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256; + ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256); + ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256; + ycbcr->Y_tab = ycbcr->Cb_g_tab + 256; + + { float f1 = 2-2*LumaRed; int32 D1 = FIX(f1); + float f2 = LumaRed*f1/LumaGreen; int32 D2 = -FIX(f2); + float f3 = 2-2*LumaBlue; int32 D3 = FIX(f3); + float f4 = LumaBlue*f3/LumaGreen; int32 D4 = -FIX(f4); + int x; + +#undef LumaBlue +#undef LumaGreen +#undef LumaRed + + /* + * i is the actual input pixel value in the range 0..255 + * Cb and Cr values are in the range -128..127 (actually + * they are in a range defined by the ReferenceBlackWhite + * tag) so there is some range shifting to do here when + * constructing tables indexed by the raw pixel data. + */ + for (i = 0, x = -128; i < 256; i++, x++) { + int32 Cr = (int32)Code2V(x, refBlackWhite[4] - 128.0F, + refBlackWhite[5] - 128.0F, 127); + int32 Cb = (int32)Code2V(x, refBlackWhite[2] - 128.0F, + refBlackWhite[3] - 128.0F, 127); + + ycbcr->Cr_r_tab[i] = (int32)((D1*Cr + ONE_HALF)>>SHIFT); + ycbcr->Cb_b_tab[i] = (int32)((D3*Cb + ONE_HALF)>>SHIFT); + ycbcr->Cr_g_tab[i] = D2*Cr; + ycbcr->Cb_g_tab[i] = D4*Cb + ONE_HALF; + ycbcr->Y_tab[i] = + (int32)Code2V(x + 128, refBlackWhite[0], refBlackWhite[1], 255); + } + } + + return 0; +} +#undef HICLAMP +#undef CLAMP +#undef Code2V +#undef SHIFT +#undef ONE_HALF +#undef FIX + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_compress.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_compress.c new file mode 100644 index 0000000000..5b2b4d5948 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_compress.c @@ -0,0 +1,307 @@ +/* $Id: tif_compress.c,v 1.22 2010-03-10 18:56:48 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library + * + * Compression Scheme Configuration Support. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +static int +TIFFNoEncode(TIFF* tif, const char* method) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + + if (c) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%s %s encoding is not implemented", + c->name, method); + } else { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Compression scheme %u %s encoding is not implemented", + tif->tif_dir.td_compression, method); + } + return (-1); +} + +int +_TIFFNoRowEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "scanline")); +} + +int +_TIFFNoStripEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "strip")); +} + +int +_TIFFNoTileEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "tile")); +} + +static int +TIFFNoDecode(TIFF* tif, const char* method) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + + if (c) + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%s %s decoding is not implemented", + c->name, method); + else + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Compression scheme %u %s decoding is not implemented", + tif->tif_dir.td_compression, method); + return (-1); +} + +int +_TIFFNoFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +int +_TIFFNoRowDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "scanline")); +} + +int +_TIFFNoStripDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "strip")); +} + +int +_TIFFNoTileDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "tile")); +} + +int +_TIFFNoSeek(TIFF* tif, uint32 off) +{ + (void) off; + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Compression algorithm does not support random access"); + return (0); +} + +int +_TIFFNoPreCode(TIFF* tif, uint16 s) +{ + (void) tif; (void) s; + return (1); +} + +static int _TIFFtrue(TIFF* tif) { (void) tif; return (1); } +static void _TIFFvoid(TIFF* tif) { (void) tif; } + +void +_TIFFSetDefaultCompressionState(TIFF* tif) +{ + tif->tif_fixuptags = _TIFFNoFixupTags; + tif->tif_decodestatus = TRUE; + tif->tif_setupdecode = _TIFFtrue; + tif->tif_predecode = _TIFFNoPreCode; + tif->tif_decoderow = _TIFFNoRowDecode; + tif->tif_decodestrip = _TIFFNoStripDecode; + tif->tif_decodetile = _TIFFNoTileDecode; + tif->tif_encodestatus = TRUE; + tif->tif_setupencode = _TIFFtrue; + tif->tif_preencode = _TIFFNoPreCode; + tif->tif_postencode = _TIFFtrue; + tif->tif_encoderow = _TIFFNoRowEncode; + tif->tif_encodestrip = _TIFFNoStripEncode; + tif->tif_encodetile = _TIFFNoTileEncode; + tif->tif_close = _TIFFvoid; + tif->tif_seek = _TIFFNoSeek; + tif->tif_cleanup = _TIFFvoid; + tif->tif_defstripsize = _TIFFDefaultStripSize; + tif->tif_deftilesize = _TIFFDefaultTileSize; + tif->tif_flags &= ~(TIFF_NOBITREV|TIFF_NOREADRAW); +} + +int +TIFFSetCompressionScheme(TIFF* tif, int scheme) +{ + const TIFFCodec *c = TIFFFindCODEC((uint16) scheme); + + _TIFFSetDefaultCompressionState(tif); + /* + * Don't treat an unknown compression scheme as an error. + * This permits applications to open files with data that + * the library does not have builtin support for, but which + * may still be meaningful. + */ + return (c ? (*c->init)(tif, scheme) : 1); +} + +/* + * Other compression schemes may be registered. Registered + * schemes can also override the builtin versions provided + * by this library. + */ +typedef struct _codec { + struct _codec* next; + TIFFCodec* info; +} codec_t; +static codec_t* registeredCODECS = NULL; + +const TIFFCodec* +TIFFFindCODEC(uint16 scheme) +{ + const TIFFCodec* c; + codec_t* cd; + + for (cd = registeredCODECS; cd; cd = cd->next) + if (cd->info->scheme == scheme) + return ((const TIFFCodec*) cd->info); + for (c = _TIFFBuiltinCODECS; c->name; c++) + if (c->scheme == scheme) + return (c); + return ((const TIFFCodec*) 0); +} + +TIFFCodec* +TIFFRegisterCODEC(uint16 scheme, const char* name, TIFFInitMethod init) +{ + codec_t* cd = (codec_t*) + _TIFFmalloc((tmsize_t)(sizeof (codec_t) + sizeof (TIFFCodec) + strlen(name)+1)); + + if (cd != NULL) { + cd->info = (TIFFCodec*) ((uint8*) cd + sizeof (codec_t)); + cd->info->name = (char*) + ((uint8*) cd->info + sizeof (TIFFCodec)); + strcpy(cd->info->name, name); + cd->info->scheme = scheme; + cd->info->init = init; + cd->next = registeredCODECS; + registeredCODECS = cd; + } else { + TIFFErrorExt(0, "TIFFRegisterCODEC", + "No space to register compression scheme %s", name); + return NULL; + } + return (cd->info); +} + +void +TIFFUnRegisterCODEC(TIFFCodec* c) +{ + codec_t* cd; + codec_t** pcd; + + for (pcd = ®isteredCODECS; (cd = *pcd); pcd = &cd->next) + if (cd->info == c) { + *pcd = cd->next; + _TIFFfree(cd); + return; + } + TIFFErrorExt(0, "TIFFUnRegisterCODEC", + "Cannot remove compression scheme %s; not registered", c->name); +} + +/************************************************************************/ +/* TIFFGetConfisuredCODECs() */ +/************************************************************************/ + +/** + * Get list of configured codecs, both built-in and registered by user. + * Caller is responsible to free this structure. + * + * @return returns array of TIFFCodec records (the last record should be NULL) + * or NULL if function failed. + */ + +TIFFCodec* +TIFFGetConfiguredCODECs() +{ + int i = 1; + codec_t *cd; + const TIFFCodec* c; + TIFFCodec* codecs = NULL; + TIFFCodec* new_codecs; + + for (cd = registeredCODECS; cd; cd = cd->next) { + new_codecs = (TIFFCodec *) + _TIFFrealloc(codecs, i * sizeof(TIFFCodec)); + if (!new_codecs) { + _TIFFfree (codecs); + return NULL; + } + codecs = new_codecs; + _TIFFmemcpy(codecs + i - 1, cd, sizeof(TIFFCodec)); + i++; + } + for (c = _TIFFBuiltinCODECS; c->name; c++) { + if (TIFFIsCODECConfigured(c->scheme)) { + new_codecs = (TIFFCodec *) + _TIFFrealloc(codecs, i * sizeof(TIFFCodec)); + if (!new_codecs) { + _TIFFfree (codecs); + return NULL; + } + codecs = new_codecs; + _TIFFmemcpy(codecs + i - 1, (const void*)c, sizeof(TIFFCodec)); + i++; + } + } + + new_codecs = (TIFFCodec *) _TIFFrealloc(codecs, i * sizeof(TIFFCodec)); + if (!new_codecs) { + _TIFFfree (codecs); + return NULL; + } + codecs = new_codecs; + _TIFFmemset(codecs + i - 1, 0, sizeof(TIFFCodec)); + + return codecs; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.c new file mode 100644 index 0000000000..076d9b4ea0 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.c @@ -0,0 +1,1662 @@ +/* $Id: tif_dir.c,v 1.113 2012-06-14 20:32:53 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Tag Get & Set Routines. + * (and also some miscellaneous stuff) + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +/* + * These are used in the backwards compatibility code... + */ +#define DATATYPE_VOID 0 /* !untyped data */ +#define DATATYPE_INT 1 /* !signed integer data */ +#define DATATYPE_UINT 2 /* !unsigned integer data */ +#define DATATYPE_IEEEFP 3 /* !IEEE floating point data */ + +static void +setByteArray(void** vpp, void* vp, size_t nmemb, size_t elem_size) +{ + if (*vpp) + _TIFFfree(*vpp), *vpp = 0; + if (vp) { + tmsize_t bytes = (tmsize_t)(nmemb * elem_size); + if (elem_size && bytes / elem_size == nmemb) + *vpp = (void*) _TIFFmalloc(bytes); + if (*vpp) + _TIFFmemcpy(*vpp, vp, bytes); + } +} +void _TIFFsetByteArray(void** vpp, void* vp, uint32 n) + { setByteArray(vpp, vp, n, 1); } +void _TIFFsetString(char** cpp, char* cp) + { setByteArray((void**) cpp, (void*) cp, strlen(cp)+1, 1); } +void _TIFFsetNString(char** cpp, char* cp, uint32 n) + { setByteArray((void**) cpp, (void*) cp, n, 1); } +void _TIFFsetShortArray(uint16** wpp, uint16* wp, uint32 n) + { setByteArray((void**) wpp, (void*) wp, n, sizeof (uint16)); } +void _TIFFsetLongArray(uint32** lpp, uint32* lp, uint32 n) + { setByteArray((void**) lpp, (void*) lp, n, sizeof (uint32)); } +void _TIFFsetLong8Array(uint64** lpp, uint64* lp, uint32 n) + { setByteArray((void**) lpp, (void*) lp, n, sizeof (uint64)); } +void _TIFFsetFloatArray(float** fpp, float* fp, uint32 n) + { setByteArray((void**) fpp, (void*) fp, n, sizeof (float)); } +void _TIFFsetDoubleArray(double** dpp, double* dp, uint32 n) + { setByteArray((void**) dpp, (void*) dp, n, sizeof (double)); } + +static void +setDoubleArrayOneValue(double** vpp, double value, size_t nmemb) +{ + if (*vpp) + _TIFFfree(*vpp); + *vpp = _TIFFmalloc(nmemb*sizeof(double)); + if (*vpp) + { + while (nmemb--) + ((double*)*vpp)[nmemb] = value; + } +} + +/* + * Install extra samples information. + */ +static int +setExtraSamples(TIFFDirectory* td, va_list ap, uint32* v) +{ +/* XXX: Unassociated alpha data == 999 is a known Corel Draw bug, see below */ +#define EXTRASAMPLE_COREL_UNASSALPHA 999 + + uint16* va; + uint32 i; + + *v = (uint16) va_arg(ap, uint16_vap); + if ((uint16) *v > td->td_samplesperpixel) + return 0; + va = va_arg(ap, uint16*); + if (*v > 0 && va == NULL) /* typically missing param */ + return 0; + for (i = 0; i < *v; i++) { + if (va[i] > EXTRASAMPLE_UNASSALPHA) { + /* + * XXX: Corel Draw is known to produce incorrect + * ExtraSamples tags which must be patched here if we + * want to be able to open some of the damaged TIFF + * files: + */ + if (va[i] == EXTRASAMPLE_COREL_UNASSALPHA) + va[i] = EXTRASAMPLE_UNASSALPHA; + else + return 0; + } + } + td->td_extrasamples = (uint16) *v; + _TIFFsetShortArray(&td->td_sampleinfo, va, td->td_extrasamples); + return 1; + +#undef EXTRASAMPLE_COREL_UNASSALPHA +} + +/* + * Confirm we have "samplesperpixel" ink names separated by \0. Returns + * zero if the ink names are not as expected. + */ +static uint32 +checkInkNamesString(TIFF* tif, uint32 slen, const char* s) +{ + TIFFDirectory* td = &tif->tif_dir; + uint16 i = td->td_samplesperpixel; + + if (slen > 0) { + const char* ep = s+slen; + const char* cp = s; + for (; i > 0; i--) { + for (; cp < ep && *cp != '\0'; cp++) {} + if (cp >= ep) + goto bad; + cp++; /* skip \0 */ + } + return ((uint32)(cp-s)); + } +bad: + TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", + "%s: Invalid InkNames value; expecting %d names, found %d", + tif->tif_name, + td->td_samplesperpixel, + td->td_samplesperpixel-i); + return (0); +} + +static int +_TIFFVSetField(TIFF* tif, uint32 tag, va_list ap) +{ + static const char module[] = "_TIFFVSetField"; + + TIFFDirectory* td = &tif->tif_dir; + int status = 1; + uint32 v32, i, v; + char* s; + const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY); + uint32 standard_tag = tag; + + /* + * We want to force the custom code to be used for custom + * fields even if the tag happens to match a well known + * one - important for reinterpreted handling of standard + * tag values in custom directories (ie. EXIF) + */ + if (fip->field_bit == FIELD_CUSTOM) { + standard_tag = 0; + } + + switch (standard_tag) { + case TIFFTAG_SUBFILETYPE: + td->td_subfiletype = (uint32) va_arg(ap, uint32); + break; + case TIFFTAG_IMAGEWIDTH: + td->td_imagewidth = (uint32) va_arg(ap, uint32); + break; + case TIFFTAG_IMAGELENGTH: + td->td_imagelength = (uint32) va_arg(ap, uint32); + break; + case TIFFTAG_BITSPERSAMPLE: + td->td_bitspersample = (uint16) va_arg(ap, uint16_vap); + /* + * If the data require post-decoding processing to byte-swap + * samples, set it up here. Note that since tags are required + * to be ordered, compression code can override this behaviour + * in the setup method if it wants to roll the post decoding + * work in with its normal work. + */ + if (tif->tif_flags & TIFF_SWAB) { + if (td->td_bitspersample == 8) + tif->tif_postdecode = _TIFFNoPostDecode; + else if (td->td_bitspersample == 16) + tif->tif_postdecode = _TIFFSwab16BitData; + else if (td->td_bitspersample == 24) + tif->tif_postdecode = _TIFFSwab24BitData; + else if (td->td_bitspersample == 32) + tif->tif_postdecode = _TIFFSwab32BitData; + else if (td->td_bitspersample == 64) + tif->tif_postdecode = _TIFFSwab64BitData; + else if (td->td_bitspersample == 128) /* two 64's */ + tif->tif_postdecode = _TIFFSwab64BitData; + } + break; + case TIFFTAG_COMPRESSION: + v = (uint16) va_arg(ap, uint16_vap); + /* + * If we're changing the compression scheme, the notify the + * previous module so that it can cleanup any state it's + * setup. + */ + if (TIFFFieldSet(tif, FIELD_COMPRESSION)) { + if ((uint32)td->td_compression == v) + break; + (*tif->tif_cleanup)(tif); + tif->tif_flags &= ~TIFF_CODERSETUP; + } + /* + * Setup new compression routine state. + */ + if( (status = TIFFSetCompressionScheme(tif, v)) != 0 ) + td->td_compression = (uint16) v; + else + status = 0; + break; + case TIFFTAG_PHOTOMETRIC: + td->td_photometric = (uint16) va_arg(ap, uint16_vap); + break; + case TIFFTAG_THRESHHOLDING: + td->td_threshholding = (uint16) va_arg(ap, uint16_vap); + break; + case TIFFTAG_FILLORDER: + v = (uint16) va_arg(ap, uint16_vap); + if (v != FILLORDER_LSB2MSB && v != FILLORDER_MSB2LSB) + goto badvalue; + td->td_fillorder = (uint16) v; + break; + case TIFFTAG_ORIENTATION: + v = (uint16) va_arg(ap, uint16_vap); + if (v < ORIENTATION_TOPLEFT || ORIENTATION_LEFTBOT < v) + goto badvalue; + else + td->td_orientation = (uint16) v; + break; + case TIFFTAG_SAMPLESPERPIXEL: + v = (uint16) va_arg(ap, uint16_vap); + if (v == 0) + goto badvalue; + td->td_samplesperpixel = (uint16) v; + break; + case TIFFTAG_ROWSPERSTRIP: + v32 = (uint32) va_arg(ap, uint32); + if (v32 == 0) + goto badvalue32; + td->td_rowsperstrip = v32; + if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { + td->td_tilelength = v32; + td->td_tilewidth = td->td_imagewidth; + } + break; + case TIFFTAG_MINSAMPLEVALUE: + td->td_minsamplevalue = (uint16) va_arg(ap, uint16_vap); + break; + case TIFFTAG_MAXSAMPLEVALUE: + td->td_maxsamplevalue = (uint16) va_arg(ap, uint16_vap); + break; + case TIFFTAG_SMINSAMPLEVALUE: + if (tif->tif_flags & TIFF_PERSAMPLE) + _TIFFsetDoubleArray(&td->td_sminsamplevalue, va_arg(ap, double*), td->td_samplesperpixel); + else + setDoubleArrayOneValue(&td->td_sminsamplevalue, va_arg(ap, double), td->td_samplesperpixel); + break; + case TIFFTAG_SMAXSAMPLEVALUE: + if (tif->tif_flags & TIFF_PERSAMPLE) + _TIFFsetDoubleArray(&td->td_smaxsamplevalue, va_arg(ap, double*), td->td_samplesperpixel); + else + setDoubleArrayOneValue(&td->td_smaxsamplevalue, va_arg(ap, double), td->td_samplesperpixel); + break; + case TIFFTAG_XRESOLUTION: + td->td_xresolution = (float) va_arg(ap, double); + break; + case TIFFTAG_YRESOLUTION: + td->td_yresolution = (float) va_arg(ap, double); + break; + case TIFFTAG_PLANARCONFIG: + v = (uint16) va_arg(ap, uint16_vap); + if (v != PLANARCONFIG_CONTIG && v != PLANARCONFIG_SEPARATE) + goto badvalue; + td->td_planarconfig = (uint16) v; + break; + case TIFFTAG_XPOSITION: + td->td_xposition = (float) va_arg(ap, double); + break; + case TIFFTAG_YPOSITION: + td->td_yposition = (float) va_arg(ap, double); + break; + case TIFFTAG_RESOLUTIONUNIT: + v = (uint16) va_arg(ap, uint16_vap); + if (v < RESUNIT_NONE || RESUNIT_CENTIMETER < v) + goto badvalue; + td->td_resolutionunit = (uint16) v; + break; + case TIFFTAG_PAGENUMBER: + td->td_pagenumber[0] = (uint16) va_arg(ap, uint16_vap); + td->td_pagenumber[1] = (uint16) va_arg(ap, uint16_vap); + break; + case TIFFTAG_HALFTONEHINTS: + td->td_halftonehints[0] = (uint16) va_arg(ap, uint16_vap); + td->td_halftonehints[1] = (uint16) va_arg(ap, uint16_vap); + break; + case TIFFTAG_COLORMAP: + v32 = (uint32)(1L<td_bitspersample); + _TIFFsetShortArray(&td->td_colormap[0], va_arg(ap, uint16*), v32); + _TIFFsetShortArray(&td->td_colormap[1], va_arg(ap, uint16*), v32); + _TIFFsetShortArray(&td->td_colormap[2], va_arg(ap, uint16*), v32); + break; + case TIFFTAG_EXTRASAMPLES: + if (!setExtraSamples(td, ap, &v)) + goto badvalue; + break; + case TIFFTAG_MATTEING: + td->td_extrasamples = (((uint16) va_arg(ap, uint16_vap)) != 0); + if (td->td_extrasamples) { + uint16 sv = EXTRASAMPLE_ASSOCALPHA; + _TIFFsetShortArray(&td->td_sampleinfo, &sv, 1); + } + break; + case TIFFTAG_TILEWIDTH: + v32 = (uint32) va_arg(ap, uint32); + if (v32 % 16) { + if (tif->tif_mode != O_RDONLY) + goto badvalue32; + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "Nonstandard tile width %d, convert file", v32); + } + td->td_tilewidth = v32; + tif->tif_flags |= TIFF_ISTILED; + break; + case TIFFTAG_TILELENGTH: + v32 = (uint32) va_arg(ap, uint32); + if (v32 % 16) { + if (tif->tif_mode != O_RDONLY) + goto badvalue32; + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "Nonstandard tile length %d, convert file", v32); + } + td->td_tilelength = v32; + tif->tif_flags |= TIFF_ISTILED; + break; + case TIFFTAG_TILEDEPTH: + v32 = (uint32) va_arg(ap, uint32); + if (v32 == 0) + goto badvalue32; + td->td_tiledepth = v32; + break; + case TIFFTAG_DATATYPE: + v = (uint16) va_arg(ap, uint16_vap); + switch (v) { + case DATATYPE_VOID: v = SAMPLEFORMAT_VOID; break; + case DATATYPE_INT: v = SAMPLEFORMAT_INT; break; + case DATATYPE_UINT: v = SAMPLEFORMAT_UINT; break; + case DATATYPE_IEEEFP: v = SAMPLEFORMAT_IEEEFP;break; + default: goto badvalue; + } + td->td_sampleformat = (uint16) v; + break; + case TIFFTAG_SAMPLEFORMAT: + v = (uint16) va_arg(ap, uint16_vap); + if (v < SAMPLEFORMAT_UINT || SAMPLEFORMAT_COMPLEXIEEEFP < v) + goto badvalue; + td->td_sampleformat = (uint16) v; + + /* Try to fix up the SWAB function for complex data. */ + if( td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT + && td->td_bitspersample == 32 + && tif->tif_postdecode == _TIFFSwab32BitData ) + tif->tif_postdecode = _TIFFSwab16BitData; + else if( (td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT + || td->td_sampleformat == SAMPLEFORMAT_COMPLEXIEEEFP) + && td->td_bitspersample == 64 + && tif->tif_postdecode == _TIFFSwab64BitData ) + tif->tif_postdecode = _TIFFSwab32BitData; + break; + case TIFFTAG_IMAGEDEPTH: + td->td_imagedepth = (uint32) va_arg(ap, uint32); + break; + case TIFFTAG_SUBIFD: + if ((tif->tif_flags & TIFF_INSUBIFD) == 0) { + td->td_nsubifd = (uint16) va_arg(ap, uint16_vap); + _TIFFsetLong8Array(&td->td_subifd, (uint64*) va_arg(ap, uint64*), + (long) td->td_nsubifd); + } else { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Sorry, cannot nest SubIFDs", + tif->tif_name); + status = 0; + } + break; + case TIFFTAG_YCBCRPOSITIONING: + td->td_ycbcrpositioning = (uint16) va_arg(ap, uint16_vap); + break; + case TIFFTAG_YCBCRSUBSAMPLING: + td->td_ycbcrsubsampling[0] = (uint16) va_arg(ap, uint16_vap); + td->td_ycbcrsubsampling[1] = (uint16) va_arg(ap, uint16_vap); + break; + case TIFFTAG_TRANSFERFUNCTION: + v = (td->td_samplesperpixel - td->td_extrasamples) > 1 ? 3 : 1; + for (i = 0; i < v; i++) + _TIFFsetShortArray(&td->td_transferfunction[i], + va_arg(ap, uint16*), 1L<td_bitspersample); + break; + case TIFFTAG_REFERENCEBLACKWHITE: + /* XXX should check for null range */ + _TIFFsetFloatArray(&td->td_refblackwhite, va_arg(ap, float*), 6); + break; + case TIFFTAG_INKNAMES: + v = (uint16) va_arg(ap, uint16_vap); + s = va_arg(ap, char*); + v = checkInkNamesString(tif, v, s); + status = v > 0; + if( v > 0 ) { + _TIFFsetNString(&td->td_inknames, s, v); + td->td_inknameslen = v; + } + break; + case TIFFTAG_PERSAMPLE: + v = (uint16) va_arg(ap, uint16_vap); + if( v == PERSAMPLE_MULTI ) + tif->tif_flags |= TIFF_PERSAMPLE; + else + tif->tif_flags &= ~TIFF_PERSAMPLE; + break; + default: { + TIFFTagValue *tv; + int tv_size, iCustom; + + /* + * This can happen if multiple images are open with different + * codecs which have private tags. The global tag information + * table may then have tags that are valid for one file but not + * the other. If the client tries to set a tag that is not valid + * for the image's codec then we'll arrive here. This + * happens, for example, when tiffcp is used to convert between + * compression schemes and codec-specific tags are blindly copied. + */ + if(fip == NULL || fip->field_bit != FIELD_CUSTOM) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Invalid %stag \"%s\" (not supported by codec)", + tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", + fip ? fip->field_name : "Unknown"); + status = 0; + break; + } + + /* + * Find the existing entry for this custom value. + */ + tv = NULL; + for (iCustom = 0; iCustom < td->td_customValueCount; iCustom++) { + if (td->td_customValues[iCustom].info->field_tag == tag) { + tv = td->td_customValues + iCustom; + if (tv->value != NULL) { + _TIFFfree(tv->value); + tv->value = NULL; + } + break; + } + } + + /* + * Grow the custom list if the entry was not found. + */ + if(tv == NULL) { + TIFFTagValue *new_customValues; + + td->td_customValueCount++; + new_customValues = (TIFFTagValue *) + _TIFFrealloc(td->td_customValues, + sizeof(TIFFTagValue) * td->td_customValueCount); + if (!new_customValues) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Failed to allocate space for list of custom values", + tif->tif_name); + status = 0; + goto end; + } + + td->td_customValues = new_customValues; + + tv = td->td_customValues + (td->td_customValueCount - 1); + tv->info = fip; + tv->value = NULL; + tv->count = 0; + } + + /* + * Set custom value ... save a copy of the custom tag value. + */ + tv_size = _TIFFDataSize(fip->field_type); + if (tv_size == 0) { + status = 0; + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Bad field type %d for \"%s\"", + tif->tif_name, fip->field_type, + fip->field_name); + goto end; + } + + if (fip->field_type == TIFF_ASCII) + { + uint32 ma; + char* mb; + if (fip->field_passcount) + { + assert(fip->field_writecount==TIFF_VARIABLE2); + ma=(uint32)va_arg(ap,uint32); + mb=(char*)va_arg(ap,char*); + } + else + { + mb=(char*)va_arg(ap,char*); + ma=(uint32)(strlen(mb)+1); + } + tv->count=ma; + setByteArray(&tv->value,mb,ma,1); + } + else + { + if (fip->field_passcount) { + if (fip->field_writecount == TIFF_VARIABLE2) + tv->count = (uint32) va_arg(ap, uint32); + else + tv->count = (int) va_arg(ap, int); + } else if (fip->field_writecount == TIFF_VARIABLE + || fip->field_writecount == TIFF_VARIABLE2) + tv->count = 1; + else if (fip->field_writecount == TIFF_SPP) + tv->count = td->td_samplesperpixel; + else + tv->count = fip->field_writecount; + + if (tv->count == 0) { + status = 0; + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Null count for \"%s\" (type " + "%d, writecount %d, passcount %d)", + tif->tif_name, + fip->field_name, + fip->field_type, + fip->field_writecount, + fip->field_passcount); + goto end; + } + + tv->value = _TIFFCheckMalloc(tif, tv->count, tv_size, + "custom tag binary object"); + if (!tv->value) { + status = 0; + goto end; + } + + if (fip->field_tag == TIFFTAG_DOTRANGE + && strcmp(fip->field_name,"DotRange") == 0) { + /* TODO: This is an evil exception and should not have been + handled this way ... likely best if we move it into + the directory structure with an explicit field in + libtiff 4.1 and assign it a FIELD_ value */ + uint16 v[2]; + v[0] = (uint16)va_arg(ap, int); + v[1] = (uint16)va_arg(ap, int); + _TIFFmemcpy(tv->value, &v, 4); + } + + else if (fip->field_passcount + || fip->field_writecount == TIFF_VARIABLE + || fip->field_writecount == TIFF_VARIABLE2 + || fip->field_writecount == TIFF_SPP + || tv->count > 1) { + _TIFFmemcpy(tv->value, va_arg(ap, void *), + tv->count * tv_size); + } else { + char *val = (char *)tv->value; + assert( tv->count == 1 ); + + switch (fip->field_type) { + case TIFF_BYTE: + case TIFF_UNDEFINED: + { + uint8 v = (uint8)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SBYTE: + { + int8 v = (int8)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SHORT: + { + uint16 v = (uint16)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SSHORT: + { + int16 v = (int16)va_arg(ap, int); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_LONG: + case TIFF_IFD: + { + uint32 v = va_arg(ap, uint32); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SLONG: + { + int32 v = va_arg(ap, int32); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_LONG8: + case TIFF_IFD8: + { + uint64 v = va_arg(ap, uint64); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_SLONG8: + { + int64 v = va_arg(ap, int64); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + { + float v = (float)va_arg(ap, double); + _TIFFmemcpy(val, &v, tv_size); + } + break; + case TIFF_DOUBLE: + { + double v = va_arg(ap, double); + _TIFFmemcpy(val, &v, tv_size); + } + break; + default: + _TIFFmemset(val, 0, tv_size); + status = 0; + break; + } + } + } + } + } + if (status) { + const TIFFField* fip=TIFFFieldWithTag(tif,tag); + if (fip) + TIFFSetFieldBit(tif, fip->field_bit); + tif->tif_flags |= TIFF_DIRTYDIRECT; + } + +end: + va_end(ap); + return (status); +badvalue: + { + const TIFFField* fip=TIFFFieldWithTag(tif,tag); + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Bad value %u for \"%s\" tag", + tif->tif_name, v, + fip ? fip->field_name : "Unknown"); + va_end(ap); + } + return (0); +badvalue32: + { + const TIFFField* fip=TIFFFieldWithTag(tif,tag); + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Bad value %u for \"%s\" tag", + tif->tif_name, v32, + fip ? fip->field_name : "Unknown"); + va_end(ap); + } + return (0); +} + +/* + * Return 1/0 according to whether or not + * it is permissible to set the tag's value. + * Note that we allow ImageLength to be changed + * so that we can append and extend to images. + * Any other tag may not be altered once writing + * has commenced, unless its value has no effect + * on the format of the data that is written. + */ +static int +OkToChangeTag(TIFF* tif, uint32 tag) +{ + const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY); + if (!fip) { /* unknown tag */ + TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", "%s: Unknown %stag %u", + tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", tag); + return (0); + } + if (tag != TIFFTAG_IMAGELENGTH && (tif->tif_flags & TIFF_BEENWRITING) && + !fip->field_oktochange) { + /* + * Consult info table to see if tag can be changed + * after we've started writing. We only allow changes + * to those tags that don't/shouldn't affect the + * compression and/or format of the data. + */ + TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", + "%s: Cannot modify tag \"%s\" while writing", + tif->tif_name, fip->field_name); + return (0); + } + return (1); +} + +/* + * Record the value of a field in the + * internal directory structure. The + * field will be written to the file + * when/if the directory structure is + * updated. + */ +int +TIFFSetField(TIFF* tif, uint32 tag, ...) +{ + va_list ap; + int status; + + va_start(ap, tag); + status = TIFFVSetField(tif, tag, ap); + va_end(ap); + return (status); +} + +/* + * Clear the contents of the field in the internal structure. + */ +int +TIFFUnsetField(TIFF* tif, uint32 tag) +{ + const TIFFField *fip = TIFFFieldWithTag(tif, tag); + TIFFDirectory* td = &tif->tif_dir; + + if( !fip ) + return 0; + + if( fip->field_bit != FIELD_CUSTOM ) + TIFFClrFieldBit(tif, fip->field_bit); + else + { + TIFFTagValue *tv = NULL; + int i; + + for (i = 0; i < td->td_customValueCount; i++) { + + tv = td->td_customValues + i; + if( tv->info->field_tag == tag ) + break; + } + + if( i < td->td_customValueCount ) + { + _TIFFfree(tv->value); + for( ; i < td->td_customValueCount-1; i++) { + td->td_customValues[i] = td->td_customValues[i+1]; + } + td->td_customValueCount--; + } + } + + tif->tif_flags |= TIFF_DIRTYDIRECT; + + return (1); +} + +/* + * Like TIFFSetField, but taking a varargs + * parameter list. This routine is useful + * for building higher-level interfaces on + * top of the library. + */ +int +TIFFVSetField(TIFF* tif, uint32 tag, va_list ap) +{ + return OkToChangeTag(tif, tag) ? + (*tif->tif_tagmethods.vsetfield)(tif, tag, ap) : 0; +} + +static int +_TIFFVGetField(TIFF* tif, uint32 tag, va_list ap) +{ + TIFFDirectory* td = &tif->tif_dir; + int ret_val = 1; + uint32 standard_tag = tag; + const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY); + + /* + * We want to force the custom code to be used for custom + * fields even if the tag happens to match a well known + * one - important for reinterpreted handling of standard + * tag values in custom directories (ie. EXIF) + */ + if (fip->field_bit == FIELD_CUSTOM) { + standard_tag = 0; + } + + switch (standard_tag) { + case TIFFTAG_SUBFILETYPE: + *va_arg(ap, uint32*) = td->td_subfiletype; + break; + case TIFFTAG_IMAGEWIDTH: + *va_arg(ap, uint32*) = td->td_imagewidth; + break; + case TIFFTAG_IMAGELENGTH: + *va_arg(ap, uint32*) = td->td_imagelength; + break; + case TIFFTAG_BITSPERSAMPLE: + *va_arg(ap, uint16*) = td->td_bitspersample; + break; + case TIFFTAG_COMPRESSION: + *va_arg(ap, uint16*) = td->td_compression; + break; + case TIFFTAG_PHOTOMETRIC: + *va_arg(ap, uint16*) = td->td_photometric; + break; + case TIFFTAG_THRESHHOLDING: + *va_arg(ap, uint16*) = td->td_threshholding; + break; + case TIFFTAG_FILLORDER: + *va_arg(ap, uint16*) = td->td_fillorder; + break; + case TIFFTAG_ORIENTATION: + *va_arg(ap, uint16*) = td->td_orientation; + break; + case TIFFTAG_SAMPLESPERPIXEL: + *va_arg(ap, uint16*) = td->td_samplesperpixel; + break; + case TIFFTAG_ROWSPERSTRIP: + *va_arg(ap, uint32*) = td->td_rowsperstrip; + break; + case TIFFTAG_MINSAMPLEVALUE: + *va_arg(ap, uint16*) = td->td_minsamplevalue; + break; + case TIFFTAG_MAXSAMPLEVALUE: + *va_arg(ap, uint16*) = td->td_maxsamplevalue; + break; + case TIFFTAG_SMINSAMPLEVALUE: + if (tif->tif_flags & TIFF_PERSAMPLE) + *va_arg(ap, double**) = td->td_sminsamplevalue; + else + { + /* libtiff historially treats this as a single value. */ + uint16 i; + double v = td->td_sminsamplevalue[0]; + for (i=1; i < td->td_samplesperpixel; ++i) + if( td->td_sminsamplevalue[i] < v ) + v = td->td_sminsamplevalue[i]; + *va_arg(ap, double*) = v; + } + break; + case TIFFTAG_SMAXSAMPLEVALUE: + if (tif->tif_flags & TIFF_PERSAMPLE) + *va_arg(ap, double**) = td->td_smaxsamplevalue; + else + { + /* libtiff historially treats this as a single value. */ + uint16 i; + double v = td->td_smaxsamplevalue[0]; + for (i=1; i < td->td_samplesperpixel; ++i) + if( td->td_smaxsamplevalue[i] > v ) + v = td->td_smaxsamplevalue[i]; + *va_arg(ap, double*) = v; + } + break; + case TIFFTAG_XRESOLUTION: + *va_arg(ap, float*) = td->td_xresolution; + break; + case TIFFTAG_YRESOLUTION: + *va_arg(ap, float*) = td->td_yresolution; + break; + case TIFFTAG_PLANARCONFIG: + *va_arg(ap, uint16*) = td->td_planarconfig; + break; + case TIFFTAG_XPOSITION: + *va_arg(ap, float*) = td->td_xposition; + break; + case TIFFTAG_YPOSITION: + *va_arg(ap, float*) = td->td_yposition; + break; + case TIFFTAG_RESOLUTIONUNIT: + *va_arg(ap, uint16*) = td->td_resolutionunit; + break; + case TIFFTAG_PAGENUMBER: + *va_arg(ap, uint16*) = td->td_pagenumber[0]; + *va_arg(ap, uint16*) = td->td_pagenumber[1]; + break; + case TIFFTAG_HALFTONEHINTS: + *va_arg(ap, uint16*) = td->td_halftonehints[0]; + *va_arg(ap, uint16*) = td->td_halftonehints[1]; + break; + case TIFFTAG_COLORMAP: + *va_arg(ap, uint16**) = td->td_colormap[0]; + *va_arg(ap, uint16**) = td->td_colormap[1]; + *va_arg(ap, uint16**) = td->td_colormap[2]; + break; + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_TILEOFFSETS: + _TIFFFillStriles( tif ); + *va_arg(ap, uint64**) = td->td_stripoffset; + break; + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEBYTECOUNTS: + _TIFFFillStriles( tif ); + *va_arg(ap, uint64**) = td->td_stripbytecount; + break; + case TIFFTAG_MATTEING: + *va_arg(ap, uint16*) = + (td->td_extrasamples == 1 && + td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA); + break; + case TIFFTAG_EXTRASAMPLES: + *va_arg(ap, uint16*) = td->td_extrasamples; + *va_arg(ap, uint16**) = td->td_sampleinfo; + break; + case TIFFTAG_TILEWIDTH: + *va_arg(ap, uint32*) = td->td_tilewidth; + break; + case TIFFTAG_TILELENGTH: + *va_arg(ap, uint32*) = td->td_tilelength; + break; + case TIFFTAG_TILEDEPTH: + *va_arg(ap, uint32*) = td->td_tiledepth; + break; + case TIFFTAG_DATATYPE: + switch (td->td_sampleformat) { + case SAMPLEFORMAT_UINT: + *va_arg(ap, uint16*) = DATATYPE_UINT; + break; + case SAMPLEFORMAT_INT: + *va_arg(ap, uint16*) = DATATYPE_INT; + break; + case SAMPLEFORMAT_IEEEFP: + *va_arg(ap, uint16*) = DATATYPE_IEEEFP; + break; + case SAMPLEFORMAT_VOID: + *va_arg(ap, uint16*) = DATATYPE_VOID; + break; + } + break; + case TIFFTAG_SAMPLEFORMAT: + *va_arg(ap, uint16*) = td->td_sampleformat; + break; + case TIFFTAG_IMAGEDEPTH: + *va_arg(ap, uint32*) = td->td_imagedepth; + break; + case TIFFTAG_SUBIFD: + *va_arg(ap, uint16*) = td->td_nsubifd; + *va_arg(ap, uint64**) = td->td_subifd; + break; + case TIFFTAG_YCBCRPOSITIONING: + *va_arg(ap, uint16*) = td->td_ycbcrpositioning; + break; + case TIFFTAG_YCBCRSUBSAMPLING: + *va_arg(ap, uint16*) = td->td_ycbcrsubsampling[0]; + *va_arg(ap, uint16*) = td->td_ycbcrsubsampling[1]; + break; + case TIFFTAG_TRANSFERFUNCTION: + *va_arg(ap, uint16**) = td->td_transferfunction[0]; + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + *va_arg(ap, uint16**) = td->td_transferfunction[1]; + *va_arg(ap, uint16**) = td->td_transferfunction[2]; + } + break; + case TIFFTAG_REFERENCEBLACKWHITE: + *va_arg(ap, float**) = td->td_refblackwhite; + break; + case TIFFTAG_INKNAMES: + *va_arg(ap, char**) = td->td_inknames; + break; + default: + { + int i; + + /* + * This can happen if multiple images are open + * with different codecs which have private + * tags. The global tag information table may + * then have tags that are valid for one file + * but not the other. If the client tries to + * get a tag that is not valid for the image's + * codec then we'll arrive here. + */ + if( fip == NULL || fip->field_bit != FIELD_CUSTOM ) + { + TIFFErrorExt(tif->tif_clientdata, "_TIFFVGetField", + "%s: Invalid %stag \"%s\" " + "(not supported by codec)", + tif->tif_name, + isPseudoTag(tag) ? "pseudo-" : "", + fip ? fip->field_name : "Unknown"); + ret_val = 0; + break; + } + + /* + * Do we have a custom value? + */ + ret_val = 0; + for (i = 0; i < td->td_customValueCount; i++) { + TIFFTagValue *tv = td->td_customValues + i; + + if (tv->info->field_tag != tag) + continue; + + if (fip->field_passcount) { + if (fip->field_readcount == TIFF_VARIABLE2) + *va_arg(ap, uint32*) = (uint32)tv->count; + else /* Assume TIFF_VARIABLE */ + *va_arg(ap, uint16*) = (uint16)tv->count; + *va_arg(ap, void **) = tv->value; + ret_val = 1; + } else if (fip->field_tag == TIFFTAG_DOTRANGE + && strcmp(fip->field_name,"DotRange") == 0) { + /* TODO: This is an evil exception and should not have been + handled this way ... likely best if we move it into + the directory structure with an explicit field in + libtiff 4.1 and assign it a FIELD_ value */ + *va_arg(ap, uint16*) = ((uint16 *)tv->value)[0]; + *va_arg(ap, uint16*) = ((uint16 *)tv->value)[1]; + ret_val = 1; + } else { + if (fip->field_type == TIFF_ASCII + || fip->field_readcount == TIFF_VARIABLE + || fip->field_readcount == TIFF_VARIABLE2 + || fip->field_readcount == TIFF_SPP + || tv->count > 1) { + *va_arg(ap, void **) = tv->value; + ret_val = 1; + } else { + char *val = (char *)tv->value; + assert( tv->count == 1 ); + switch (fip->field_type) { + case TIFF_BYTE: + case TIFF_UNDEFINED: + *va_arg(ap, uint8*) = + *(uint8 *)val; + ret_val = 1; + break; + case TIFF_SBYTE: + *va_arg(ap, int8*) = + *(int8 *)val; + ret_val = 1; + break; + case TIFF_SHORT: + *va_arg(ap, uint16*) = + *(uint16 *)val; + ret_val = 1; + break; + case TIFF_SSHORT: + *va_arg(ap, int16*) = + *(int16 *)val; + ret_val = 1; + break; + case TIFF_LONG: + case TIFF_IFD: + *va_arg(ap, uint32*) = + *(uint32 *)val; + ret_val = 1; + break; + case TIFF_SLONG: + *va_arg(ap, int32*) = + *(int32 *)val; + ret_val = 1; + break; + case TIFF_LONG8: + case TIFF_IFD8: + *va_arg(ap, uint64*) = + *(uint64 *)val; + ret_val = 1; + break; + case TIFF_SLONG8: + *va_arg(ap, int64*) = + *(int64 *)val; + ret_val = 1; + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + *va_arg(ap, float*) = + *(float *)val; + ret_val = 1; + break; + case TIFF_DOUBLE: + *va_arg(ap, double*) = + *(double *)val; + ret_val = 1; + break; + default: + ret_val = 0; + break; + } + } + } + break; + } + } + } + return(ret_val); +} + +/* + * Return the value of a field in the + * internal directory structure. + */ +int +TIFFGetField(TIFF* tif, uint32 tag, ...) +{ + int status; + va_list ap; + + va_start(ap, tag); + status = TIFFVGetField(tif, tag, ap); + va_end(ap); + return (status); +} + +/* + * Like TIFFGetField, but taking a varargs + * parameter list. This routine is useful + * for building higher-level interfaces on + * top of the library. + */ +int +TIFFVGetField(TIFF* tif, uint32 tag, va_list ap) +{ + const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY); + return (fip && (isPseudoTag(tag) || TIFFFieldSet(tif, fip->field_bit)) ? + (*tif->tif_tagmethods.vgetfield)(tif, tag, ap) : 0); +} + +#define CleanupField(member) { \ + if (td->member) { \ + _TIFFfree(td->member); \ + td->member = 0; \ + } \ +} + +/* + * Release storage associated with a directory. + */ +void +TIFFFreeDirectory(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + int i; + + _TIFFmemset(td->td_fieldsset, 0, FIELD_SETLONGS); + CleanupField(td_sminsamplevalue); + CleanupField(td_smaxsamplevalue); + CleanupField(td_colormap[0]); + CleanupField(td_colormap[1]); + CleanupField(td_colormap[2]); + CleanupField(td_sampleinfo); + CleanupField(td_subifd); + CleanupField(td_inknames); + CleanupField(td_refblackwhite); + CleanupField(td_transferfunction[0]); + CleanupField(td_transferfunction[1]); + CleanupField(td_transferfunction[2]); + CleanupField(td_stripoffset); + CleanupField(td_stripbytecount); + TIFFClrFieldBit(tif, FIELD_YCBCRSUBSAMPLING); + TIFFClrFieldBit(tif, FIELD_YCBCRPOSITIONING); + + /* Cleanup custom tag values */ + for( i = 0; i < td->td_customValueCount; i++ ) { + if (td->td_customValues[i].value) + _TIFFfree(td->td_customValues[i].value); + } + + td->td_customValueCount = 0; + CleanupField(td_customValues); + +#if defined(DEFER_STRILE_LOAD) + _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry)); + _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry)); +#endif +} +#undef CleanupField + +/* + * Client Tag extension support (from Niles Ritter). + */ +static TIFFExtendProc _TIFFextender = (TIFFExtendProc) NULL; + +TIFFExtendProc +TIFFSetTagExtender(TIFFExtendProc extender) +{ + TIFFExtendProc prev = _TIFFextender; + _TIFFextender = extender; + return (prev); +} + +/* + * Setup for a new directory. Should we automatically call + * TIFFWriteDirectory() if the current one is dirty? + * + * The newly created directory will not exist on the file till + * TIFFWriteDirectory(), TIFFFlush() or TIFFClose() is called. + */ +int +TIFFCreateDirectory(TIFF* tif) +{ + TIFFDefaultDirectory(tif); + tif->tif_diroff = 0; + tif->tif_nextdiroff = 0; + tif->tif_curoff = 0; + tif->tif_row = (uint32) -1; + tif->tif_curstrip = (uint32) -1; + + return 0; +} + +int +TIFFCreateCustomDirectory(TIFF* tif, const TIFFFieldArray* infoarray) +{ + TIFFDefaultDirectory(tif); + + /* + * Reset the field definitions to match the application provided list. + * Hopefully TIFFDefaultDirectory() won't have done anything irreversable + * based on it's assumption this is an image directory. + */ + _TIFFSetupFields(tif, infoarray); + + tif->tif_diroff = 0; + tif->tif_nextdiroff = 0; + tif->tif_curoff = 0; + tif->tif_row = (uint32) -1; + tif->tif_curstrip = (uint32) -1; + + return 0; +} + +int +TIFFCreateEXIFDirectory(TIFF* tif) +{ + const TIFFFieldArray* exifFieldArray; + exifFieldArray = _TIFFGetExifFields(); + return TIFFCreateCustomDirectory(tif, exifFieldArray); +} + +/* + * Setup a default directory structure. + */ +int +TIFFDefaultDirectory(TIFF* tif) +{ + register TIFFDirectory* td = &tif->tif_dir; + const TIFFFieldArray* tiffFieldArray; + + tiffFieldArray = _TIFFGetFields(); + _TIFFSetupFields(tif, tiffFieldArray); + + _TIFFmemset(td, 0, sizeof (*td)); + td->td_fillorder = FILLORDER_MSB2LSB; + td->td_bitspersample = 1; + td->td_threshholding = THRESHHOLD_BILEVEL; + td->td_orientation = ORIENTATION_TOPLEFT; + td->td_samplesperpixel = 1; + td->td_rowsperstrip = (uint32) -1; + td->td_tilewidth = 0; + td->td_tilelength = 0; + td->td_tiledepth = 1; + td->td_stripbytecountsorted = 1; /* Our own arrays always sorted. */ + td->td_resolutionunit = RESUNIT_INCH; + td->td_sampleformat = SAMPLEFORMAT_UINT; + td->td_imagedepth = 1; + td->td_ycbcrsubsampling[0] = 2; + td->td_ycbcrsubsampling[1] = 2; + td->td_ycbcrpositioning = YCBCRPOSITION_CENTERED; + tif->tif_postdecode = _TIFFNoPostDecode; + tif->tif_foundfield = NULL; + tif->tif_tagmethods.vsetfield = _TIFFVSetField; + tif->tif_tagmethods.vgetfield = _TIFFVGetField; + tif->tif_tagmethods.printdir = NULL; + /* + * Give client code a chance to install their own + * tag extensions & methods, prior to compression overloads. + */ + if (_TIFFextender) + (*_TIFFextender)(tif); + (void) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + /* + * NB: The directory is marked dirty as a result of setting + * up the default compression scheme. However, this really + * isn't correct -- we want TIFF_DIRTYDIRECT to be set only + * if the user does something. We could just do the setup + * by hand, but it seems better to use the normal mechanism + * (i.e. TIFFSetField). + */ + tif->tif_flags &= ~TIFF_DIRTYDIRECT; + + /* + * As per http://bugzilla.remotesensing.org/show_bug.cgi?id=19 + * we clear the ISTILED flag when setting up a new directory. + * Should we also be clearing stuff like INSUBIFD? + */ + tif->tif_flags &= ~TIFF_ISTILED; + + return (1); +} + +static int +TIFFAdvanceDirectory(TIFF* tif, uint64* nextdir, uint64* off) +{ + static const char module[] = "TIFFAdvanceDirectory"; + if (isMapped(tif)) + { + uint64 poff=*nextdir; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + tmsize_t poffa,poffb,poffc,poffd; + uint16 dircount; + uint32 nextdir32; + poffa=(tmsize_t)poff; + poffb=poffa+sizeof(uint16); + if (((uint64)poffa!=poff)||(poffbtif->tif_size)) + { + TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory count"); + return(0); + } + _TIFFmemcpy(&dircount,tif->tif_base+poffa,sizeof(uint16)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort(&dircount); + poffc=poffb+dircount*12; + poffd=poffc+sizeof(uint32); + if ((poffctif->tif_size)) + { + TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory link"); + return(0); + } + if (off!=NULL) + *off=(uint64)poffc; + _TIFFmemcpy(&nextdir32,tif->tif_base+poffc,sizeof(uint32)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&nextdir32); + *nextdir=nextdir32; + } + else + { + tmsize_t poffa,poffb,poffc,poffd; + uint64 dircount64; + uint16 dircount16; + poffa=(tmsize_t)poff; + poffb=poffa+sizeof(uint64); + if (((uint64)poffa!=poff)||(poffbtif->tif_size)) + { + TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory count"); + return(0); + } + _TIFFmemcpy(&dircount64,tif->tif_base+poffa,sizeof(uint64)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>0xFFFF) + { + TIFFErrorExt(tif->tif_clientdata,module,"Sanity check on directory count failed"); + return(0); + } + dircount16=(uint16)dircount64; + poffc=poffb+dircount16*20; + poffd=poffc+sizeof(uint64); + if ((poffctif->tif_size)) + { + TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory link"); + return(0); + } + if (off!=NULL) + *off=(uint64)poffc; + _TIFFmemcpy(nextdir,tif->tif_base+poffc,sizeof(uint64)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(nextdir); + } + return(1); + } + else + { + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint16 dircount; + uint32 nextdir32; + if (!SeekOK(tif, *nextdir) || + !ReadOK(tif, &dircount, sizeof (uint16))) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + if (off != NULL) + *off = TIFFSeekFile(tif, + dircount*12, SEEK_CUR); + else + (void) TIFFSeekFile(tif, + dircount*12, SEEK_CUR); + if (!ReadOK(tif, &nextdir32, sizeof (uint32))) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextdir32); + *nextdir=nextdir32; + } + else + { + uint64 dircount64; + uint16 dircount16; + if (!SeekOK(tif, *nextdir) || + !ReadOK(tif, &dircount64, sizeof (uint64))) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>0xFFFF) + { + TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory count"); + return(0); + } + dircount16 = (uint16)dircount64; + if (off != NULL) + *off = TIFFSeekFile(tif, + dircount16*20, SEEK_CUR); + else + (void) TIFFSeekFile(tif, + dircount16*20, SEEK_CUR); + if (!ReadOK(tif, nextdir, sizeof (uint64))) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(nextdir); + } + return (1); + } +} + +/* + * Count the number of directories in a file. + */ +uint16 +TIFFNumberOfDirectories(TIFF* tif) +{ + uint64 nextdir; + uint16 n; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + nextdir = tif->tif_header.classic.tiff_diroff; + else + nextdir = tif->tif_header.big.tiff_diroff; + n = 0; + while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL)) + n++; + return (n); +} + +/* + * Set the n-th directory as the current directory. + * NB: Directories are numbered starting at 0. + */ +int +TIFFSetDirectory(TIFF* tif, uint16 dirn) +{ + uint64 nextdir; + uint16 n; + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + nextdir = tif->tif_header.classic.tiff_diroff; + else + nextdir = tif->tif_header.big.tiff_diroff; + for (n = dirn; n > 0 && nextdir != 0; n--) + if (!TIFFAdvanceDirectory(tif, &nextdir, NULL)) + return (0); + tif->tif_nextdiroff = nextdir; + /* + * Set curdir to the actual directory index. The + * -1 is because TIFFReadDirectory will increment + * tif_curdir after successfully reading the directory. + */ + tif->tif_curdir = (dirn - n) - 1; + /* + * Reset tif_dirnumber counter and start new list of seen directories. + * We need this to prevent IFD loops. + */ + tif->tif_dirnumber = 0; + return (TIFFReadDirectory(tif)); +} + +/* + * Set the current directory to be the directory + * located at the specified file offset. This interface + * is used mainly to access directories linked with + * the SubIFD tag (e.g. thumbnail images). + */ +int +TIFFSetSubDirectory(TIFF* tif, uint64 diroff) +{ + tif->tif_nextdiroff = diroff; + /* + * Reset tif_dirnumber counter and start new list of seen directories. + * We need this to prevent IFD loops. + */ + tif->tif_dirnumber = 0; + return (TIFFReadDirectory(tif)); +} + +/* + * Return file offset of the current directory. + */ +uint64 +TIFFCurrentDirOffset(TIFF* tif) +{ + return (tif->tif_diroff); +} + +/* + * Return an indication of whether or not we are + * at the last directory in the file. + */ +int +TIFFLastDirectory(TIFF* tif) +{ + return (tif->tif_nextdiroff == 0); +} + +/* + * Unlink the specified directory from the directory chain. + */ +int +TIFFUnlinkDirectory(TIFF* tif, uint16 dirn) +{ + static const char module[] = "TIFFUnlinkDirectory"; + uint64 nextdir; + uint64 off; + uint16 n; + + if (tif->tif_mode == O_RDONLY) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not unlink directory in read-only file"); + return (0); + } + /* + * Go to the directory before the one we want + * to unlink and nab the offset of the link + * field we'll need to patch. + */ + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + nextdir = tif->tif_header.classic.tiff_diroff; + off = 4; + } + else + { + nextdir = tif->tif_header.big.tiff_diroff; + off = 8; + } + for (n = dirn-1; n > 0; n--) { + if (nextdir == 0) { + TIFFErrorExt(tif->tif_clientdata, module, "Directory %d does not exist", dirn); + return (0); + } + if (!TIFFAdvanceDirectory(tif, &nextdir, &off)) + return (0); + } + /* + * Advance to the directory to be unlinked and fetch + * the offset of the directory that follows. + */ + if (!TIFFAdvanceDirectory(tif, &nextdir, NULL)) + return (0); + /* + * Go back and patch the link field of the preceding + * directory to point to the offset of the directory + * that follows. + */ + (void) TIFFSeekFile(tif, off, SEEK_SET); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32 nextdir32; + nextdir32=(uint32)nextdir; + assert((uint64)nextdir32==nextdir); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextdir32); + if (!WriteOK(tif, &nextdir32, sizeof (uint32))) { + TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link"); + return (0); + } + } + else + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&nextdir); + if (!WriteOK(tif, &nextdir, sizeof (uint64))) { + TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link"); + return (0); + } + } + /* + * Leave directory state setup safely. We don't have + * facilities for doing inserting and removing directories, + * so it's safest to just invalidate everything. This + * means that the caller can only append to the directory + * chain. + */ + (*tif->tif_cleanup)(tif); + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawcc = 0; + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = 0; + } + tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP|TIFF_POSTENCODE|TIFF_BUF4WRITE); + TIFFFreeDirectory(tif); + TIFFDefaultDirectory(tif); + tif->tif_diroff = 0; /* force link on next write */ + tif->tif_nextdiroff = 0; /* next write must be at end */ + tif->tif_curoff = 0; + tif->tif_row = (uint32) -1; + tif->tif_curstrip = (uint32) -1; + return (1); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.h b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.h new file mode 100644 index 0000000000..6af5f3dc37 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dir.h @@ -0,0 +1,308 @@ +/* $Id: tif_dir.h,v 1.54 2011-02-18 20:53:05 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFDIR_ +#define _TIFFDIR_ +/* + * ``Library-private'' Directory-related Definitions. + */ + +typedef struct { + const TIFFField *info; + int count; + void *value; +} TIFFTagValue; + +/* + * TIFF Image File Directories are comprised of a table of field + * descriptors of the form shown below. The table is sorted in + * ascending order by tag. The values associated with each entry are + * disjoint and may appear anywhere in the file (so long as they are + * placed on a word boundary). + * + * If the value is 4 bytes or less, in ClassicTIFF, or 8 bytes or less in + * BigTIFF, then it is placed in the offset field to save space. If so, + * it is left-justified in the offset field. + */ +typedef struct { + uint16 tdir_tag; /* see below */ + uint16 tdir_type; /* data type; see below */ + uint64 tdir_count; /* number of items; length in spec */ + union { + uint16 toff_short; + uint32 toff_long; + uint64 toff_long8; + } tdir_offset; /* either offset or the data itself if fits */ +} TIFFDirEntry; + +/* + * Internal format of a TIFF directory entry. + */ +typedef struct { +#define FIELD_SETLONGS 4 + /* bit vector of fields that are set */ + unsigned long td_fieldsset[FIELD_SETLONGS]; + + uint32 td_imagewidth, td_imagelength, td_imagedepth; + uint32 td_tilewidth, td_tilelength, td_tiledepth; + uint32 td_subfiletype; + uint16 td_bitspersample; + uint16 td_sampleformat; + uint16 td_compression; + uint16 td_photometric; + uint16 td_threshholding; + uint16 td_fillorder; + uint16 td_orientation; + uint16 td_samplesperpixel; + uint32 td_rowsperstrip; + uint16 td_minsamplevalue, td_maxsamplevalue; + double* td_sminsamplevalue; + double* td_smaxsamplevalue; + float td_xresolution, td_yresolution; + uint16 td_resolutionunit; + uint16 td_planarconfig; + float td_xposition, td_yposition; + uint16 td_pagenumber[2]; + uint16* td_colormap[3]; + uint16 td_halftonehints[2]; + uint16 td_extrasamples; + uint16* td_sampleinfo; + /* even though the name is misleading, td_stripsperimage is the number + * of striles (=strips or tiles) per plane, and td_nstrips the total + * number of striles */ + uint32 td_stripsperimage; + uint32 td_nstrips; /* size of offset & bytecount arrays */ + uint64* td_stripoffset; + uint64* td_stripbytecount; + int td_stripbytecountsorted; /* is the bytecount array sorted ascending? */ +#if defined(DEFER_STRILE_LOAD) + TIFFDirEntry td_stripoffset_entry; /* for deferred loading */ + TIFFDirEntry td_stripbytecount_entry; /* for deferred loading */ +#endif + uint16 td_nsubifd; + uint64* td_subifd; + /* YCbCr parameters */ + uint16 td_ycbcrsubsampling[2]; + uint16 td_ycbcrpositioning; + /* Colorimetry parameters */ + uint16* td_transferfunction[3]; + float* td_refblackwhite; + /* CMYK parameters */ + int td_inknameslen; + char* td_inknames; + + int td_customValueCount; + TIFFTagValue *td_customValues; +} TIFFDirectory; + +/* + * Field flags used to indicate fields that have been set in a directory, and + * to reference fields when manipulating a directory. + */ + +/* + * FIELD_IGNORE is used to signify tags that are to be processed but otherwise + * ignored. This permits antiquated tags to be quietly read and discarded. + * Note that a bit *is* allocated for ignored tags; this is understood by the + * directory reading logic which uses this fact to avoid special-case handling + */ +#define FIELD_IGNORE 0 + +/* multi-item fields */ +#define FIELD_IMAGEDIMENSIONS 1 +#define FIELD_TILEDIMENSIONS 2 +#define FIELD_RESOLUTION 3 +#define FIELD_POSITION 4 + +/* single-item fields */ +#define FIELD_SUBFILETYPE 5 +#define FIELD_BITSPERSAMPLE 6 +#define FIELD_COMPRESSION 7 +#define FIELD_PHOTOMETRIC 8 +#define FIELD_THRESHHOLDING 9 +#define FIELD_FILLORDER 10 +#define FIELD_ORIENTATION 15 +#define FIELD_SAMPLESPERPIXEL 16 +#define FIELD_ROWSPERSTRIP 17 +#define FIELD_MINSAMPLEVALUE 18 +#define FIELD_MAXSAMPLEVALUE 19 +#define FIELD_PLANARCONFIG 20 +#define FIELD_RESOLUTIONUNIT 22 +#define FIELD_PAGENUMBER 23 +#define FIELD_STRIPBYTECOUNTS 24 +#define FIELD_STRIPOFFSETS 25 +#define FIELD_COLORMAP 26 +#define FIELD_EXTRASAMPLES 31 +#define FIELD_SAMPLEFORMAT 32 +#define FIELD_SMINSAMPLEVALUE 33 +#define FIELD_SMAXSAMPLEVALUE 34 +#define FIELD_IMAGEDEPTH 35 +#define FIELD_TILEDEPTH 36 +#define FIELD_HALFTONEHINTS 37 +#define FIELD_YCBCRSUBSAMPLING 39 +#define FIELD_YCBCRPOSITIONING 40 +#define FIELD_REFBLACKWHITE 41 +#define FIELD_TRANSFERFUNCTION 44 +#define FIELD_INKNAMES 46 +#define FIELD_SUBIFD 49 +/* FIELD_CUSTOM (see tiffio.h) 65 */ +/* end of support for well-known tags; codec-private tags follow */ +#define FIELD_CODEC 66 /* base of codec-private tags */ + + +/* + * Pseudo-tags don't normally need field bits since they are not written to an + * output file (by definition). The library also has express logic to always + * query a codec for a pseudo-tag so allocating a field bit for one is a + * waste. If codec wants to promote the notion of a pseudo-tag being ``set'' + * or ``unset'' then it can do using internal state flags without polluting + * the field bit space defined for real tags. + */ +#define FIELD_PSEUDO 0 + +#define FIELD_LAST (32*FIELD_SETLONGS-1) + +#define BITn(n) (((unsigned long)1L)<<((n)&0x1f)) +#define BITFIELDn(tif, n) ((tif)->tif_dir.td_fieldsset[(n)/32]) +#define TIFFFieldSet(tif, field) (BITFIELDn(tif, field) & BITn(field)) +#define TIFFSetFieldBit(tif, field) (BITFIELDn(tif, field) |= BITn(field)) +#define TIFFClrFieldBit(tif, field) (BITFIELDn(tif, field) &= ~BITn(field)) + +#define FieldSet(fields, f) (fields[(f)/32] & BITn(f)) +#define ResetFieldBit(fields, f) (fields[(f)/32] &= ~BITn(f)) + +typedef enum { + TIFF_SETGET_UNDEFINED = 0, + TIFF_SETGET_ASCII = 1, + TIFF_SETGET_UINT8 = 2, + TIFF_SETGET_SINT8 = 3, + TIFF_SETGET_UINT16 = 4, + TIFF_SETGET_SINT16 = 5, + TIFF_SETGET_UINT32 = 6, + TIFF_SETGET_SINT32 = 7, + TIFF_SETGET_UINT64 = 8, + TIFF_SETGET_SINT64 = 9, + TIFF_SETGET_FLOAT = 10, + TIFF_SETGET_DOUBLE = 11, + TIFF_SETGET_IFD8 = 12, + TIFF_SETGET_INT = 13, + TIFF_SETGET_UINT16_PAIR = 14, + TIFF_SETGET_C0_ASCII = 15, + TIFF_SETGET_C0_UINT8 = 16, + TIFF_SETGET_C0_SINT8 = 17, + TIFF_SETGET_C0_UINT16 = 18, + TIFF_SETGET_C0_SINT16 = 19, + TIFF_SETGET_C0_UINT32 = 20, + TIFF_SETGET_C0_SINT32 = 21, + TIFF_SETGET_C0_UINT64 = 22, + TIFF_SETGET_C0_SINT64 = 23, + TIFF_SETGET_C0_FLOAT = 24, + TIFF_SETGET_C0_DOUBLE = 25, + TIFF_SETGET_C0_IFD8 = 26, + TIFF_SETGET_C16_ASCII = 27, + TIFF_SETGET_C16_UINT8 = 28, + TIFF_SETGET_C16_SINT8 = 29, + TIFF_SETGET_C16_UINT16 = 30, + TIFF_SETGET_C16_SINT16 = 31, + TIFF_SETGET_C16_UINT32 = 32, + TIFF_SETGET_C16_SINT32 = 33, + TIFF_SETGET_C16_UINT64 = 34, + TIFF_SETGET_C16_SINT64 = 35, + TIFF_SETGET_C16_FLOAT = 36, + TIFF_SETGET_C16_DOUBLE = 37, + TIFF_SETGET_C16_IFD8 = 38, + TIFF_SETGET_C32_ASCII = 39, + TIFF_SETGET_C32_UINT8 = 40, + TIFF_SETGET_C32_SINT8 = 41, + TIFF_SETGET_C32_UINT16 = 42, + TIFF_SETGET_C32_SINT16 = 43, + TIFF_SETGET_C32_UINT32 = 44, + TIFF_SETGET_C32_SINT32 = 45, + TIFF_SETGET_C32_UINT64 = 46, + TIFF_SETGET_C32_SINT64 = 47, + TIFF_SETGET_C32_FLOAT = 48, + TIFF_SETGET_C32_DOUBLE = 49, + TIFF_SETGET_C32_IFD8 = 50, + TIFF_SETGET_OTHER = 51 +} TIFFSetGetFieldType; + +#if defined(__cplusplus) +extern "C" { +#endif + +extern const TIFFFieldArray* _TIFFGetFields(void); +extern const TIFFFieldArray* _TIFFGetExifFields(void); +extern void _TIFFSetupFields(TIFF* tif, const TIFFFieldArray* infoarray); +extern void _TIFFPrintFieldInfo(TIFF*, FILE*); + +extern int _TIFFFillStriles(TIFF*); + +typedef enum { + tfiatImage, + tfiatExif, + tfiatOther +} TIFFFieldArrayType; + +struct _TIFFFieldArray { + TIFFFieldArrayType type; /* array type, will be used to determine if IFD is image and such */ + uint32 allocated_size; /* 0 if array is constant, other if modified by future definition extension support */ + uint32 count; /* number of elements in fields array */ + TIFFField* fields; /* actual field info */ +}; + +struct _TIFFField { + uint32 field_tag; /* field's tag */ + short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ + short field_writecount; /* write count/TIFF_VARIABLE */ + TIFFDataType field_type; /* type of associated data */ + uint32 reserved; /* reserved for future extension */ + TIFFSetGetFieldType set_field_type; /* type to be passed to TIFFSetField */ + TIFFSetGetFieldType get_field_type; /* type to be passed to TIFFGetField */ + unsigned short field_bit; /* bit in fieldsset bit vector */ + unsigned char field_oktochange; /* if true, can change while writing */ + unsigned char field_passcount; /* if true, pass dir count on set */ + char* field_name; /* ASCII name */ + TIFFFieldArray* field_subfields; /* if field points to child ifds, child ifd field definition array */ +}; + +extern int _TIFFMergeFields(TIFF*, const TIFFField[], uint32); +extern const TIFFField* _TIFFFindOrRegisterField(TIFF *, uint32, TIFFDataType); +extern TIFFField* _TIFFCreateAnonField(TIFF *, uint32, TIFFDataType); + +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFDIR_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirinfo.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirinfo.c new file mode 100644 index 0000000000..5f28d23602 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirinfo.c @@ -0,0 +1,978 @@ +/* $Id: tif_dirinfo.c,v 1.117 2012-08-19 16:56:34 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Core Directory Tag Support. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#include + +/* + * NOTE: THIS ARRAY IS ASSUMED TO BE SORTED BY TAG. + * + * NOTE: The second field (field_readcount) and third field (field_writecount) + * sometimes use the values TIFF_VARIABLE (-1), TIFF_VARIABLE2 (-3) + * and TIFF_SPP (-2). The macros should be used but would throw off + * the formatting of the code, so please interprete the -1, -2 and -3 + * values accordingly. + */ + +static TIFFFieldArray tiffFieldArray; +static TIFFFieldArray exifFieldArray; + +static TIFFField +tiffFields[] = { + { TIFFTAG_SUBFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_SUBFILETYPE, 1, 0, "SubfileType", NULL }, + { TIFFTAG_OSUBFILETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_SUBFILETYPE, 1, 0, "OldSubfileType", NULL }, + { TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDIMENSIONS, 0, 0, "ImageWidth", NULL }, + { TIFFTAG_IMAGELENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDIMENSIONS, 1, 0, "ImageLength", NULL }, + { TIFFTAG_BITSPERSAMPLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_BITSPERSAMPLE, 0, 0, "BitsPerSample", NULL }, + { TIFFTAG_COMPRESSION, -1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_COMPRESSION, 0, 0, "Compression", NULL }, + { TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_PHOTOMETRIC, 0, 0, "PhotometricInterpretation", NULL }, + { TIFFTAG_THRESHHOLDING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_THRESHHOLDING, 1, 0, "Threshholding", NULL }, + { TIFFTAG_CELLWIDTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "CellWidth", NULL }, + { TIFFTAG_CELLLENGTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "CellLength", NULL }, + { TIFFTAG_FILLORDER, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_FILLORDER, 0, 0, "FillOrder", NULL }, + { TIFFTAG_DOCUMENTNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DocumentName", NULL }, + { TIFFTAG_IMAGEDESCRIPTION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageDescription", NULL }, + { TIFFTAG_MAKE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Make", NULL }, + { TIFFTAG_MODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Model", NULL }, + { TIFFTAG_STRIPOFFSETS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPOFFSETS, 0, 0, "StripOffsets", NULL }, + { TIFFTAG_ORIENTATION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_ORIENTATION, 0, 0, "Orientation", NULL }, + { TIFFTAG_SAMPLESPERPIXEL, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLESPERPIXEL, 0, 0, "SamplesPerPixel", NULL }, + { TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_ROWSPERSTRIP, 0, 0, "RowsPerStrip", NULL }, + { TIFFTAG_STRIPBYTECOUNTS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPBYTECOUNTS, 0, 0, "StripByteCounts", NULL }, + { TIFFTAG_MINSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_MINSAMPLEVALUE, 1, 0, "MinSampleValue", NULL }, + { TIFFTAG_MAXSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_MAXSAMPLEVALUE, 1, 0, "MaxSampleValue", NULL }, + { TIFFTAG_XRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTION, 1, 0, "XResolution", NULL }, + { TIFFTAG_YRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTION, 1, 0, "YResolution", NULL }, + { TIFFTAG_PLANARCONFIG, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_PLANARCONFIG, 0, 0, "PlanarConfiguration", NULL }, + { TIFFTAG_PAGENAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PageName", NULL }, + { TIFFTAG_XPOSITION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_POSITION, 1, 0, "XPosition", NULL }, + { TIFFTAG_YPOSITION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_POSITION, 1, 0, "YPosition", NULL }, + { TIFFTAG_FREEOFFSETS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 0, 0, "FreeOffsets", NULL }, + { TIFFTAG_FREEBYTECOUNTS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 0, 0, "FreeByteCounts", NULL }, + { TIFFTAG_GRAYRESPONSEUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "GrayResponseUnit", NULL }, + { TIFFTAG_GRAYRESPONSECURVE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "GrayResponseCurve", NULL }, + { TIFFTAG_RESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTIONUNIT, 1, 0, "ResolutionUnit", NULL }, + { TIFFTAG_PAGENUMBER, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_PAGENUMBER, 1, 0, "PageNumber", NULL }, + { TIFFTAG_COLORRESPONSEUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "ColorResponseUnit", NULL }, + { TIFFTAG_TRANSFERFUNCTION, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_TRANSFERFUNCTION, 1, 0, "TransferFunction", NULL }, + { TIFFTAG_SOFTWARE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Software", NULL }, + { TIFFTAG_DATETIME, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTime", NULL }, + { TIFFTAG_ARTIST, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Artist", NULL }, + { TIFFTAG_HOSTCOMPUTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "HostComputer", NULL }, + { TIFFTAG_WHITEPOINT, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "WhitePoint", NULL }, + { TIFFTAG_PRIMARYCHROMATICITIES, 6, 6, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PrimaryChromaticities", NULL }, + { TIFFTAG_COLORMAP, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_COLORMAP, 1, 0, "ColorMap", NULL }, + { TIFFTAG_HALFTONEHINTS, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_HALFTONEHINTS, 1, 0, "HalftoneHints", NULL }, + { TIFFTAG_TILEWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDIMENSIONS, 0, 0, "TileWidth", NULL }, + { TIFFTAG_TILELENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDIMENSIONS, 0, 0, "TileLength", NULL }, + { TIFFTAG_TILEOFFSETS, -1, 1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPOFFSETS, 0, 0, "TileOffsets", NULL }, + { TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPBYTECOUNTS, 0, 0, "TileByteCounts", NULL }, + { TIFFTAG_SUBIFD, -1, -1, TIFF_IFD8, 0, TIFF_SETGET_C16_IFD8, TIFF_SETGET_UNDEFINED, FIELD_SUBIFD, 1, 1, "SubIFD", &tiffFieldArray }, + { TIFFTAG_INKSET, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InkSet", NULL }, + { TIFFTAG_INKNAMES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_C16_ASCII, TIFF_SETGET_UNDEFINED, FIELD_INKNAMES, 1, 1, "InkNames", NULL }, + { TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "NumberOfInks", NULL }, + { TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DotRange", NULL }, + { TIFFTAG_TARGETPRINTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TargetPrinter", NULL }, + { TIFFTAG_EXTRASAMPLES, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 1, "ExtraSamples", NULL }, + { TIFFTAG_SAMPLEFORMAT, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLEFORMAT, 0, 0, "SampleFormat", NULL }, + { TIFFTAG_SMINSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_SMINSAMPLEVALUE, 1, 0, "SMinSampleValue", NULL }, + { TIFFTAG_SMAXSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_SMAXSAMPLEVALUE, 1, 0, "SMaxSampleValue", NULL }, + { TIFFTAG_CLIPPATH, -1, -3, TIFF_BYTE, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ClipPath", NULL }, + { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SLONG, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "XClipPathUnits", NULL }, + { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SBYTE, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "XClipPathUnits", NULL }, + { TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SLONG, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "YClipPathUnits", NULL }, + { TIFFTAG_YCBCRCOEFFICIENTS, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "YCbCrCoefficients", NULL }, + { TIFFTAG_YCBCRSUBSAMPLING, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_YCBCRSUBSAMPLING, 0, 0, "YCbCrSubsampling", NULL }, + { TIFFTAG_YCBCRPOSITIONING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_YCBCRPOSITIONING, 0, 0, "YCbCrPositioning", NULL }, + { TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_REFBLACKWHITE, 1, 0, "ReferenceBlackWhite", NULL }, + { TIFFTAG_XMLPACKET, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "XMLPacket", NULL }, + /* begin SGI tags */ + { TIFFTAG_MATTEING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 0, "Matteing", NULL }, + { TIFFTAG_DATATYPE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLEFORMAT, 0, 0, "DataType", NULL }, + { TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDEPTH, 0, 0, "ImageDepth", NULL }, + { TIFFTAG_TILEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDEPTH, 0, 0, "TileDepth", NULL }, + /* end SGI tags */ + /* begin Pixar tags */ + { TIFFTAG_PIXAR_IMAGEFULLWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageFullWidth", NULL }, + { TIFFTAG_PIXAR_IMAGEFULLLENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageFullLength", NULL }, + { TIFFTAG_PIXAR_TEXTUREFORMAT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TextureFormat", NULL }, + { TIFFTAG_PIXAR_WRAPMODES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TextureWrapModes", NULL }, + { TIFFTAG_PIXAR_FOVCOT, 1, 1, TIFF_FLOAT, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FieldOfViewCotangent", NULL }, + { TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToScreen", NULL }, + { TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToCamera", NULL }, + { TIFFTAG_COPYRIGHT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Copyright", NULL }, + /* end Pixar tags */ + { TIFFTAG_RICHTIFFIPTC, -3, -3, TIFF_LONG, 0, TIFF_SETGET_C32_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "RichTIFFIPTC", NULL }, + { TIFFTAG_PHOTOSHOP, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "Photoshop", NULL }, + { TIFFTAG_EXIFIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "EXIFIFDOffset", &exifFieldArray }, + { TIFFTAG_ICCPROFILE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ICC Profile", NULL }, + { TIFFTAG_GPSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "GPSIFDOffset", NULL }, + { TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvParams", NULL }, + { TIFFTAG_FAXSUBADDRESS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxSubAddress", NULL }, + { TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvTime", NULL }, + { TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxDcs", NULL }, + { TIFFTAG_STONITS, 1, 1, TIFF_DOUBLE, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "StoNits", NULL }, + { TIFFTAG_INTEROPERABILITYIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InteroperabilityIFDOffset", NULL }, + /* begin DNG tags */ + { TIFFTAG_DNGVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DNGVersion", NULL }, + { TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DNGBackwardVersion", NULL }, + { TIFFTAG_UNIQUECAMERAMODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "UniqueCameraModel", NULL }, + { TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "LocalizedCameraModel", NULL }, + { TIFFTAG_CFAPLANECOLOR, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CFAPlaneColor", NULL }, + { TIFFTAG_CFALAYOUT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CFALayout", NULL }, + { TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "LinearizationTable", NULL }, + { TIFFTAG_BLACKLEVELREPEATDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BlackLevelRepeatDim", NULL }, + { TIFFTAG_BLACKLEVEL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevel", NULL }, + { TIFFTAG_BLACKLEVELDELTAH, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevelDeltaH", NULL }, + { TIFFTAG_BLACKLEVELDELTAV, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevelDeltaV", NULL }, + { TIFFTAG_WHITELEVEL, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "WhiteLevel", NULL }, + { TIFFTAG_DEFAULTSCALE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultScale", NULL }, + { TIFFTAG_BESTQUALITYSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BestQualityScale", NULL }, + { TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultCropOrigin", NULL }, + { TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultCropSize", NULL }, + { TIFFTAG_COLORMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ColorMatrix1", NULL }, + { TIFFTAG_COLORMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ColorMatrix2", NULL }, + { TIFFTAG_CAMERACALIBRATION1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CameraCalibration1", NULL }, + { TIFFTAG_CAMERACALIBRATION2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CameraCalibration2", NULL }, + { TIFFTAG_REDUCTIONMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ReductionMatrix1", NULL }, + { TIFFTAG_REDUCTIONMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ReductionMatrix2", NULL }, + { TIFFTAG_ANALOGBALANCE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AnalogBalance", NULL }, + { TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotNeutral", NULL }, + { TIFFTAG_ASSHOTWHITEXY, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "AsShotWhiteXY", NULL }, + { TIFFTAG_BASELINEEXPOSURE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineExposure", NULL }, + { TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineNoise", NULL }, + { TIFFTAG_BASELINESHARPNESS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineSharpness", NULL }, + { TIFFTAG_BAYERGREENSPLIT, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BayerGreenSplit", NULL }, + { TIFFTAG_LINEARRESPONSELIMIT, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "LinearResponseLimit", NULL }, + { TIFFTAG_CAMERASERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CameraSerialNumber", NULL }, + { TIFFTAG_LENSINFO, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "LensInfo", NULL }, + { TIFFTAG_CHROMABLURRADIUS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ChromaBlurRadius", NULL }, + { TIFFTAG_ANTIALIASSTRENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "AntiAliasStrength", NULL }, + { TIFFTAG_SHADOWSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ShadowScale", NULL }, + { TIFFTAG_DNGPRIVATEDATA, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "DNGPrivateData", NULL }, + { TIFFTAG_MAKERNOTESAFETY, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "MakerNoteSafety", NULL }, + { TIFFTAG_CALIBRATIONILLUMINANT1, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CalibrationIlluminant1", NULL }, + { TIFFTAG_CALIBRATIONILLUMINANT2, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CalibrationIlluminant2", NULL }, + { TIFFTAG_RAWDATAUNIQUEID, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "RawDataUniqueID", NULL }, + { TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OriginalRawFileName", NULL }, + { TIFFTAG_ORIGINALRAWFILEDATA, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "OriginalRawFileData", NULL }, + { TIFFTAG_ACTIVEAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ActiveArea", NULL }, + { TIFFTAG_MASKEDAREAS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "MaskedAreas", NULL }, + { TIFFTAG_ASSHOTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotICCProfile", NULL }, + { TIFFTAG_ASSHOTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotPreProfileMatrix", NULL }, + { TIFFTAG_CURRENTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CurrentICCProfile", NULL }, + { TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CurrentPreProfileMatrix", NULL }, + { TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL}, + /* end DNG tags */ + /* begin TIFF/FX tags */ + { TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "Indexed" }, + { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "GlobalParametersIFD", NULL }, + { TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ProfileType", NULL }, + { TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "FaxProfile", NULL }, + { TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CodingMethods", NULL }, + { TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "VersionYear", NULL }, + { TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ModeNumber", NULL }, + { TIFFTAG_DECODE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "Decode", NULL }, + { TIFFTAG_IMAGEBASECOLOR, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ImageBaseColor", NULL }, + { TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "T82Options", NULL }, + { TIFFTAG_STRIPROWCOUNTS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "StripRowCounts", NULL }, + { TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ImageLayer", NULL }, + /* end DNG tags */ + /* begin pseudo tags */ +}; + +static TIFFField +exifFields[] = { + { EXIFTAG_EXPOSURETIME, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureTime", NULL }, + { EXIFTAG_FNUMBER, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FNumber", NULL }, + { EXIFTAG_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureProgram", NULL }, + { EXIFTAG_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SpectralSensitivity", NULL }, + { EXIFTAG_ISOSPEEDRATINGS, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ISOSpeedRatings", NULL }, + { EXIFTAG_OECF, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OptoelectricConversionFactor", NULL }, + { EXIFTAG_EXIFVERSION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExifVersion", NULL }, + { EXIFTAG_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTimeOriginal", NULL }, + { EXIFTAG_DATETIMEDIGITIZED, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTimeDigitized", NULL }, + { EXIFTAG_COMPONENTSCONFIGURATION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ComponentsConfiguration", NULL }, + { EXIFTAG_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CompressedBitsPerPixel", NULL }, + { EXIFTAG_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ShutterSpeedValue", NULL }, + { EXIFTAG_APERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ApertureValue", NULL }, + { EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BrightnessValue", NULL }, + { EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureBiasValue", NULL }, + { EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaxApertureValue", NULL }, + { EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistance", NULL }, + { EXIFTAG_METERINGMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MeteringMode", NULL }, + { EXIFTAG_LIGHTSOURCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LightSource", NULL }, + { EXIFTAG_FLASH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Flash", NULL }, + { EXIFTAG_FOCALLENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalLength", NULL }, + { EXIFTAG_SUBJECTAREA, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "SubjectArea", NULL }, + { EXIFTAG_MAKERNOTE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "MakerNote", NULL }, + { EXIFTAG_USERCOMMENT, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "UserComment", NULL }, + { EXIFTAG_SUBSECTIME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTime", NULL }, + { EXIFTAG_SUBSECTIMEORIGINAL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTimeOriginal", NULL }, + { EXIFTAG_SUBSECTIMEDIGITIZED, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTimeDigitized", NULL }, + { EXIFTAG_FLASHPIXVERSION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FlashpixVersion", NULL }, + { EXIFTAG_COLORSPACE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ColorSpace", NULL }, + { EXIFTAG_PIXELXDIMENSION, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PixelXDimension", NULL }, + { EXIFTAG_PIXELYDIMENSION, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PixelYDimension", NULL }, + { EXIFTAG_RELATEDSOUNDFILE, 13, 13, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RelatedSoundFile", NULL }, + { EXIFTAG_FLASHENERGY, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FlashEnergy", NULL }, + { EXIFTAG_SPATIALFREQUENCYRESPONSE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "SpatialFrequencyResponse", NULL }, + { EXIFTAG_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneXResolution", NULL }, + { EXIFTAG_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneYResolution", NULL }, + { EXIFTAG_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneResolutionUnit", NULL }, + { EXIFTAG_SUBJECTLOCATION, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectLocation", NULL }, + { EXIFTAG_EXPOSUREINDEX, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureIndex", NULL }, + { EXIFTAG_SENSINGMETHOD, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SensingMethod", NULL }, + { EXIFTAG_FILESOURCE, 1, 1, TIFF_UNDEFINED, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FileSource", NULL }, + { EXIFTAG_SCENETYPE, 1, 1, TIFF_UNDEFINED, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SceneType", NULL }, + { EXIFTAG_CFAPATTERN, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CFAPattern", NULL }, + { EXIFTAG_CUSTOMRENDERED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CustomRendered", NULL }, + { EXIFTAG_EXPOSUREMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureMode", NULL }, + { EXIFTAG_WHITEBALANCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "WhiteBalance", NULL }, + { EXIFTAG_DIGITALZOOMRATIO, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DigitalZoomRatio", NULL }, + { EXIFTAG_FOCALLENGTHIN35MMFILM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalLengthIn35mmFilm", NULL }, + { EXIFTAG_SCENECAPTURETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SceneCaptureType", NULL }, + { EXIFTAG_GAINCONTROL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "GainControl", NULL }, + { EXIFTAG_CONTRAST, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Contrast", NULL }, + { EXIFTAG_SATURATION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Saturation", NULL }, + { EXIFTAG_SHARPNESS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Sharpness", NULL }, + { EXIFTAG_DEVICESETTINGDESCRIPTION, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "DeviceSettingDescription", NULL }, + { EXIFTAG_SUBJECTDISTANCERANGE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistanceRange", NULL }, + { EXIFTAG_IMAGEUNIQUEID, 33, 33, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageUniqueID", NULL } +}; + +static TIFFFieldArray +tiffFieldArray = { tfiatImage, 0, TIFFArrayCount(tiffFields), tiffFields }; +static TIFFFieldArray +exifFieldArray = { tfiatExif, 0, TIFFArrayCount(exifFields), exifFields }; + +/* + * We have our own local lfind() equivelent to avoid subtle differences + * in types passed to lfind() on different systems. + */ + +static void * +td_lfind(const void *key, const void *base, size_t *nmemb, size_t size, + int(*compar)(const void *, const void *)) +{ + char *element, *end; + + end = (char *)base + *nmemb * size; + for (element = (char *)base; element < end; element += size) + if (!compar(key, element)) /* key found */ + return element; + + return NULL; +} + +const TIFFFieldArray* +_TIFFGetFields(void) +{ + return(&tiffFieldArray); +} + +const TIFFFieldArray* +_TIFFGetExifFields(void) +{ + return(&exifFieldArray); +} + +void +_TIFFSetupFields(TIFF* tif, const TIFFFieldArray* fieldarray) +{ + if (tif->tif_fields && tif->tif_nfields > 0) { + uint32 i; + + for (i = 0; i < tif->tif_nfields; i++) { + TIFFField *fld = tif->tif_fields[i]; + if (fld->field_bit == FIELD_CUSTOM && + strncmp("Tag ", fld->field_name, 4) == 0) { + _TIFFfree(fld->field_name); + _TIFFfree(fld); + } + } + + _TIFFfree(tif->tif_fields); + tif->tif_fields = NULL; + tif->tif_nfields = 0; + } + if (!_TIFFMergeFields(tif, fieldarray->fields, fieldarray->count)) { + TIFFErrorExt(tif->tif_clientdata, "_TIFFSetupFields", + "Setting up field info failed"); + } +} + +static int +tagCompare(const void* a, const void* b) +{ + const TIFFField* ta = *(const TIFFField**) a; + const TIFFField* tb = *(const TIFFField**) b; + /* NB: be careful of return values for 16-bit platforms */ + if (ta->field_tag != tb->field_tag) + return (int)ta->field_tag - (int)tb->field_tag; + else + return (ta->field_type == TIFF_ANY) ? + 0 : ((int)tb->field_type - (int)ta->field_type); +} + +static int +tagNameCompare(const void* a, const void* b) +{ + const TIFFField* ta = *(const TIFFField**) a; + const TIFFField* tb = *(const TIFFField**) b; + int ret = strcmp(ta->field_name, tb->field_name); + + if (ret) + return ret; + else + return (ta->field_type == TIFF_ANY) ? + 0 : ((int)tb->field_type - (int)ta->field_type); +} + +int +_TIFFMergeFields(TIFF* tif, const TIFFField info[], uint32 n) +{ + static const char module[] = "_TIFFMergeFields"; + static const char reason[] = "for fields array"; + /* TIFFField** tp; */ + uint32 i; + + tif->tif_foundfield = NULL; + + if (tif->tif_fields && tif->tif_nfields > 0) { + tif->tif_fields = (TIFFField**) + _TIFFCheckRealloc(tif, tif->tif_fields, + (tif->tif_nfields + n), + sizeof(TIFFField *), reason); + } else { + tif->tif_fields = (TIFFField **) + _TIFFCheckMalloc(tif, n, sizeof(TIFFField *), + reason); + } + if (!tif->tif_fields) { + TIFFErrorExt(tif->tif_clientdata, module, + "Failed to allocate fields array"); + return 0; + } + + /* tp = tif->tif_fields + tif->tif_nfields; */ + for (i = 0; i < n; i++) { + const TIFFField *fip = + TIFFFindField(tif, info[i].field_tag, TIFF_ANY); + + /* only add definitions that aren't already present */ + if (!fip) { + tif->tif_fields[tif->tif_nfields] = (TIFFField *) (info+i); + tif->tif_nfields++; + } + } + + /* Sort the field info by tag number */ + qsort(tif->tif_fields, tif->tif_nfields, + sizeof(TIFFField *), tagCompare); + + return n; +} + +void +_TIFFPrintFieldInfo(TIFF* tif, FILE* fd) +{ + uint32 i; + + fprintf(fd, "%s: \n", tif->tif_name); + for (i = 0; i < tif->tif_nfields; i++) { + const TIFFField* fip = tif->tif_fields[i]; + fprintf(fd, "field[%2d] %5lu, %2d, %2d, %d, %2d, %5s, %5s, %s\n" + , (int)i + , (unsigned long) fip->field_tag + , fip->field_readcount, fip->field_writecount + , fip->field_type + , fip->field_bit + , fip->field_oktochange ? "TRUE" : "FALSE" + , fip->field_passcount ? "TRUE" : "FALSE" + , fip->field_name + ); + } +} + +/* + * Return size of TIFFDataType in bytes + */ +int +TIFFDataWidth(TIFFDataType type) +{ + switch(type) + { + case 0: /* nothing */ + case TIFF_BYTE: + case TIFF_ASCII: + case TIFF_SBYTE: + case TIFF_UNDEFINED: + return 1; + case TIFF_SHORT: + case TIFF_SSHORT: + return 2; + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_FLOAT: + case TIFF_IFD: + return 4; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_DOUBLE: + case TIFF_LONG8: + case TIFF_SLONG8: + case TIFF_IFD8: + return 8; + default: + return 0; /* will return 0 for unknown types */ + } +} + +/* + * Return size of TIFFDataType in bytes. + * + * XXX: We need a separate function to determine the space needed + * to store the value. For TIFF_RATIONAL values TIFFDataWidth() returns 8, + * but we use 4-byte float to represent rationals. + */ +int +_TIFFDataSize(TIFFDataType type) +{ + switch (type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_ASCII: + case TIFF_UNDEFINED: + return 1; + case TIFF_SHORT: + case TIFF_SSHORT: + return 2; + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_FLOAT: + case TIFF_IFD: + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + return 4; + case TIFF_DOUBLE: + case TIFF_LONG8: + case TIFF_SLONG8: + case TIFF_IFD8: + return 8; + default: + return 0; + } +} + +/* Sync from 3.8.2's modified*/ +#ifdef _WIN32_WCE +void* wceex_bsearch(const void *key, const void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)); +#define bsearch wceex_bsearch +#endif + +const TIFFField* +TIFFFindField(TIFF* tif, uint32 tag, TIFFDataType dt) +{ + TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, 0, NULL, NULL}; + TIFFField* pkey = &key; + const TIFFField **ret; + if (tif->tif_foundfield && tif->tif_foundfield->field_tag == tag && + (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type)) + return tif->tif_foundfield; + + /* If we are invoked with no field information, then just return. */ + if (!tif->tif_fields) + return NULL; + + /* NB: use sorted search (e.g. binary search) */ + + key.field_tag = tag; + key.field_type = dt; + + ret = (const TIFFField **) bsearch(&pkey, tif->tif_fields, + tif->tif_nfields, + sizeof(TIFFField *), tagCompare); + return tif->tif_foundfield = (ret ? *ret : NULL); +} + +const TIFFField* +_TIFFFindFieldByName(TIFF* tif, const char *field_name, TIFFDataType dt) +{ + TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, 0, NULL, NULL}; + TIFFField* pkey = &key; + const TIFFField **ret; + if (tif->tif_foundfield + && streq(tif->tif_foundfield->field_name, field_name) + && (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type)) + return (tif->tif_foundfield); + + /* If we are invoked with no field information, then just return. */ + if (!tif->tif_fields) + return NULL; + + /* NB: use linear search since list is sorted by key#, not name */ + + key.field_name = (char *)field_name; + key.field_type = dt; + +#if 1 + ret = (const TIFFField **) + td_lfind(&pkey, tif->tif_fields, &tif->tif_nfields, + sizeof(TIFFField *), tagNameCompare); +#else + // from old svn version + /*ret = (const TIFFFieldInfo **) lfind(&pkey, + tif->tif_fieldinfo, + &tif->tif_nfields, + sizeof(TIFFFieldInfo *), + tagNameCompare); + */ + /*modify by Sunliang.Liu 20090827 for some platform not support lfind*/ + ret = NULL; +#endif + return tif->tif_foundfield = (ret ? *ret : NULL); +} + +const TIFFField* +TIFFFieldWithTag(TIFF* tif, uint32 tag) +{ + const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY); + if (!fip) { + TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithTag", + "Internal error, unknown tag 0x%x", + (unsigned int) tag); + } + return (fip); +} + +const TIFFField* +TIFFFieldWithName(TIFF* tif, const char *field_name) +{ + const TIFFField* fip = + _TIFFFindFieldByName(tif, field_name, TIFF_ANY); + if (!fip) { + TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithName", + "Internal error, unknown tag %s", field_name); + } + return (fip); +} + +uint32 +TIFFFieldTag(const TIFFField* fip) +{ + return fip->field_tag; +} + +const char * +TIFFFieldName(const TIFFField* fip) +{ + return fip->field_name; +} + +TIFFDataType +TIFFFieldDataType(const TIFFField* fip) +{ + return fip->field_type; +} + +int +TIFFFieldPassCount(const TIFFField* fip) +{ + return fip->field_passcount; +} + +int +TIFFFieldReadCount(const TIFFField* fip) +{ + return fip->field_readcount; +} + +int +TIFFFieldWriteCount(const TIFFField* fip) +{ + return fip->field_writecount; +} + +const TIFFField* +_TIFFFindOrRegisterField(TIFF *tif, uint32 tag, TIFFDataType dt) + +{ + const TIFFField *fld; + + fld = TIFFFindField(tif, tag, dt); + if (fld == NULL) { + fld = _TIFFCreateAnonField(tif, tag, dt); + if (!_TIFFMergeFields(tif, fld, 1)) + return NULL; + } + + return fld; +} + +TIFFField* +_TIFFCreateAnonField(TIFF *tif, uint32 tag, TIFFDataType field_type) +{ + TIFFField *fld; + (void) tif; + + fld = (TIFFField *) _TIFFmalloc(sizeof (TIFFField)); + if (fld == NULL) + return NULL; + _TIFFmemset(fld, 0, sizeof(TIFFField)); + + fld->field_tag = tag; + fld->field_readcount = TIFF_VARIABLE2; + fld->field_writecount = TIFF_VARIABLE2; + fld->field_type = field_type; + fld->reserved = 0; + switch (field_type) + { + case TIFF_BYTE: + case TIFF_UNDEFINED: + fld->set_field_type = TIFF_SETGET_C32_UINT8; + fld->get_field_type = TIFF_SETGET_C32_UINT8; + break; + case TIFF_ASCII: + fld->set_field_type = TIFF_SETGET_C32_ASCII; + fld->get_field_type = TIFF_SETGET_C32_ASCII; + break; + case TIFF_SHORT: + fld->set_field_type = TIFF_SETGET_C32_UINT16; + fld->get_field_type = TIFF_SETGET_C32_UINT16; + break; + case TIFF_LONG: + fld->set_field_type = TIFF_SETGET_C32_UINT32; + fld->get_field_type = TIFF_SETGET_C32_UINT32; + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + fld->set_field_type = TIFF_SETGET_C32_FLOAT; + fld->get_field_type = TIFF_SETGET_C32_FLOAT; + break; + case TIFF_SBYTE: + fld->set_field_type = TIFF_SETGET_C32_SINT8; + fld->get_field_type = TIFF_SETGET_C32_SINT8; + break; + case TIFF_SSHORT: + fld->set_field_type = TIFF_SETGET_C32_SINT16; + fld->get_field_type = TIFF_SETGET_C32_SINT16; + break; + case TIFF_SLONG: + fld->set_field_type = TIFF_SETGET_C32_SINT32; + fld->get_field_type = TIFF_SETGET_C32_SINT32; + break; + case TIFF_DOUBLE: + fld->set_field_type = TIFF_SETGET_C32_DOUBLE; + fld->get_field_type = TIFF_SETGET_C32_DOUBLE; + break; + case TIFF_IFD: + case TIFF_IFD8: + fld->set_field_type = TIFF_SETGET_C32_IFD8; + fld->get_field_type = TIFF_SETGET_C32_IFD8; + break; + case TIFF_LONG8: + fld->set_field_type = TIFF_SETGET_C32_UINT64; + fld->get_field_type = TIFF_SETGET_C32_UINT64; + break; + case TIFF_SLONG8: + fld->set_field_type = TIFF_SETGET_C32_SINT64; + fld->get_field_type = TIFF_SETGET_C32_SINT64; + break; + default: + fld->set_field_type = TIFF_SETGET_UNDEFINED; + fld->get_field_type = TIFF_SETGET_UNDEFINED; + break; + } + fld->field_bit = FIELD_CUSTOM; + fld->field_oktochange = TRUE; + fld->field_passcount = TRUE; + fld->field_name = (char *) _TIFFmalloc(32); + if (fld->field_name == NULL) { + _TIFFfree(fld); + return NULL; + } + fld->field_subfields = NULL; + + /* + * note that this name is a special sign to TIFFClose() and + * _TIFFSetupFields() to free the field + */ + sprintf(fld->field_name, "Tag %d", (int) tag); + + return fld; +} + +/**************************************************************************** + * O B S O L E T E D I N T E R F A C E S + * + * Don't use this stuff in your applications, it may be removed in the future + * libtiff versions. + ****************************************************************************/ + +static TIFFSetGetFieldType +_TIFFSetGetType(TIFFDataType type, short count, unsigned char passcount) +{ + if (type == TIFF_ASCII && count == TIFF_VARIABLE && passcount == 0) + return TIFF_SETGET_ASCII; + + else if (count == 1 && passcount == 0) { + switch (type) + { + case TIFF_BYTE: + case TIFF_UNDEFINED: + return TIFF_SETGET_UINT8; + case TIFF_ASCII: + return TIFF_SETGET_ASCII; + case TIFF_SHORT: + return TIFF_SETGET_UINT16; + case TIFF_LONG: + return TIFF_SETGET_UINT32; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + return TIFF_SETGET_FLOAT; + case TIFF_SBYTE: + return TIFF_SETGET_SINT8; + case TIFF_SSHORT: + return TIFF_SETGET_SINT16; + case TIFF_SLONG: + return TIFF_SETGET_SINT32; + case TIFF_DOUBLE: + return TIFF_SETGET_DOUBLE; + case TIFF_IFD: + case TIFF_IFD8: + return TIFF_SETGET_IFD8; + case TIFF_LONG8: + return TIFF_SETGET_UINT64; + case TIFF_SLONG8: + return TIFF_SETGET_SINT64; + default: + return TIFF_SETGET_UNDEFINED; + } + } + + else if (count >= 1 && passcount == 0) { + switch (type) + { + case TIFF_BYTE: + case TIFF_UNDEFINED: + return TIFF_SETGET_C0_UINT8; + case TIFF_ASCII: + return TIFF_SETGET_C0_ASCII; + case TIFF_SHORT: + return TIFF_SETGET_C0_UINT16; + case TIFF_LONG: + return TIFF_SETGET_C0_UINT32; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + return TIFF_SETGET_C0_FLOAT; + case TIFF_SBYTE: + return TIFF_SETGET_C0_SINT8; + case TIFF_SSHORT: + return TIFF_SETGET_C0_SINT16; + case TIFF_SLONG: + return TIFF_SETGET_C0_SINT32; + case TIFF_DOUBLE: + return TIFF_SETGET_C0_DOUBLE; + case TIFF_IFD: + case TIFF_IFD8: + return TIFF_SETGET_C0_IFD8; + case TIFF_LONG8: + return TIFF_SETGET_C0_UINT64; + case TIFF_SLONG8: + return TIFF_SETGET_C0_SINT64; + default: + return TIFF_SETGET_UNDEFINED; + } + } + + else if (count == TIFF_VARIABLE && passcount == 1) { + switch (type) + { + case TIFF_BYTE: + case TIFF_UNDEFINED: + return TIFF_SETGET_C16_UINT8; + case TIFF_ASCII: + return TIFF_SETGET_C16_ASCII; + case TIFF_SHORT: + return TIFF_SETGET_C16_UINT16; + case TIFF_LONG: + return TIFF_SETGET_C16_UINT32; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + return TIFF_SETGET_C16_FLOAT; + case TIFF_SBYTE: + return TIFF_SETGET_C16_SINT8; + case TIFF_SSHORT: + return TIFF_SETGET_C16_SINT16; + case TIFF_SLONG: + return TIFF_SETGET_C16_SINT32; + case TIFF_DOUBLE: + return TIFF_SETGET_C16_DOUBLE; + case TIFF_IFD: + case TIFF_IFD8: + return TIFF_SETGET_C16_IFD8; + case TIFF_LONG8: + return TIFF_SETGET_C16_UINT64; + case TIFF_SLONG8: + return TIFF_SETGET_C16_SINT64; + default: + return TIFF_SETGET_UNDEFINED; + } + } + + else if (count == TIFF_VARIABLE2 && passcount == 1) { + switch (type) + { + case TIFF_BYTE: + case TIFF_UNDEFINED: + return TIFF_SETGET_C32_UINT8; + case TIFF_ASCII: + return TIFF_SETGET_C32_ASCII; + case TIFF_SHORT: + return TIFF_SETGET_C32_UINT16; + case TIFF_LONG: + return TIFF_SETGET_C32_UINT32; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + return TIFF_SETGET_C32_FLOAT; + case TIFF_SBYTE: + return TIFF_SETGET_C32_SINT8; + case TIFF_SSHORT: + return TIFF_SETGET_C32_SINT16; + case TIFF_SLONG: + return TIFF_SETGET_C32_SINT32; + case TIFF_DOUBLE: + return TIFF_SETGET_C32_DOUBLE; + case TIFF_IFD: + case TIFF_IFD8: + return TIFF_SETGET_C32_IFD8; + case TIFF_LONG8: + return TIFF_SETGET_C32_UINT64; + case TIFF_SLONG8: + return TIFF_SETGET_C32_SINT64; + default: + return TIFF_SETGET_UNDEFINED; + } + } + + return TIFF_SETGET_UNDEFINED; +} + +int +TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], uint32 n) +{ + static const char module[] = "TIFFMergeFieldInfo"; + static const char reason[] = "for fields array"; + TIFFField *tp; + size_t nfields; + uint32 i; + + if (tif->tif_nfieldscompat > 0) { + tif->tif_fieldscompat = (TIFFFieldArray *) + _TIFFCheckRealloc(tif, tif->tif_fieldscompat, + tif->tif_nfieldscompat + 1, + sizeof(TIFFFieldArray), reason); + } else { + tif->tif_fieldscompat = (TIFFFieldArray *) + _TIFFCheckMalloc(tif, 1, sizeof(TIFFFieldArray), + reason); + } + if (!tif->tif_fieldscompat) { + TIFFErrorExt(tif->tif_clientdata, module, + "Failed to allocate fields array"); + return -1; + } + nfields = tif->tif_nfieldscompat++; + + tif->tif_fieldscompat[nfields].type = tfiatOther; + tif->tif_fieldscompat[nfields].allocated_size = n; + tif->tif_fieldscompat[nfields].count = n; + tif->tif_fieldscompat[nfields].fields = + (TIFFField *)_TIFFCheckMalloc(tif, n, sizeof(TIFFField), + reason); + if (!tif->tif_fieldscompat[nfields].fields) { + TIFFErrorExt(tif->tif_clientdata, module, + "Failed to allocate fields array"); + return -1; + } + + tp = tif->tif_fieldscompat[nfields].fields; + for (i = 0; i < n; i++) { + tp->field_tag = info[i].field_tag; + tp->field_readcount = info[i].field_readcount; + tp->field_writecount = info[i].field_writecount; + tp->field_type = info[i].field_type; + tp->reserved = 0; + tp->set_field_type = + _TIFFSetGetType(info[i].field_type, + info[i].field_readcount, + info[i].field_passcount); + tp->get_field_type = + _TIFFSetGetType(info[i].field_type, + info[i].field_readcount, + info[i].field_passcount); + tp->field_bit = info[i].field_bit; + tp->field_oktochange = info[i].field_oktochange; + tp->field_passcount = info[i].field_passcount; + tp->field_name = info[i].field_name; + tp->field_subfields = NULL; + tp++; + } + + if (!_TIFFMergeFields(tif, tif->tif_fieldscompat[nfields].fields, n)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Setting up field info failed"); + return -1; + } + + return 0; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirread.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirread.c new file mode 100644 index 0000000000..bd28d6926d --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirread.c @@ -0,0 +1,5616 @@ +/* $Id: tif_dirread.c,v 1.178 2012-08-19 16:56:34 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Read Support Routines. + */ + +/* Suggested pending improvements: + * - add a field 'ignore' to the TIFFDirEntry structure, to flag status, + * eliminating current use of the IGNORE value, and therefore eliminating + * current irrational behaviour on tags with tag id code 0 + * - add a field 'field_info' to the TIFFDirEntry structure, and set that with + * the pointer to the appropriate TIFFField structure early on in + * TIFFReadDirectory, so as to eliminate current possibly repetitive lookup. + */ + +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +#define IGNORE 0 /* tag placeholder used below */ +#define FAILED_FII ((uint32) -1) + +#ifdef HAVE_IEEEFP +# define TIFFCvtIEEEFloatToNative(tif, n, fp) +# define TIFFCvtIEEEDoubleToNative(tif, n, dp) +#else +extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32, float*); +extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32, double*); +#endif + +enum TIFFReadDirEntryErr { + TIFFReadDirEntryErrOk = 0, + TIFFReadDirEntryErrCount = 1, + TIFFReadDirEntryErrType = 2, + TIFFReadDirEntryErrIo = 3, + TIFFReadDirEntryErrRange = 4, + TIFFReadDirEntryErrPsdif = 5, + TIFFReadDirEntryErrSizesan = 6, + TIFFReadDirEntryErrAlloc = 7, +}; + +static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryFloat(TIFF* tif, TIFFDirEntry* direntry, float* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryDouble(TIFF* tif, TIFFDirEntry* direntry, double* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8(TIFF* tif, TIFFDirEntry* direntry, uint64* value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEntry* direntry, float** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryDoubleArray(TIFF* tif, TIFFDirEntry* direntry, double** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value); +#if 0 +static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value); +#endif + +static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value); +static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8* value); +static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value); +static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16* value); +static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value); +static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSlong8(TIFF* tif, TIFFDirEntry* direntry, int64* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSrational(TIFF* tif, TIFFDirEntry* direntry, double* value); +static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64 value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64 value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64 value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64 value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongLong8(uint64 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong8(int64 value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong(uint32 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong8(uint64 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongSlong8(int64 value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sbyte(int8 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sshort(int16 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong(int32 value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong8(int64 value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryData(TIFF* tif, uint64 offset, tmsize_t size, void* dest); +static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, const char* module, const char* tagname, int recover); + +static void TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16 dircount); +static TIFFDirEntry* TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16 dircount, uint16 tagid); +static void TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16 tagid, uint32* fii); + +static int EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount); +static void MissingRequired(TIFF*, const char*); +static int TIFFCheckDirOffset(TIFF* tif, uint64 diroff); +static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32); +static uint16 TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir, uint64* nextdiroff); +static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*, int recover); +static int TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp); +static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*); +static void ChopUpSingleUncompressedStrip(TIFF*); +static uint64 TIFFReadUInt64(const uint8 *value); + +typedef union _UInt64Aligned_t +{ + double d; + uint64 l; + uint32 i[2]; + uint16 s[4]; + uint8 c[8]; +} UInt64Aligned_t; + +/* + Unaligned safe copy of a uint64 value from an octet array. +*/ +static uint64 TIFFReadUInt64(const uint8 *value) +{ + UInt64Aligned_t result; + + result.c[0]=value[0]; + result.c[1]=value[1]; + result.c[2]=value[2]; + result.c[3]=value[3]; + result.c[4]=value[4]; + result.c[5]=value[5]; + result.c[6]=value[6]; + result.c[7]=value[7]; + + return result.l; +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + TIFFReadDirEntryCheckedByte(tif,direntry,value); + return(TIFFReadDirEntryErrOk); + case TIFF_SBYTE: + { + int8 m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeByteSbyte(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16 m; + TIFFReadDirEntryCheckedShort(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeByteShort(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16 m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeByteSshort(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32 m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeByteLong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32 m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeByteSlong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64 m; + err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeByteLong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64 m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeByteSlong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8)m; + return(TIFFReadDirEntryErrOk); + } + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8 m; + TIFFReadDirEntryCheckedByte(tif,direntry,&m); + *value=(uint16)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8 m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeShortSbyte(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + TIFFReadDirEntryCheckedShort(tif,direntry,value); + return(TIFFReadDirEntryErrOk); + case TIFF_SSHORT: + { + int16 m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeShortSshort(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32 m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeShortLong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32 m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeShortSlong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64 m; + err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeShortLong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64 m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeShortSlong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16)m; + return(TIFFReadDirEntryErrOk); + } + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8 m; + TIFFReadDirEntryCheckedByte(tif,direntry,&m); + *value=(uint32)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8 m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLongSbyte(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint32)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16 m; + TIFFReadDirEntryCheckedShort(tif,direntry,&m); + *value=(uint32)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16 m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLongSshort(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint32)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + TIFFReadDirEntryCheckedLong(tif,direntry,value); + return(TIFFReadDirEntryErrOk); + case TIFF_SLONG: + { + int32 m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLongSlong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint32)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64 m; + err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeLongLong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint32)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64 m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeLongSlong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint32)m; + return(TIFFReadDirEntryErrOk); + } + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8 m; + TIFFReadDirEntryCheckedByte(tif,direntry,&m); + *value=(uint64)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8 m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLong8Sbyte(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint64)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16 m; + TIFFReadDirEntryCheckedShort(tif,direntry,&m); + *value=(uint64)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16 m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLong8Sshort(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint64)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32 m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + *value=(uint64)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32 m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLong8Slong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint64)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + err=TIFFReadDirEntryCheckedLong8(tif,direntry,value); + return(err); + case TIFF_SLONG8: + { + int64 m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeLong8Slong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint64)m; + return(TIFFReadDirEntryErrOk); + } + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryFloat(TIFF* tif, TIFFDirEntry* direntry, float* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8 m; + TIFFReadDirEntryCheckedByte(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8 m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16 m; + TIFFReadDirEntryCheckedShort(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16 m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32 m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32 m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64 m; + err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); +#if defined(__WIN32__) && (_MSC_VER < 1500) + /* + * XXX: MSVC 6.0 does not support conversion + * of 64-bit integers into floating point + * values. + */ + *value = _TIFFUInt64ToFloat(m); +#else + *value=(float)m; +#endif + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64 m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_RATIONAL: + { + double m; + err=TIFFReadDirEntryCheckedRational(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SRATIONAL: + { + double m; + err=TIFFReadDirEntryCheckedSrational(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_FLOAT: + TIFFReadDirEntryCheckedFloat(tif,direntry,value); + return(TIFFReadDirEntryErrOk); + case TIFF_DOUBLE: + { + double m; + err=TIFFReadDirEntryCheckedDouble(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryDouble(TIFF* tif, TIFFDirEntry* direntry, double* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8 m; + TIFFReadDirEntryCheckedByte(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8 m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16 m; + TIFFReadDirEntryCheckedShort(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16 m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32 m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32 m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64 m; + err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); +#if defined(__WIN32__) && (_MSC_VER < 1500) + /* + * XXX: MSVC 6.0 does not support conversion + * of 64-bit integers into floating point + * values. + */ + *value = _TIFFUInt64ToDouble(m); +#else + *value = (double)m; +#endif + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64 m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_RATIONAL: + err=TIFFReadDirEntryCheckedRational(tif,direntry,value); + return(err); + case TIFF_SRATIONAL: + err=TIFFReadDirEntryCheckedSrational(tif,direntry,value); + return(err); + case TIFF_FLOAT: + { + float m; + TIFFReadDirEntryCheckedFloat(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_DOUBLE: + err=TIFFReadDirEntryCheckedDouble(tif,direntry,value); + return(err); + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8(TIFF* tif, TIFFDirEntry* direntry, uint64* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_LONG: + case TIFF_IFD: + { + uint32 m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + *value=(uint64)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + case TIFF_IFD8: + err=TIFFReadDirEntryCheckedLong8(tif,direntry,value); + return(err); + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value) +{ + int typesize; + uint32 datasize; + void* data; + typesize=TIFFDataWidth(direntry->tdir_type); + if ((direntry->tdir_count==0)||(typesize==0)) + { + *value=0; + return(TIFFReadDirEntryErrOk); + } + (void) desttypesize; + + /* + * As a sanity check, make sure we have no more than a 2GB tag array + * in either the current data type or the dest data type. This also + * avoids problems with overflow of tmsize_t on 32bit systems. + */ + if ((uint64)(2147483647/typesize)tdir_count) + return(TIFFReadDirEntryErrSizesan); + if ((uint64)(2147483647/desttypesize)tdir_count) + return(TIFFReadDirEntryErrSizesan); + + *count=(uint32)direntry->tdir_count; + datasize=(*count)*typesize; + assert((tmsize_t)datasize>0); + data=_TIFFCheckMalloc(tif, *count, typesize, "ReadDirEntryArray"); + if (data==0) + return(TIFFReadDirEntryErrAlloc); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if (datasize<=4) + _TIFFmemcpy(data,&direntry->tdir_offset,datasize); + else + { + enum TIFFReadDirEntryErr err; + uint32 offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,(uint64)offset,(tmsize_t)datasize,data); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + } + } + else + { + if (datasize<=8) + _TIFFmemcpy(data,&direntry->tdir_offset,datasize); + else + { + enum TIFFReadDirEntryErr err; + uint64 offset = direntry->tdir_offset.toff_long8; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(&offset); + err=TIFFReadDirEntryData(tif,offset,(tmsize_t)datasize,data); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + } + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value) +{ + enum TIFFReadDirEntryErr err; + uint32 count; + void* origdata; + uint8* data; + switch (direntry->tdir_type) + { + case TIFF_ASCII: + case TIFF_UNDEFINED: + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,1,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_ASCII: + case TIFF_UNDEFINED: + case TIFF_BYTE: + *value=(uint8*)origdata; + return(TIFFReadDirEntryErrOk); + case TIFF_SBYTE: + { + int8* m; + uint32 n; + m=(int8*)origdata; + for (n=0; ntdir_type) + { + case TIFF_SHORT: + { + uint16* ma; + uint8* mb; + uint32 n; + ma=(uint16*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + err=TIFFReadDirEntryCheckRangeByteShort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16* ma; + uint8* mb; + uint32 n; + ma=(int16*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)ma); + err=TIFFReadDirEntryCheckRangeByteSshort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32* ma; + uint8* mb; + uint32 n; + ma=(uint32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + err=TIFFReadDirEntryCheckRangeByteLong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32* ma; + uint8* mb; + uint32 n; + ma=(int32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)ma); + err=TIFFReadDirEntryCheckRangeByteSlong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64* ma; + uint8* mb; + uint32 n; + ma=(uint64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeByteLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64* ma; + uint8* mb; + uint32 n; + ma=(int64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)ma); + err=TIFFReadDirEntryCheckRangeByteSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8** value) +{ + enum TIFFReadDirEntryErr err; + uint32 count; + void* origdata; + int8* data; + switch (direntry->tdir_type) + { + case TIFF_UNDEFINED: + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,1,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_UNDEFINED: + case TIFF_BYTE: + { + uint8* m; + uint32 n; + m=(uint8*)origdata; + for (n=0; ntdir_type) + { + case TIFF_SHORT: + { + uint16* ma; + int8* mb; + uint32 n; + ma=(uint16*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + err=TIFFReadDirEntryCheckRangeSbyteShort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16* ma; + int8* mb; + uint32 n; + ma=(int16*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)ma); + err=TIFFReadDirEntryCheckRangeSbyteSshort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32* ma; + int8* mb; + uint32 n; + ma=(uint32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + err=TIFFReadDirEntryCheckRangeSbyteLong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32* ma; + int8* mb; + uint32 n; + ma=(int32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)ma); + err=TIFFReadDirEntryCheckRangeSbyteSlong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64* ma; + int8* mb; + uint32 n; + ma=(uint64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeSbyteLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64* ma; + int8* mb; + uint32 n; + ma=(int64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)ma); + err=TIFFReadDirEntryCheckRangeSbyteSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16** value) +{ + enum TIFFReadDirEntryErr err; + uint32 count; + void* origdata; + uint16* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,2,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_SHORT: + *value=(uint16*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfShort(*value,count); + return(TIFFReadDirEntryErrOk); + case TIFF_SSHORT: + { + int16* m; + uint32 n; + m=(int16*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)m); + err=TIFFReadDirEntryCheckRangeShortSshort(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(uint16*)origdata; + return(TIFFReadDirEntryErrOk); + } + } + data=(uint16*)_TIFFmalloc(count*2); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8* ma; + uint16* mb; + uint32 n; + ma=(uint8*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + err=TIFFReadDirEntryCheckRangeShortLong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint16)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32* ma; + uint16* mb; + uint32 n; + ma=(int32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)ma); + err=TIFFReadDirEntryCheckRangeShortSlong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint16)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64* ma; + uint16* mb; + uint32 n; + ma=(uint64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeShortLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint16)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64* ma; + uint16* mb; + uint32 n; + ma=(int64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)ma); + err=TIFFReadDirEntryCheckRangeShortSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint16)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16** value) +{ + enum TIFFReadDirEntryErr err; + uint32 count; + void* origdata; + int16* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,2,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_SHORT: + { + uint16* m; + uint32 n; + m=(uint16*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(m); + err=TIFFReadDirEntryCheckRangeSshortShort(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(int16*)origdata; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + *value=(int16*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfShort((uint16*)(*value),count); + return(TIFFReadDirEntryErrOk); + } + data=(int16*)_TIFFmalloc(count*2); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8* ma; + int16* mb; + uint32 n; + ma=(uint8*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + err=TIFFReadDirEntryCheckRangeSshortLong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int16)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32* ma; + int16* mb; + uint32 n; + ma=(int32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)ma); + err=TIFFReadDirEntryCheckRangeSshortSlong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int16)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64* ma; + int16* mb; + uint32 n; + ma=(uint64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeSshortLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int16)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64* ma; + int16* mb; + uint32 n; + ma=(int64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)ma); + err=TIFFReadDirEntryCheckRangeSshortSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int16)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32** value) +{ + enum TIFFReadDirEntryErr err; + uint32 count; + void* origdata; + uint32* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_LONG: + *value=(uint32*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(*value,count); + return(TIFFReadDirEntryErrOk); + case TIFF_SLONG: + { + int32* m; + uint32 n; + m=(int32*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)m); + err=TIFFReadDirEntryCheckRangeLongSlong(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(uint32*)origdata; + return(TIFFReadDirEntryErrOk); + } + } + data=(uint32*)_TIFFmalloc(count*4); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8* ma; + uint32* mb; + uint32 n; + ma=(uint8*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(uint32)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16* ma; + uint32* mb; + uint32 n; + ma=(int16*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)ma); + err=TIFFReadDirEntryCheckRangeLongSshort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint32)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64* ma; + uint32* mb; + uint32 n; + ma=(uint64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeLongLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint32)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64* ma; + uint32* mb; + uint32 n; + ma=(int64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)ma); + err=TIFFReadDirEntryCheckRangeLongSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint32)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32** value) +{ + enum TIFFReadDirEntryErr err; + uint32 count; + void* origdata; + int32* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_LONG: + { + uint32* m; + uint32 n; + m=(uint32*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)m); + err=TIFFReadDirEntryCheckRangeSlongLong(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(int32*)origdata; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + *value=(int32*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong((uint32*)(*value),count); + return(TIFFReadDirEntryErrOk); + } + data=(int32*)_TIFFmalloc(count*4); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8* ma; + int32* mb; + uint32 n; + ma=(uint8*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(int32)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16* ma; + int32* mb; + uint32 n; + ma=(int16*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)ma); + *mb++=(int32)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64* ma; + int32* mb; + uint32 n; + ma=(uint64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeSlongLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int32)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64* ma; + int32* mb; + uint32 n; + ma=(int64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)ma); + err=TIFFReadDirEntryCheckRangeSlongSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int32)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value) +{ + enum TIFFReadDirEntryErr err; + uint32 count; + void* origdata; + uint64* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_LONG8: + *value=(uint64*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8(*value,count); + return(TIFFReadDirEntryErrOk); + case TIFF_SLONG8: + { + int64* m; + uint32 n; + m=(int64*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)m); + err=TIFFReadDirEntryCheckRangeLong8Slong8(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(uint64*)origdata; + return(TIFFReadDirEntryErrOk); + } + } + data=(uint64*)_TIFFmalloc(count*8); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8* ma; + uint64* mb; + uint32 n; + ma=(uint8*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(uint64)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16* ma; + uint64* mb; + uint32 n; + ma=(int16*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)ma); + err=TIFFReadDirEntryCheckRangeLong8Sshort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint64)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32* ma; + uint64* mb; + uint32 n; + ma=(uint32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + *mb++=(uint64)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32* ma; + uint64* mb; + uint32 n; + ma=(int32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)ma); + err=TIFFReadDirEntryCheckRangeLong8Slong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint64)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** value) +{ + enum TIFFReadDirEntryErr err; + uint32 count; + void* origdata; + int64* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_LONG8: + { + uint64* m; + uint32 n; + m=(uint64*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(m); + err=TIFFReadDirEntryCheckRangeSlong8Long8(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(int64*)origdata; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + *value=(int64*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8((uint64*)(*value),count); + return(TIFFReadDirEntryErrOk); + } + data=(int64*)_TIFFmalloc(count*8); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8* ma; + int64* mb; + uint32 n; + ma=(uint8*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(int64)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16* ma; + int64* mb; + uint32 n; + ma=(int16*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)ma); + *mb++=(int64)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32* ma; + int64* mb; + uint32 n; + ma=(uint32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + *mb++=(int64)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32* ma; + int64* mb; + uint32 n; + ma=(int32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)ma); + *mb++=(int64)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEntry* direntry, float** value) +{ + enum TIFFReadDirEntryErr err; + uint32 count; + void* origdata; + float* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + case TIFF_DOUBLE: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_FLOAT: + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong((uint32*)origdata,count); + TIFFCvtIEEEDoubleToNative(tif,count,(float*)origdata); + *value=(float*)origdata; + return(TIFFReadDirEntryErrOk); + } + data=(float*)_TIFFmalloc(count*sizeof(float)); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8* ma; + float* mb; + uint32 n; + ma=(uint8*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(float)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16* ma; + float* mb; + uint32 n; + ma=(int16*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)ma); + *mb++=(float)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32* ma; + float* mb; + uint32 n; + ma=(uint32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + *mb++=(float)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32* ma; + float* mb; + uint32 n; + ma=(int32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)ma); + *mb++=(float)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64* ma; + float* mb; + uint32 n; + ma=(uint64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); +#if defined(__WIN32__) && (_MSC_VER < 1500) + /* + * XXX: MSVC 6.0 does not support + * conversion of 64-bit integers into + * floating point values. + */ + *mb++ = _TIFFUInt64ToFloat(*ma++); +#else + *mb++ = (float)(*ma++); +#endif + } + } + break; + case TIFF_SLONG8: + { + int64* ma; + float* mb; + uint32 n; + ma=(int64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)ma); + *mb++=(float)(*ma++); + } + } + break; + case TIFF_RATIONAL: + { + uint32* ma; + uint32 maa; + uint32 mab; + float* mb; + uint32 n; + ma=(uint32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + maa=*ma++; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + mab=*ma++; + if (mab==0) + *mb++=0.0; + else + *mb++=(float)maa/(float)mab; + } + } + break; + case TIFF_SRATIONAL: + { + uint32* ma; + int32 maa; + uint32 mab; + float* mb; + uint32 n; + ma=(uint32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + maa=*(int32*)ma; + ma++; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + mab=*ma++; + if (mab==0) + *mb++=0.0; + else + *mb++=(float)maa/(float)mab; + } + } + break; + case TIFF_DOUBLE: + { + double* ma; + float* mb; + uint32 n; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8((uint64*)origdata,count); + TIFFCvtIEEEDoubleToNative(tif,count,(double*)origdata); + ma=(double*)origdata; + mb=data; + for (n=0; ntdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + case TIFF_DOUBLE: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_DOUBLE: + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8((uint64*)origdata,count); + TIFFCvtIEEEDoubleToNative(tif,count,(double*)origdata); + *value=(double*)origdata; + return(TIFFReadDirEntryErrOk); + } + data=(double*)_TIFFmalloc(count*sizeof(double)); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8* ma; + double* mb; + uint32 n; + ma=(uint8*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(double)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16* ma; + double* mb; + uint32 n; + ma=(int16*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)ma); + *mb++=(double)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32* ma; + double* mb; + uint32 n; + ma=(uint32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + *mb++=(double)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32* ma; + double* mb; + uint32 n; + ma=(int32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)ma); + *mb++=(double)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64* ma; + double* mb; + uint32 n; + ma=(uint64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); +#if defined(__WIN32__) && (_MSC_VER < 1500) + /* + * XXX: MSVC 6.0 does not support + * conversion of 64-bit integers into + * floating point values. + */ + *mb++ = _TIFFUInt64ToDouble(*ma++); +#else + *mb++ = (double)(*ma++); +#endif + } + } + break; + case TIFF_SLONG8: + { + int64* ma; + double* mb; + uint32 n; + ma=(int64*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)ma); + *mb++=(double)(*ma++); + } + } + break; + case TIFF_RATIONAL: + { + uint32* ma; + uint32 maa; + uint32 mab; + double* mb; + uint32 n; + ma=(uint32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + maa=*ma++; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + mab=*ma++; + if (mab==0) + *mb++=0.0; + else + *mb++=(double)maa/(double)mab; + } + } + break; + case TIFF_SRATIONAL: + { + uint32* ma; + int32 maa; + uint32 mab; + double* mb; + uint32 n; + ma=(uint32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + maa=*(int32*)ma; + ma++; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + mab=*ma++; + if (mab==0) + *mb++=0.0; + else + *mb++=(double)maa/(double)mab; + } + } + break; + case TIFF_FLOAT: + { + float* ma; + double* mb; + uint32 n; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong((uint32*)origdata,count); + TIFFCvtIEEEFloatToNative(tif,count,(float*)origdata); + ma=(float*)origdata; + mb=data; + for (n=0; ntdir_type) + { + case TIFF_LONG: + case TIFF_LONG8: + case TIFF_IFD: + case TIFF_IFD8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_LONG8: + case TIFF_IFD8: + *value=(uint64*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8(*value,count); + return(TIFFReadDirEntryErrOk); + } + data=(uint64*)_TIFFmalloc(count*8); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_LONG: + case TIFF_IFD: + { + uint32* ma; + uint64* mb; + uint32 n; + ma=(uint32*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + *mb++=(uint64)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value) +{ + enum TIFFReadDirEntryErr err; + uint16* m; + uint16* na; + uint16 nb; + if (direntry->tdir_count<(uint64)tif->tif_dir.td_samplesperpixel) + return(TIFFReadDirEntryErrCount); + err=TIFFReadDirEntryShortArray(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + na=m; + nb=tif->tif_dir.td_samplesperpixel; + *value=*na++; + nb--; + while (nb>0) + { + if (*na++!=*value) + { + err=TIFFReadDirEntryErrPsdif; + break; + } + nb--; + } + _TIFFfree(m); + return(err); +} + +#if 0 +static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value) +{ + enum TIFFReadDirEntryErr err; + double* m; + double* na; + uint16 nb; + if (direntry->tdir_count<(uint64)tif->tif_dir.td_samplesperpixel) + return(TIFFReadDirEntryErrCount); + err=TIFFReadDirEntryDoubleArray(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + na=m; + nb=tif->tif_dir.td_samplesperpixel; + *value=*na++; + nb--; + while (nb>0) + { + if (*na++!=*value) + { + err=TIFFReadDirEntryErrPsdif; + break; + } + nb--; + } + _TIFFfree(m); + return(err); +} +#endif + +static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value) +{ + (void) tif; + *value=*(uint8*)(&direntry->tdir_offset); +} + +static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8* value) +{ + (void) tif; + *value=*(int8*)(&direntry->tdir_offset); +} + +static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value) +{ + *value = direntry->tdir_offset.toff_short; + /* *value=*(uint16*)(&direntry->tdir_offset); */ + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort(value); +} + +static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16* value) +{ + *value=*(int16*)(&direntry->tdir_offset); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)value); +} + +static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value) +{ + *value=*(uint32*)(&direntry->tdir_offset); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(value); +} + +static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32* value) +{ + *value=*(int32*)(&direntry->tdir_offset); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)value); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value) +{ + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + enum TIFFReadDirEntryErr err; + uint32 offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,value); + if (err!=TIFFReadDirEntryErrOk) + return(err); + } + else + *value = direntry->tdir_offset.toff_long8; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(value); + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSlong8(TIFF* tif, TIFFDirEntry* direntry, int64* value) +{ + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + enum TIFFReadDirEntryErr err; + uint32 offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,value); + if (err!=TIFFReadDirEntryErrOk) + return(err); + } + else + *value=*(int64*)(&direntry->tdir_offset); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)value); + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value) +{ + UInt64Aligned_t m; + + assert(sizeof(double)==8); + assert(sizeof(uint64)==8); + assert(sizeof(uint32)==4); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + enum TIFFReadDirEntryErr err; + uint32 offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,m.i); + if (err!=TIFFReadDirEntryErrOk) + return(err); + } + else + m.l = direntry->tdir_offset.toff_long8; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(m.i,2); + if (m.i[0]==0) + *value=0.0; + else + *value=(double)m.i[0]/(double)m.i[1]; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSrational(TIFF* tif, TIFFDirEntry* direntry, double* value) +{ + UInt64Aligned_t m; + assert(sizeof(double)==8); + assert(sizeof(uint64)==8); + assert(sizeof(int32)==4); + assert(sizeof(uint32)==4); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + enum TIFFReadDirEntryErr err; + uint32 offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,m.i); + if (err!=TIFFReadDirEntryErrOk) + return(err); + } + else + m.l=direntry->tdir_offset.toff_long8; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(m.i,2); + if ((int32)m.i[0]==0) + *value=0.0; + else + *value=(double)((int32)m.i[0])/(double)m.i[1]; + return(TIFFReadDirEntryErrOk); +} + +static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value) +{ + union + { + float f; + uint32 i; + } float_union; + assert(sizeof(float)==4); + assert(sizeof(uint32)==4); + assert(sizeof(float_union)==4); + float_union.i=*(uint32*)(&direntry->tdir_offset); + *value=float_union.f; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)value); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value) +{ + assert(sizeof(double)==8); + assert(sizeof(uint64)==8); + assert(sizeof(UInt64Aligned_t)==8); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + enum TIFFReadDirEntryErr err; + uint32 offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,value); + if (err!=TIFFReadDirEntryErrOk) + return(err); + } + else + { + UInt64Aligned_t uint64_union; + uint64_union.l=direntry->tdir_offset.toff_long8; + *value=uint64_union.d; + } + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)value); + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8 value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16 value) +{ + if (value>0xFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16 value) +{ + if ((value<0)||(value>0xFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32 value) +{ + if (value>0xFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32 value) +{ + if ((value<0)||(value>0xFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64 value) +{ + if (value>0xFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64 value) +{ + if ((value<0)||(value>0xFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8 value) +{ + if (value>0x7F) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16 value) +{ + if (value>0x7F) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16 value) +{ + if ((value<-0x80)||(value>0x7F)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32 value) +{ + if (value>0x7F) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32 value) +{ + if ((value<-0x80)||(value>0x7F)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64 value) +{ + if (value>0x7F) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64 value) +{ + if ((value<-0x80)||(value>0x7F)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8 value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16 value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32 value) +{ + if (value>0xFFFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32 value) +{ + if ((value<0)||(value>0xFFFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64 value) +{ + if (value>0xFFFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64 value) +{ + if ((value<0)||(value>0xFFFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16 value) +{ + if (value>0x7FFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32 value) +{ + if (value>0x7FFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32 value) +{ + if ((value<-0x8000)||(value>0x7FFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64 value) +{ + if (value>0x7FFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64 value) +{ + if ((value<-0x8000)||(value>0x7FFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8 value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16 value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32 value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +/* + * Largest 32-bit unsigned integer value. + */ +#if defined(__WIN32__) && defined(_MSC_VER) +# define TIFF_UINT32_MAX 0xFFFFFFFFI64 +#else +# define TIFF_UINT32_MAX 0xFFFFFFFFLL +#endif + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLongLong8(uint64 value) +{ + if (value > TIFF_UINT32_MAX) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLongSlong8(int64 value) +{ + if ((value<0) || (value > TIFF_UINT32_MAX)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +#undef TIFF_UINT32_MAX + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlongLong(uint32 value) +{ + if (value > 0x7FFFFFFFUL) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlongLong8(uint64 value) +{ + if (value > 0x7FFFFFFFUL) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlongSlong8(int64 value) +{ + if ((value < 0L-0x80000000L) || (value > 0x7FFFFFFFL)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLong8Sbyte(int8 value) +{ + if (value < 0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLong8Sshort(int16 value) +{ + if (value < 0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLong8Slong(int32 value) +{ + if (value < 0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLong8Slong8(int64 value) +{ + if (value < 0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +/* + * Largest 64-bit signed integer value. + */ +#if defined(__WIN32__) && defined(_MSC_VER) +# define TIFF_INT64_MAX 0x7FFFFFFFFFFFFFFFI64 +#else +# define TIFF_INT64_MAX 0x7FFFFFFFFFFFFFFFLL +#endif + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value) +{ + if (value > TIFF_INT64_MAX) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +#undef TIFF_INT64_MAX + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryData(TIFF* tif, uint64 offset, tmsize_t size, void* dest) +{ + assert(size>0); + if (!isMapped(tif)) { + if (!SeekOK(tif,offset)) + return(TIFFReadDirEntryErrIo); + if (!ReadOK(tif,dest,size)) + return(TIFFReadDirEntryErrIo); + } else { + size_t ma,mb; + ma=(size_t)offset; + mb=ma+size; + if (((uint64)ma!=offset) + || (mb < ma) + || (mb - ma != (size_t) size) + || (mb < (size_t)size) + || (mb > (size_t)tif->tif_size) + ) + return(TIFFReadDirEntryErrIo); + _TIFFmemcpy(dest,tif->tif_base+ma,size); + } + return(TIFFReadDirEntryErrOk); +} + +static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, const char* module, const char* tagname, int recover) +{ + if (!recover) { + switch (err) { + case TIFFReadDirEntryErrCount: + TIFFErrorExt(tif->tif_clientdata, module, + "Incorrect count for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrType: + TIFFErrorExt(tif->tif_clientdata, module, + "Incompatible type for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrIo: + TIFFErrorExt(tif->tif_clientdata, module, + "IO error during reading of \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrRange: + TIFFErrorExt(tif->tif_clientdata, module, + "Incorrect value for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrPsdif: + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot handle different values per sample for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrSizesan: + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on size of \"%s\" value failed", + tagname); + break; + case TIFFReadDirEntryErrAlloc: + TIFFErrorExt(tif->tif_clientdata, module, + "Out of memory reading of \"%s\"", + tagname); + break; + default: + assert(0); /* we should never get here */ + break; + } + } else { + switch (err) { + case TIFFReadDirEntryErrCount: + TIFFErrorExt(tif->tif_clientdata, module, + "Incorrect count for \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrType: + TIFFWarningExt(tif->tif_clientdata, module, + "Incompatible type for \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrIo: + TIFFWarningExt(tif->tif_clientdata, module, + "IO error during reading of \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrRange: + TIFFWarningExt(tif->tif_clientdata, module, + "Incorrect value for \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrPsdif: + TIFFWarningExt(tif->tif_clientdata, module, + "Cannot handle different values per sample for \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrSizesan: + TIFFWarningExt(tif->tif_clientdata, module, + "Sanity check on size of \"%s\" value failed; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrAlloc: + TIFFWarningExt(tif->tif_clientdata, module, + "Out of memory reading of \"%s\"; tag ignored", + tagname); + break; + default: + assert(0); /* we should never get here */ + break; + } + } +} + +/* + * Read the next TIFF directory from a file and convert it to the internal + * format. We read directories sequentially. + */ +int +TIFFReadDirectory(TIFF* tif) +{ + static const char module[] = "TIFFReadDirectory"; + TIFFDirEntry* dir; + uint16 dircount; + TIFFDirEntry* dp; + uint16 di; + const TIFFField* fip; + uint32 fii=FAILED_FII; + toff_t nextdiroff; + tif->tif_diroff=tif->tif_nextdiroff; + if (!TIFFCheckDirOffset(tif,tif->tif_nextdiroff)) + return 0; /* last offset or bad offset (IFD looping) */ + (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ + tif->tif_curdir++; + nextdiroff = tif->tif_nextdiroff; + dircount=TIFFFetchDirectory(tif,nextdiroff,&dir,&tif->tif_nextdiroff); + if (!dircount) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Failed to read directory at offset " TIFF_UINT64_FORMAT,nextdiroff); + return 0; + } + TIFFReadDirectoryCheckOrder(tif,dir,dircount); + + /* + * Mark duplicates of any tag to be ignored (bugzilla 1994) + * to avoid certain pathological problems. + */ + { + TIFFDirEntry* ma; + uint16 mb; + for (ma=dir, mb=0; mbtdir_tag==na->tdir_tag) + na->tdir_tag=IGNORE; + } + } + } + + tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */ + tif->tif_flags &= ~TIFF_BUF4WRITE; /* reset before new dir */ + /* free any old stuff and reinit */ + TIFFFreeDirectory(tif); + TIFFDefaultDirectory(tif); + /* + * Electronic Arts writes gray-scale TIFF files + * without a PlanarConfiguration directory entry. + * Thus we setup a default value here, even though + * the TIFF spec says there is no default value. + */ + TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG); + /* + * Setup default value and then make a pass over + * the fields to check type and tag information, + * and to extract info required to size data + * structures. A second pass is made afterwards + * to read in everthing not taken in the first pass. + * But we must process the Compression tag first + * in order to merge in codec-private tag definitions (otherwise + * we may get complaints about unknown tags). However, the + * Compression tag may be dependent on the SamplesPerPixel + * tag value because older TIFF specs permited Compression + * to be written as a SamplesPerPixel-count tag entry. + * Thus if we don't first figure out the correct SamplesPerPixel + * tag value then we may end up ignoring the Compression tag + * value because it has an incorrect count value (if the + * true value of SamplesPerPixel is not 1). + */ + dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_SAMPLESPERPIXEL); + if (dp) + { + if (!TIFFFetchNormalTag(tif,dp,0)) + goto bad; + dp->tdir_tag=IGNORE; + } + dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_COMPRESSION); + if (dp) + { + /* + * The 5.0 spec says the Compression tag has one value, while + * earlier specs say it has one value per sample. Because of + * this, we accept the tag if one value is supplied with either + * count. + */ + uint16 value; + enum TIFFReadDirEntryErr err; + err=TIFFReadDirEntryShort(tif,dp,&value); + if (err==TIFFReadDirEntryErrCount) + err=TIFFReadDirEntryPersampleShort(tif,dp,&value); + if (err!=TIFFReadDirEntryErrOk) + { + TIFFReadDirEntryOutputErr(tif,err,module,"Compression",0); + goto bad; + } + if (!TIFFSetField(tif,TIFFTAG_COMPRESSION,value)) + goto bad; + dp->tdir_tag=IGNORE; + } + else + { + if (!TIFFSetField(tif,TIFFTAG_COMPRESSION,COMPRESSION_NONE)) + goto bad; + } + /* + * First real pass over the directory. + */ + for (di=0, dp=dir; ditdir_tag!=IGNORE) + { + TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); + if (fii == FAILED_FII) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Unknown field with tag %d (0x%x) encountered", + dp->tdir_tag,dp->tdir_tag); + /* the following knowingly leaks the + anonymous field structure */ + if (!_TIFFMergeFields(tif, + _TIFFCreateAnonField(tif, + dp->tdir_tag, + (TIFFDataType) dp->tdir_type), + 1)) { + TIFFWarningExt(tif->tif_clientdata, + module, + "Registering anonymous field with tag %d (0x%x) failed", + dp->tdir_tag, + dp->tdir_tag); + dp->tdir_tag=IGNORE; + } else { + TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); + assert(fii != FAILED_FII); + } + } + } + if (dp->tdir_tag!=IGNORE) + { + fip=tif->tif_fields[fii]; + if (fip->field_bit==FIELD_IGNORE) + dp->tdir_tag=IGNORE; + else + { + switch (dp->tdir_tag) + { + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEOFFSETS: + case TIFFTAG_TILEBYTECOUNTS: + TIFFSetFieldBit(tif,fip->field_bit); + break; + case TIFFTAG_IMAGEWIDTH: + case TIFFTAG_IMAGELENGTH: + case TIFFTAG_IMAGEDEPTH: + case TIFFTAG_TILELENGTH: + case TIFFTAG_TILEWIDTH: + case TIFFTAG_TILEDEPTH: + case TIFFTAG_PLANARCONFIG: + case TIFFTAG_ROWSPERSTRIP: + case TIFFTAG_EXTRASAMPLES: + if (!TIFFFetchNormalTag(tif,dp,0)) + goto bad; + dp->tdir_tag=IGNORE; + break; + } + } + } + } + /* + * XXX: OJPEG hack. + * If a) compression is OJPEG, b) planarconfig tag says it's separate, + * c) strip offsets/bytecounts tag are both present and + * d) both contain exactly one value, then we consistently find + * that the buggy implementation of the buggy compression scheme + * matches contig planarconfig best. So we 'fix-up' the tag here + */ + if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG)&& + (tif->tif_dir.td_planarconfig==PLANARCONFIG_SEPARATE)) + { + if (!_TIFFFillStriles(tif)) + goto bad; + dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_STRIPOFFSETS); + if ((dp!=0)&&(dp->tdir_count==1)) + { + dp=TIFFReadDirectoryFindEntry(tif,dir,dircount, + TIFFTAG_STRIPBYTECOUNTS); + if ((dp!=0)&&(dp->tdir_count==1)) + { + tif->tif_dir.td_planarconfig=PLANARCONFIG_CONTIG; + TIFFWarningExt(tif->tif_clientdata,module, + "Planarconfig tag value assumed incorrect, " + "assuming data is contig instead of chunky"); + } + } + } + /* + * Allocate directory structure and setup defaults. + */ + if (!TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS)) + { + MissingRequired(tif,"ImageLength"); + goto bad; + } + /* + * Setup appropriate structures (by strip or by tile) + */ + if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { + tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif); + tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth; + tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip; + tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth; + tif->tif_flags &= ~TIFF_ISTILED; + } else { + tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif); + tif->tif_flags |= TIFF_ISTILED; + } + if (!tif->tif_dir.td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot handle zero number of %s", + isTiled(tif) ? "tiles" : "strips"); + goto bad; + } + tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips; + if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE) + tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel; + if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) { + if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) && + (isTiled(tif)==0) && + (tif->tif_dir.td_nstrips==1)) { + /* + * XXX: OJPEG hack. + * If a) compression is OJPEG, b) it's not a tiled TIFF, + * and c) the number of strips is 1, + * then we tolerate the absence of stripoffsets tag, + * because, presumably, all required data is in the + * JpegInterchangeFormat stream. + */ + TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); + } else { + MissingRequired(tif, + isTiled(tif) ? "TileOffsets" : "StripOffsets"); + goto bad; + } + } + /* + * Second pass: extract other information. + */ + for (di=0, dp=dir; ditdir_tag) + { + case IGNORE: + break; + case TIFFTAG_MINSAMPLEVALUE: + case TIFFTAG_MAXSAMPLEVALUE: + case TIFFTAG_BITSPERSAMPLE: + case TIFFTAG_DATATYPE: + case TIFFTAG_SAMPLEFORMAT: + /* + * The MinSampleValue, MaxSampleValue, BitsPerSample + * DataType and SampleFormat tags are supposed to be + * written as one value/sample, but some vendors + * incorrectly write one value only -- so we accept + * that as well (yech). Other vendors write correct + * value for NumberOfSamples, but incorrect one for + * BitsPerSample and friends, and we will read this + * too. + */ + { + uint16 value; + enum TIFFReadDirEntryErr err; + err=TIFFReadDirEntryShort(tif,dp,&value); + if (err==TIFFReadDirEntryErrCount) + err=TIFFReadDirEntryPersampleShort(tif,dp,&value); + if (err!=TIFFReadDirEntryErrOk) + { + fip = TIFFFieldWithTag(tif,dp->tdir_tag); + TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0); + goto bad; + } + if (!TIFFSetField(tif,dp->tdir_tag,value)) + goto bad; + } + break; + case TIFFTAG_SMINSAMPLEVALUE: + case TIFFTAG_SMAXSAMPLEVALUE: + { + + double *data; + enum TIFFReadDirEntryErr err; + uint32 saved_flags; + int m; + if (dp->tdir_count != (uint64)tif->tif_dir.td_samplesperpixel) + err = TIFFReadDirEntryErrCount; + else + err = TIFFReadDirEntryDoubleArray(tif, dp, &data); + if (err!=TIFFReadDirEntryErrOk) + { + fip = TIFFFieldWithTag(tif,dp->tdir_tag); + TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0); + goto bad; + } + saved_flags = tif->tif_flags; + tif->tif_flags |= TIFF_PERSAMPLE; + m = TIFFSetField(tif,dp->tdir_tag,data); + tif->tif_flags = saved_flags; + _TIFFfree(data); + if (!m) + goto bad; + } + break; + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_TILEOFFSETS: +#if defined(DEFER_STRILE_LOAD) + _TIFFmemcpy( &(tif->tif_dir.td_stripoffset_entry), + dp, sizeof(TIFFDirEntry) ); +#else + if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripoffset)) + goto bad; +#endif + break; + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEBYTECOUNTS: +#if defined(DEFER_STRILE_LOAD) + _TIFFmemcpy( &(tif->tif_dir.td_stripbytecount_entry), + dp, sizeof(TIFFDirEntry) ); +#else + if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripbytecount)) + goto bad; +#endif + break; + case TIFFTAG_COLORMAP: + case TIFFTAG_TRANSFERFUNCTION: + { + enum TIFFReadDirEntryErr err; + uint32 countpersample; + uint32 countrequired; + uint32 incrementpersample; + uint16* value=NULL; + countpersample=(1L<tif_dir.td_bitspersample); + if ((dp->tdir_tag==TIFFTAG_TRANSFERFUNCTION)&&(dp->tdir_count==(uint64)countpersample)) + { + countrequired=countpersample; + incrementpersample=0; + } + else + { + countrequired=3*countpersample; + incrementpersample=countpersample; + } + if (dp->tdir_count!=(uint64)countrequired) + err=TIFFReadDirEntryErrCount; + else + err=TIFFReadDirEntryShortArray(tif,dp,&value); + if (err!=TIFFReadDirEntryErrOk) + { + fip = TIFFFieldWithTag(tif,dp->tdir_tag); + TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",1); + } + else + { + TIFFSetField(tif,dp->tdir_tag,value,value+incrementpersample,value+2*incrementpersample); + _TIFFfree(value); + } + } + break; +/* BEGIN REV 4.0 COMPATIBILITY */ + case TIFFTAG_OSUBFILETYPE: + { + uint16 valueo; + uint32 value; + if (TIFFReadDirEntryShort(tif,dp,&valueo)==TIFFReadDirEntryErrOk) + { + switch (valueo) + { + case OFILETYPE_REDUCEDIMAGE: value=FILETYPE_REDUCEDIMAGE; break; + case OFILETYPE_PAGE: value=FILETYPE_PAGE; break; + default: value=0; break; + } + if (value!=0) + TIFFSetField(tif,TIFFTAG_SUBFILETYPE,value); + } + } + break; +/* END REV 4.0 COMPATIBILITY */ + default: + (void) TIFFFetchNormalTag(tif, dp, TRUE); + break; + } + } + /* + * OJPEG hack: + * - If a) compression is OJPEG, and b) photometric tag is missing, + * then we consistently find that photometric should be YCbCr + * - If a) compression is OJPEG, and b) photometric tag says it's RGB, + * then we consistently find that the buggy implementation of the + * buggy compression scheme matches photometric YCbCr instead. + * - If a) compression is OJPEG, and b) bitspersample tag is missing, + * then we consistently find bitspersample should be 8. + * - If a) compression is OJPEG, b) samplesperpixel tag is missing, + * and c) photometric is RGB or YCbCr, then we consistently find + * samplesperpixel should be 3 + * - If a) compression is OJPEG, b) samplesperpixel tag is missing, + * and c) photometric is MINISWHITE or MINISBLACK, then we consistently + * find samplesperpixel should be 3 + */ + if (tif->tif_dir.td_compression==COMPRESSION_OJPEG) + { + if (!TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Photometric tag is missing, assuming data is YCbCr"); + if (!TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_YCBCR)) + goto bad; + } + else if (tif->tif_dir.td_photometric==PHOTOMETRIC_RGB) + { + tif->tif_dir.td_photometric=PHOTOMETRIC_YCBCR; + TIFFWarningExt(tif->tif_clientdata, module, + "Photometric tag value assumed incorrect, " + "assuming data is YCbCr instead of RGB"); + } + if (!TIFFFieldSet(tif,FIELD_BITSPERSAMPLE)) + { + TIFFWarningExt(tif->tif_clientdata,module, + "BitsPerSample tag is missing, assuming 8 bits per sample"); + if (!TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,8)) + goto bad; + } + if (!TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL)) + { + if (tif->tif_dir.td_photometric==PHOTOMETRIC_RGB) + { + TIFFWarningExt(tif->tif_clientdata,module, + "SamplesPerPixel tag is missing, " + "assuming correct SamplesPerPixel value is 3"); + if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3)) + goto bad; + } + if (tif->tif_dir.td_photometric==PHOTOMETRIC_YCBCR) + { + TIFFWarningExt(tif->tif_clientdata,module, + "SamplesPerPixel tag is missing, " + "applying correct SamplesPerPixel value of 3"); + if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3)) + goto bad; + } + else if ((tif->tif_dir.td_photometric==PHOTOMETRIC_MINISWHITE) + || (tif->tif_dir.td_photometric==PHOTOMETRIC_MINISBLACK)) + { + /* + * SamplesPerPixel tag is missing, but is not required + * by spec. Assume correct SamplesPerPixel value of 1. + */ + if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,1)) + goto bad; + } + } + } + /* + * Verify Palette image has a Colormap. + */ + if (tif->tif_dir.td_photometric == PHOTOMETRIC_PALETTE && + !TIFFFieldSet(tif, FIELD_COLORMAP)) { + if ( tif->tif_dir.td_bitspersample>=8 && tif->tif_dir.td_samplesperpixel==3) + tif->tif_dir.td_photometric = PHOTOMETRIC_RGB; + else if (tif->tif_dir.td_bitspersample>=8) + tif->tif_dir.td_photometric = PHOTOMETRIC_MINISBLACK; + else { + MissingRequired(tif, "Colormap"); + goto bad; + } + } + /* + * OJPEG hack: + * We do no further messing with strip/tile offsets/bytecounts in OJPEG + * TIFFs + */ + if (tif->tif_dir.td_compression!=COMPRESSION_OJPEG) + { + /* + * Attempt to deal with a missing StripByteCounts tag. + */ + if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) { + /* + * Some manufacturers violate the spec by not giving + * the size of the strips. In this case, assume there + * is one uncompressed strip of data. + */ + if ((tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG && + tif->tif_dir.td_nstrips > 1) || + (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE && + tif->tif_dir.td_nstrips != (uint32)tif->tif_dir.td_samplesperpixel)) { + MissingRequired(tif, "StripByteCounts"); + goto bad; + } + TIFFWarningExt(tif->tif_clientdata, module, + "TIFF directory is missing required " + "\"StripByteCounts\" field, calculating from imagelength"); + if (EstimateStripByteCounts(tif, dir, dircount) < 0) + goto bad; + /* + * Assume we have wrong StripByteCount value (in case + * of single strip) in following cases: + * - it is equal to zero along with StripOffset; + * - it is larger than file itself (in case of uncompressed + * image); + * - it is smaller than the size of the bytes per row + * multiplied on the number of rows. The last case should + * not be checked in the case of writing new image, + * because we may do not know the exact strip size + * until the whole image will be written and directory + * dumped out. + */ + #define BYTECOUNTLOOKSBAD \ + ( (tif->tif_dir.td_stripbytecount[0] == 0 && tif->tif_dir.td_stripoffset[0] != 0) || \ + (tif->tif_dir.td_compression == COMPRESSION_NONE && \ + tif->tif_dir.td_stripbytecount[0] > TIFFGetFileSize(tif) - tif->tif_dir.td_stripoffset[0]) || \ + (tif->tif_mode == O_RDONLY && \ + tif->tif_dir.td_compression == COMPRESSION_NONE && \ + tif->tif_dir.td_stripbytecount[0] < TIFFScanlineSize64(tif) * tif->tif_dir.td_imagelength) ) + + } else if (tif->tif_dir.td_nstrips == 1 + && _TIFFFillStriles(tif) + && tif->tif_dir.td_stripoffset[0] != 0 + && BYTECOUNTLOOKSBAD) { + /* + * XXX: Plexus (and others) sometimes give a value of + * zero for a tag when they don't know what the + * correct value is! Try and handle the simple case + * of estimating the size of a one strip image. + */ + TIFFWarningExt(tif->tif_clientdata, module, + "Bogus \"StripByteCounts\" field, ignoring and calculating from imagelength"); + if(EstimateStripByteCounts(tif, dir, dircount) < 0) + goto bad; + +#if !defined(DEFER_STRILE_LOAD) + } else if (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG + && tif->tif_dir.td_nstrips > 2 + && tif->tif_dir.td_compression == COMPRESSION_NONE + && tif->tif_dir.td_stripbytecount[0] != tif->tif_dir.td_stripbytecount[1] + && tif->tif_dir.td_stripbytecount[0] != 0 + && tif->tif_dir.td_stripbytecount[1] != 0 ) { + /* + * XXX: Some vendors fill StripByteCount array with + * absolutely wrong values (it can be equal to + * StripOffset array, for example). Catch this case + * here. + * + * We avoid this check if deferring strile loading + * as it would always force us to load the strip/tile + * information. + */ + TIFFWarningExt(tif->tif_clientdata, module, + "Wrong \"StripByteCounts\" field, ignoring and calculating from imagelength"); + if (EstimateStripByteCounts(tif, dir, dircount) < 0) + goto bad; +#endif /* !defined(DEFER_STRILE_LOAD) */ + } + } + if (dir) + { + _TIFFfree(dir); + dir=NULL; + } + if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE)) + { + if (tif->tif_dir.td_bitspersample>=16) + tif->tif_dir.td_maxsamplevalue=0xFFFF; + else + tif->tif_dir.td_maxsamplevalue = (uint16)((1L<tif_dir.td_bitspersample)-1); + } + /* + * XXX: We can optimize checking for the strip bounds using the sorted + * bytecounts array. See also comments for TIFFAppendToStrip() + * function in tif_write.c. + */ +#if !defined(DEFER_STRILE_LOAD) + if (tif->tif_dir.td_nstrips > 1) { + uint32 strip; + + tif->tif_dir.td_stripbytecountsorted = 1; + for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) { + if (tif->tif_dir.td_stripoffset[strip - 1] > + tif->tif_dir.td_stripoffset[strip]) { + tif->tif_dir.td_stripbytecountsorted = 0; + break; + } + } + } +#endif /* !defined(DEFER_STRILE_LOAD) */ + + /* + * An opportunity for compression mode dependent tag fixup + */ + (*tif->tif_fixuptags)(tif); + + /* + * Some manufacturers make life difficult by writing + * large amounts of uncompressed data as a single strip. + * This is contrary to the recommendations of the spec. + * The following makes an attempt at breaking such images + * into strips closer to the recommended 8k bytes. A + * side effect, however, is that the RowsPerStrip tag + * value may be changed. + */ + if ((tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG)&& + (tif->tif_dir.td_nstrips==1)&& + (tif->tif_dir.td_compression==COMPRESSION_NONE)&& + ((tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED))==TIFF_STRIPCHOP)) + { + if ( !_TIFFFillStriles(tif) || !tif->tif_dir.td_stripbytecount ) + return 0; + ChopUpSingleUncompressedStrip(tif); + } + + /* + * Clear the dirty directory flag. + */ + tif->tif_flags &= ~TIFF_DIRTYDIRECT; + tif->tif_flags &= ~TIFF_DIRTYSTRIP; + + /* + * Reinitialize i/o since we are starting on a new directory. + */ + tif->tif_row = (uint32) -1; + tif->tif_curstrip = (uint32) -1; + tif->tif_col = (uint32) -1; + tif->tif_curtile = (uint32) -1; + tif->tif_tilesize = (tmsize_t) -1; + + tif->tif_scanlinesize = TIFFScanlineSize(tif); + if (!tif->tif_scanlinesize) { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot handle zero scanline size"); + return (0); + } + + if (isTiled(tif)) { + tif->tif_tilesize = TIFFTileSize(tif); + if (!tif->tif_tilesize) { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot handle zero tile size"); + return (0); + } + } else { + if (!TIFFStripSize(tif)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot handle zero strip size"); + return (0); + } + } + return (1); +bad: + if (dir) + _TIFFfree(dir); + return (0); +} + +static void +TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16 dircount) +{ + static const char module[] = "TIFFReadDirectoryCheckOrder"; + uint16 m; + uint16 n; + TIFFDirEntry* o; + m=0; + for (n=0, o=dir; ntdir_tagtif_clientdata,module, + "Invalid TIFF directory; tags are not sorted in ascending order"); + break; + } + m=o->tdir_tag+1; + } +} + +static TIFFDirEntry* +TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16 dircount, uint16 tagid) +{ + TIFFDirEntry* m; + uint16 n; + (void) tif; + for (m=dir, n=0; ntdir_tag==tagid) + return(m); + } + return(0); +} + +static void +TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16 tagid, uint32* fii) +{ + int32 ma,mb,mc; + ma=-1; + mc=(int32)tif->tif_nfields; + while (1) + { + if (ma+1==mc) + { + *fii = FAILED_FII; + return; + } + mb=(ma+mc)/2; + if (tif->tif_fields[mb]->field_tag==(uint32)tagid) + break; + if (tif->tif_fields[mb]->field_tag<(uint32)tagid) + ma=mb; + else + mc=mb; + } + while (1) + { + if (mb==0) + break; + if (tif->tif_fields[mb-1]->field_tag!=(uint32)tagid) + break; + mb--; + } + *fii=mb; +} + +/* + * Read custom directory from the arbitarry offset. + * The code is very similar to TIFFReadDirectory(). + */ +int +TIFFReadCustomDirectory(TIFF* tif, toff_t diroff, + const TIFFFieldArray* infoarray) +{ + static const char module[] = "TIFFReadCustomDirectory"; + TIFFDirEntry* dir; + uint16 dircount; + TIFFDirEntry* dp; + uint16 di; + const TIFFField* fip; + uint32 fii; + _TIFFSetupFields(tif, infoarray); + dircount=TIFFFetchDirectory(tif,diroff,&dir,NULL); + if (!dircount) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Failed to read custom directory at offset " TIFF_UINT64_FORMAT,diroff); + return 0; + } + TIFFFreeDirectory(tif); + _TIFFmemset(&tif->tif_dir, 0, sizeof(TIFFDirectory)); + TIFFReadDirectoryCheckOrder(tif,dir,dircount); + for (di=0, dp=dir; ditdir_tag,&fii); + if (fii == FAILED_FII) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Unknown field with tag %d (0x%x) encountered", + dp->tdir_tag, dp->tdir_tag); + if (!_TIFFMergeFields(tif, _TIFFCreateAnonField(tif, + dp->tdir_tag, + (TIFFDataType) dp->tdir_type), + 1)) { + TIFFWarningExt(tif->tif_clientdata, module, + "Registering anonymous field with tag %d (0x%x) failed", + dp->tdir_tag, dp->tdir_tag); + dp->tdir_tag=IGNORE; + } else { + TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); + assert( fii != FAILED_FII ); + } + } + if (dp->tdir_tag!=IGNORE) + { + fip=tif->tif_fields[fii]; + if (fip->field_bit==FIELD_IGNORE) + dp->tdir_tag=IGNORE; + else + { + /* check data type */ + while ((fip->field_type!=TIFF_ANY)&&(fip->field_type!=dp->tdir_type)) + { + fii++; + if ((fii==tif->tif_nfields)|| + (tif->tif_fields[fii]->field_tag!=(uint32)dp->tdir_tag)) + { + fii=0xFFFF; + break; + } + fip=tif->tif_fields[fii]; + } + if (fii==0xFFFF) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Wrong data type %d for \"%s\"; tag ignored", + dp->tdir_type,fip->field_name); + dp->tdir_tag=IGNORE; + } + else + { + /* check count if known in advance */ + if ((fip->field_readcount!=TIFF_VARIABLE)&& + (fip->field_readcount!=TIFF_VARIABLE2)) + { + uint32 expected; + if (fip->field_readcount==TIFF_SPP) + expected=(uint32)tif->tif_dir.td_samplesperpixel; + else + expected=(uint32)fip->field_readcount; + if (!CheckDirCount(tif,dp,expected)) + dp->tdir_tag=IGNORE; + } + } + } + switch (dp->tdir_tag) + { + case IGNORE: + break; + case EXIFTAG_SUBJECTDISTANCE: + (void) TIFFFetchSubjectDistance(tif,dp); + break; + default: + (void) TIFFFetchNormalTag(tif, dp, TRUE); + break; + } + } + } + if (dir) + _TIFFfree(dir); + return 1; +} + +/* + * EXIF is important special case of custom IFD, so we have a special + * function to read it. + */ +int +TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff) +{ + const TIFFFieldArray* exifFieldArray; + exifFieldArray = _TIFFGetExifFields(); + return TIFFReadCustomDirectory(tif, diroff, exifFieldArray); +} + +static int +EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount) +{ + static const char module[] = "EstimateStripByteCounts"; + + TIFFDirEntry *dp; + TIFFDirectory *td = &tif->tif_dir; + uint32 strip; + + _TIFFFillStriles( tif ); + + if (td->td_stripbytecount) + _TIFFfree(td->td_stripbytecount); + td->td_stripbytecount = (uint64*) + _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64), + "for \"StripByteCounts\" array"); + if( td->td_stripbytecount == NULL ) + return -1; + + if (td->td_compression != COMPRESSION_NONE) { + uint64 space; + uint64 filesize; + uint16 n; + filesize = TIFFGetFileSize(tif); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + space=sizeof(TIFFHeaderClassic)+2+dircount*12+4; + else + space=sizeof(TIFFHeaderBig)+8+dircount*20+8; + /* calculate amount of space used by indirect values */ + for (dp = dir, n = dircount; n > 0; n--, dp++) + { + uint32 typewidth = TIFFDataWidth((TIFFDataType) dp->tdir_type); + uint64 datasize; + typewidth = TIFFDataWidth((TIFFDataType) dp->tdir_type); + if (typewidth == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot determine size of unknown tag type %d", + dp->tdir_type); + return -1; + } + datasize=(uint64)typewidth*dp->tdir_count; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if (datasize<=4) + datasize=0; + } + else + { + if (datasize<=8) + datasize=0; + } + space+=datasize; + } + space = filesize - space; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + space /= td->td_samplesperpixel; + for (strip = 0; strip < td->td_nstrips; strip++) + td->td_stripbytecount[strip] = space; + /* + * This gross hack handles the case were the offset to + * the last strip is past the place where we think the strip + * should begin. Since a strip of data must be contiguous, + * it's safe to assume that we've overestimated the amount + * of data in the strip and trim this number back accordingly. + */ + strip--; + if (td->td_stripoffset[strip]+td->td_stripbytecount[strip] > filesize) + td->td_stripbytecount[strip] = filesize - td->td_stripoffset[strip]; + } else if (isTiled(tif)) { + uint64 bytespertile = TIFFTileSize64(tif); + + for (strip = 0; strip < td->td_nstrips; strip++) + td->td_stripbytecount[strip] = bytespertile; + } else { + uint64 rowbytes = TIFFScanlineSize64(tif); + uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage; + for (strip = 0; strip < td->td_nstrips; strip++) + td->td_stripbytecount[strip] = rowbytes * rowsperstrip; + } + TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); + if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP)) + td->td_rowsperstrip = td->td_imagelength; + return 1; +} + +static void +MissingRequired(TIFF* tif, const char* tagname) +{ + static const char module[] = "MissingRequired"; + + TIFFErrorExt(tif->tif_clientdata, module, + "TIFF directory is missing required \"%s\" field", + tagname); +} + +/* + * Check the directory offset against the list of already seen directory + * offsets. This is a trick to prevent IFD looping. The one can create TIFF + * file with looped directory pointers. We will maintain a list of already + * seen directories and check every IFD offset against that list. + */ +static int +TIFFCheckDirOffset(TIFF* tif, uint64 diroff) +{ + uint16 n; + + if (diroff == 0) /* no more directories */ + return 0; + + for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) { + if (tif->tif_dirlist[n] == diroff) + return 0; + } + + tif->tif_dirnumber++; + + if (tif->tif_dirnumber > tif->tif_dirlistsize) { + uint64* new_dirlist; + + /* + * XXX: Reduce memory allocation granularity of the dirlist + * array. + */ + new_dirlist = (uint64*)_TIFFCheckRealloc(tif, tif->tif_dirlist, + tif->tif_dirnumber, 2 * sizeof(uint64), "for IFD list"); + if (!new_dirlist) + return 0; + tif->tif_dirlistsize = 2 * tif->tif_dirnumber; + tif->tif_dirlist = new_dirlist; + } + + tif->tif_dirlist[tif->tif_dirnumber - 1] = diroff; + + return 1; +} + +/* + * Check the count field of a directory entry against a known value. The + * caller is expected to skip/ignore the tag if there is a mismatch. + */ +static int +CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count) +{ + if ((uint64)count > dir->tdir_count) { + const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag); + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "incorrect count for field \"%s\" (" TIFF_UINT64_FORMAT ", expecting %u); tag ignored", + fip ? fip->field_name : "unknown tagname", + dir->tdir_count, count); + return (0); + } else if ((uint64)count < dir->tdir_count) { + const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag); + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "incorrect count for field \"%s\" (" TIFF_UINT64_FORMAT ", expecting %u); tag trimmed", + fip ? fip->field_name : "unknown tagname", + dir->tdir_count, count); + dir->tdir_count = count; + return (1); + } + return (1); +} + +/* + * Read IFD structure from the specified offset. If the pointer to + * nextdiroff variable has been specified, read it too. Function returns a + * number of fields in the directory or 0 if failed. + */ +static uint16 +TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir, + uint64 *nextdiroff) +{ + static const char module[] = "TIFFFetchDirectory"; + + void* origdir; + uint16 dircount16; + uint32 dirsize; + TIFFDirEntry* dir; + uint8* ma; + TIFFDirEntry* mb; + uint16 n; + + assert(pdir); + + tif->tif_diroff = diroff; + if (nextdiroff) + *nextdiroff = 0; + if (!isMapped(tif)) { + if (!SeekOK(tif, tif->tif_diroff)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Seek error accessing TIFF directory", + tif->tif_name); + return 0; + } + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if (!ReadOK(tif, &dircount16, sizeof (uint16))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount16); + if (dircount16>4096) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on directory count failed, this is probably not a valid IFD offset"); + return 0; + } + dirsize = 12; + } else { + uint64 dircount64; + if (!ReadOK(tif, &dircount64, sizeof (uint64))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>4096) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on directory count failed, this is probably not a valid IFD offset"); + return 0; + } + dircount16 = (uint16)dircount64; + dirsize = 20; + } + origdir = _TIFFCheckMalloc(tif, dircount16, + dirsize, "to read TIFF directory"); + if (origdir == NULL) + return 0; + if (!ReadOK(tif, origdir, (tmsize_t)(dircount16*dirsize))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%.100s: Can not read TIFF directory", + tif->tif_name); + _TIFFfree(origdir); + return 0; + } + /* + * Read offset to next directory for sequential scans if + * needed. + */ + if (nextdiroff) + { + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32 nextdiroff32; + if (!ReadOK(tif, &nextdiroff32, sizeof(uint32))) + nextdiroff32 = 0; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&nextdiroff32); + *nextdiroff=nextdiroff32; + } else { + if (!ReadOK(tif, nextdiroff, sizeof(uint64))) + *nextdiroff = 0; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(nextdiroff); + } + } + } else { + tmsize_t m; + tmsize_t off = (tmsize_t) tif->tif_diroff; + if ((uint64)off!=tif->tif_diroff) + { + TIFFErrorExt(tif->tif_clientdata,module,"Can not read TIFF directory count"); + return(0); + } + + /* + * Check for integer overflow when validating the dir_off, + * otherwise a very high offset may cause an OOB read and + * crash the client. Make two comparisons instead of + * + * off + sizeof(uint16) > tif->tif_size + * + * to avoid overflow. + */ + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + m=off+sizeof(uint16); + if ((mtif->tif_size)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not read TIFF directory count"); + return 0; + } else { + _TIFFmemcpy(&dircount16, tif->tif_base + off, + sizeof(uint16)); + } + off += sizeof (uint16); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount16); + if (dircount16>4096) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on directory count failed, this is probably not a valid IFD offset"); + return 0; + } + dirsize = 12; + } + else + { + tmsize_t m; + uint64 dircount64; + m=off+sizeof(uint64); + if ((mtif->tif_size)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not read TIFF directory count"); + return 0; + } else { + _TIFFmemcpy(&dircount64, tif->tif_base + off, + sizeof(uint64)); + } + off += sizeof (uint64); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>4096) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on directory count failed, this is probably not a valid IFD offset"); + return 0; + } + dircount16 = (uint16)dircount64; + dirsize = 20; + } + if (dircount16 == 0 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on directory count failed, zero tag directories not supported"); + return 0; + } + origdir = _TIFFCheckMalloc(tif, dircount16, + dirsize, + "to read TIFF directory"); + if (origdir == NULL) + return 0; + m=off+dircount16*dirsize; + if ((mtif->tif_size)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not read TIFF directory"); + _TIFFfree(origdir); + return 0; + } else { + _TIFFmemcpy(origdir, tif->tif_base + off, + dircount16 * dirsize); + } + if (nextdiroff) { + off += dircount16 * dirsize; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32 nextdiroff32; + m=off+sizeof(uint32); + if ((mtif->tif_size)) + nextdiroff32 = 0; + else + _TIFFmemcpy(&nextdiroff32, tif->tif_base + off, + sizeof (uint32)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&nextdiroff32); + *nextdiroff = nextdiroff32; + } + else + { + m=off+sizeof(uint64); + if ((mtif->tif_size)) + *nextdiroff = 0; + else + _TIFFmemcpy(nextdiroff, tif->tif_base + off, + sizeof (uint64)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(nextdiroff); + } + } + } + dir = (TIFFDirEntry*)_TIFFCheckMalloc(tif, dircount16, + sizeof(TIFFDirEntry), + "to read TIFF directory"); + if (dir==0) + { + _TIFFfree(origdir); + return 0; + } + ma=(uint8*)origdir; + mb=dir; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)ma); + mb->tdir_tag=*(uint16*)ma; + ma+=sizeof(uint16); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)ma); + mb->tdir_type=*(uint16*)ma; + ma+=sizeof(uint16); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)ma); + mb->tdir_count=(uint64)(*(uint32*)ma); + ma+=sizeof(uint32); + *(uint32*)(&mb->tdir_offset)=*(uint32*)ma; + ma+=sizeof(uint32); + } + else + { + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)ma); + mb->tdir_count=TIFFReadUInt64(ma); + ma+=sizeof(uint64); + mb->tdir_offset.toff_long8=TIFFReadUInt64(ma); + ma+=sizeof(uint64); + } + mb++; + } + _TIFFfree(origdir); + *pdir = dir; + return dircount16; +} + +/* + * Fetch a tag that is not handled by special case code. + */ +static int +TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover) +{ + static const char module[] = "TIFFFetchNormalTag"; + enum TIFFReadDirEntryErr err; + uint32 fii; + const TIFFField* fip = NULL; + TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); + if( fii == FAILED_FII ) + { + TIFFErrorExt(tif->tif_clientdata, "TIFFFetchNormalTag", + "No definition found for tag %d", + dp->tdir_tag); + return 0; + } + fip=tif->tif_fields[fii]; + assert(fip->set_field_type!=TIFF_SETGET_OTHER); /* if so, we shouldn't arrive here but deal with this in specialized code */ + assert(fip->set_field_type!=TIFF_SETGET_INT); /* if so, we shouldn't arrive here as this is only the case for pseudo-tags */ + err=TIFFReadDirEntryErrOk; + switch (fip->set_field_type) + { + case TIFF_SETGET_UNDEFINED: + break; + case TIFF_SETGET_ASCII: + { + uint8* data; + assert(fip->field_passcount==0); + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + uint8* ma; + uint32 mb; + int n; + ma=data; + mb=0; + while (mb<(uint32)dp->tdir_count) + { + if (*ma==0) + break; + ma++; + mb++; + } + if (mb+1<(uint32)dp->tdir_count) + TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" contains null byte in value; value incorrectly truncated during reading due to implementation limitations",fip->field_name); + else if (mb+1>(uint32)dp->tdir_count) + { + uint8* o; + TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte",fip->field_name); + if ((uint32)dp->tdir_count+1!=dp->tdir_count+1) + o=NULL; + else + o=_TIFFmalloc((uint32)dp->tdir_count+1); + if (o==NULL) + { + if (data!=NULL) + _TIFFfree(data); + return(0); + } + _TIFFmemcpy(o,data,(uint32)dp->tdir_count); + o[(uint32)dp->tdir_count]=0; + if (data!=0) + _TIFFfree(data); + data=o; + } + n=TIFFSetField(tif,dp->tdir_tag,data); + if (data!=0) + _TIFFfree(data); + if (!n) + return(0); + } + } + break; + case TIFF_SETGET_UINT8: + { + uint8 data=0; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryByte(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_UINT16: + { + uint16 data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryShort(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_UINT32: + { + uint32 data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryLong(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_UINT64: + { + uint64 data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryLong8(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_FLOAT: + { + float data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryFloat(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_DOUBLE: + { + double data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryDouble(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_IFD8: + { + uint64 data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryIfd8(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_UINT16_PAIR: + { + uint16* data; + assert(fip->field_readcount==2); + assert(fip->field_passcount==0); + if (dp->tdir_count!=2) { + TIFFWarningExt(tif->tif_clientdata,module, + "incorrect count for field \"%s\", expected 2, got %d", + fip->field_name,(int)dp->tdir_count); + return(0); + } + err=TIFFReadDirEntryShortArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,data[0],data[1]); + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C0_UINT8: + { + uint8* data; + assert(fip->field_readcount>=1); + assert(fip->field_passcount==0); + if (dp->tdir_count!=(uint64)fip->field_readcount) { + TIFFWarningExt(tif->tif_clientdata,module, + "incorrect count for field \"%s\", expected %d, got %d", + fip->field_name,(int) fip->field_readcount, (int)dp->tdir_count); + return 0; + } + else + { + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C0_UINT16: + { + uint16* data; + assert(fip->field_readcount>=1); + assert(fip->field_passcount==0); + if (dp->tdir_count!=(uint64)fip->field_readcount) + /* corrupt file */; + else + { + err=TIFFReadDirEntryShortArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C0_UINT32: + { + uint32* data; + assert(fip->field_readcount>=1); + assert(fip->field_passcount==0); + if (dp->tdir_count!=(uint64)fip->field_readcount) + /* corrupt file */; + else + { + err=TIFFReadDirEntryLongArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C0_FLOAT: + { + float* data; + assert(fip->field_readcount>=1); + assert(fip->field_passcount==0); + if (dp->tdir_count!=(uint64)fip->field_readcount) + /* corrupt file */; + else + { + err=TIFFReadDirEntryFloatArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_ASCII: + { + uint8* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_UINT8: + { + uint8* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_UINT16: + { + uint16* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryShortArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_UINT32: + { + uint32* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryLongArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_UINT64: + { + uint64* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryLong8Array(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_FLOAT: + { + float* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryFloatArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_DOUBLE: + { + double* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryDoubleArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_IFD8: + { + uint64* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryIfd8Array(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C32_ASCII: + { + uint8* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_UINT8: + { + uint8* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_SINT8: + { + int8* data = NULL; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntrySbyteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_UINT16: + { + uint16* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryShortArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_SINT16: + { + int16* data = NULL; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntrySshortArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_UINT32: + { + uint32* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryLongArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_SINT32: + { + int32* data = NULL; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntrySlongArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_UINT64: + { + uint64* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryLong8Array(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_SINT64: + { + int64* data = NULL; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntrySlong8Array(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_FLOAT: + { + float* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryFloatArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_DOUBLE: + { + double* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryDoubleArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_IFD8: + { + uint64* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryIfd8Array(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + default: + assert(0); /* we should never get here */ + break; + } + if (err!=TIFFReadDirEntryErrOk) + { + TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",recover); + return(0); + } + return(1); +} + +/* + * Fetch a set of offsets or lengths. + * While this routine says "strips", in fact it's also used for tiles. + */ +static int +TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp) +{ + static const char module[] = "TIFFFetchStripThing"; + enum TIFFReadDirEntryErr err; + uint64* data; + err=TIFFReadDirEntryLong8Array(tif,dir,&data); + if (err!=TIFFReadDirEntryErrOk) + { + const TIFFField* fip = TIFFFieldWithTag(tif,dir->tdir_tag); + TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0); + return(0); + } + if (dir->tdir_count!=(uint64)nstrips) + { + uint64* resizeddata; + resizeddata=(uint64*)_TIFFCheckMalloc(tif,nstrips,sizeof(uint64),"for strip array"); + if (resizeddata==0) { + _TIFFfree(data); + return(0); + } + if (dir->tdir_count<(uint64)nstrips) + { + _TIFFmemcpy(resizeddata,data,(uint32)dir->tdir_count*sizeof(uint64)); + _TIFFmemset(resizeddata+(uint32)dir->tdir_count,0,(nstrips-(uint32)dir->tdir_count)*sizeof(uint64)); + } + else + _TIFFmemcpy(resizeddata,data,nstrips*sizeof(uint64)); + _TIFFfree(data); + data=resizeddata; + } + *lpp=data; + return(1); +} + +/* + * Fetch and set the SubjectDistance EXIF tag. + */ +static int +TIFFFetchSubjectDistance(TIFF* tif, TIFFDirEntry* dir) +{ + static const char module[] = "TIFFFetchSubjectDistance"; + enum TIFFReadDirEntryErr err; + UInt64Aligned_t m; + m.l=0; + assert(sizeof(double)==8); + assert(sizeof(uint64)==8); + assert(sizeof(uint32)==4); + if (dir->tdir_count!=1) + err=TIFFReadDirEntryErrCount; + else if (dir->tdir_type!=TIFF_RATIONAL) + err=TIFFReadDirEntryErrType; + else + { + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32 offset; + offset=*(uint32*)(&dir->tdir_offset); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,m.i); + } + else + { + m.l=dir->tdir_offset.toff_long8; + err=TIFFReadDirEntryErrOk; + } + } + if (err==TIFFReadDirEntryErrOk) + { + double n; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(m.i,2); + if (m.i[0]==0) + n=0.0; + else if (m.i[0]==0xFFFFFFFF) + /* + * XXX: Numerator 0xFFFFFFFF means that we have infinite + * distance. Indicate that with a negative floating point + * SubjectDistance value. + */ + n=-1.0; + else + n=(double)m.i[0]/(double)m.i[1]; + return(TIFFSetField(tif,dir->tdir_tag,n)); + } + else + { + TIFFReadDirEntryOutputErr(tif,err,module,"SubjectDistance",TRUE); + return(0); + } +} + +/* + * Replace a single strip (tile) of uncompressed data by multiple strips + * (tiles), each approximately STRIP_SIZE_DEFAULT bytes. This is useful for + * dealing with large images or for dealing with machines with a limited + * amount memory. + */ +static void +ChopUpSingleUncompressedStrip(TIFF* tif) +{ + register TIFFDirectory *td = &tif->tif_dir; + uint64 bytecount; + uint64 offset; + uint32 rowblock; + uint64 rowblockbytes; + uint64 stripbytes; + uint32 strip; + uint64 nstrips64; + uint32 nstrips32; + uint32 rowsperstrip; + uint64* newcounts; + uint64* newoffsets; + + bytecount = td->td_stripbytecount[0]; + offset = td->td_stripoffset[0]; + assert(td->td_planarconfig == PLANARCONFIG_CONTIG); + if ((td->td_photometric == PHOTOMETRIC_YCBCR)&& + (!isUpSampled(tif))) + rowblock = td->td_ycbcrsubsampling[1]; + else + rowblock = 1; + rowblockbytes = TIFFVTileSize64(tif, rowblock); + /* + * Make the rows hold at least one scanline, but fill specified amount + * of data if possible. + */ + if (rowblockbytes > STRIP_SIZE_DEFAULT) { + stripbytes = rowblockbytes; + rowsperstrip = rowblock; + } else if (rowblockbytes > 0 ) { + uint32 rowblocksperstrip; + rowblocksperstrip = (uint32) (STRIP_SIZE_DEFAULT / rowblockbytes); + rowsperstrip = rowblocksperstrip * rowblock; + stripbytes = rowblocksperstrip * rowblockbytes; + } + else + return; + + /* + * never increase the number of strips in an image + */ + if (rowsperstrip >= td->td_rowsperstrip) + return; + nstrips64 = TIFFhowmany_64(bytecount, stripbytes); + if ((nstrips64==0)||(nstrips64>0xFFFFFFFF)) /* something is wonky, do nothing. */ + return; + nstrips32 = (uint32)nstrips64; + + newcounts = (uint64*) _TIFFCheckMalloc(tif, nstrips32, sizeof (uint64), + "for chopped \"StripByteCounts\" array"); + newoffsets = (uint64*) _TIFFCheckMalloc(tif, nstrips32, sizeof (uint64), + "for chopped \"StripOffsets\" array"); + if (newcounts == NULL || newoffsets == NULL) { + /* + * Unable to allocate new strip information, give up and use + * the original one strip information. + */ + if (newcounts != NULL) + _TIFFfree(newcounts); + if (newoffsets != NULL) + _TIFFfree(newoffsets); + return; + } + /* + * Fill the strip information arrays with new bytecounts and offsets + * that reflect the broken-up format. + */ + for (strip = 0; strip < nstrips32; strip++) { + if (stripbytes > bytecount) + stripbytes = bytecount; + newcounts[strip] = stripbytes; + newoffsets[strip] = offset; + offset += stripbytes; + bytecount -= stripbytes; + } + /* + * Replace old single strip info with multi-strip info. + */ + td->td_stripsperimage = td->td_nstrips = nstrips32; + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); + + _TIFFfree(td->td_stripbytecount); + _TIFFfree(td->td_stripoffset); + td->td_stripbytecount = newcounts; + td->td_stripoffset = newoffsets; + td->td_stripbytecountsorted = 1; +} + +int _TIFFFillStriles( TIFF *tif ) +{ +#if defined(DEFER_STRILE_LOAD) + register TIFFDirectory *td = &tif->tif_dir; + int return_value = 1; + + if( td->td_stripoffset != NULL ) + return 1; + + if( td->td_stripoffset_entry.tdir_count == 0 ) + return 0; + + if (!TIFFFetchStripThing(tif,&(td->td_stripoffset_entry), + td->td_nstrips,&td->td_stripoffset)) + { + return_value = 0; + } + + if (!TIFFFetchStripThing(tif,&(td->td_stripbytecount_entry), + td->td_nstrips,&td->td_stripbytecount)) + { + return_value = 0; + } + + _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry)); + _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry)); + + if (tif->tif_dir.td_nstrips > 1 && return_value == 1 ) { + uint32 strip; + + tif->tif_dir.td_stripbytecountsorted = 1; + for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) { + if (tif->tif_dir.td_stripoffset[strip - 1] > + tif->tif_dir.td_stripoffset[strip]) { + tif->tif_dir.td_stripbytecountsorted = 0; + break; + } + } + } + + return return_value; +#else /* !defined(DEFER_STRILE_LOAD) */ + (void) tif; + return 1; +#endif +} + + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ + #endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirwrite.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirwrite.c new file mode 100644 index 0000000000..ac13cd4916 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dirwrite.c @@ -0,0 +1,2912 @@ +/* $Id: tif_dirwrite.c,v 1.77 2012-07-06 19:18:31 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Write Support Routines. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +#ifdef HAVE_IEEEFP +#define TIFFCvtNativeToIEEEFloat(tif, n, fp) +#define TIFFCvtNativeToIEEEDouble(tif, n, dp) +#else +extern void TIFFCvtNativeToIEEEFloat(TIFF* tif, uint32 n, float* fp); +extern void TIFFCvtNativeToIEEEDouble(TIFF* tif, uint32 n, double* dp); +#endif + +static int TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff); + +static int TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value); +#if 0 +static int TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); +#endif + +static int TIFFWriteDirectoryTagAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value); +static int TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value); +#ifdef notdef +static int TIFFWriteDirectoryTagByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value); +#endif +static int TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value); +#if 0 +static int TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value); +#endif +#ifdef notdef +static int TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value); +#endif +static int TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value); +#if 0 +static int TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value); +#endif +static int TIFFWriteDirectoryTagShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value); +static int TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value); +static int TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value); +#ifdef notdef +static int TIFFWriteDirectoryTagSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value); +#endif +static int TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value); +#if 0 +static int TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value); +#endif +static int TIFFWriteDirectoryTagLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value); +static int TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value); +#if 0 +static int TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value); +#endif +#ifdef notdef +static int TIFFWriteDirectoryTagSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value); +#endif +static int TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value); +#if 0 +static int TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value); +#endif +#ifdef notdef +static int TIFFWriteDirectoryTagLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value); +#endif +static int TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); +#ifdef notdef +static int TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value); +#endif +static int TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value); +static int TIFFWriteDirectoryTagRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); +static int TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); +static int TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); +#ifdef notdef +static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value); +#endif +static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); +#if 0 +static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value); +#endif +#ifdef notdef +static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); +#endif +static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value); +#if 0 +static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); +#endif +static int TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value); +#ifdef notdef +static int TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); +#endif +static int TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value); +static int TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); +static int TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); +#ifdef notdef +static int TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); +#endif +static int TIFFWriteDirectoryTagColormap(TIFF* tif, uint32* ndir, TIFFDirEntry* dir); +static int TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32* ndir, TIFFDirEntry* dir); +static int TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32* ndir, TIFFDirEntry* dir); + +static int TIFFWriteDirectoryTagCheckedAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value); +static int TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value); +#endif +static int TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value); +#endif +static int TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value); +static int TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value); +static int TIFFWriteDirectoryTagCheckedShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value); +#endif +static int TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value); +static int TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value); +static int TIFFWriteDirectoryTagCheckedLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value); +#endif +static int TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value); +#endif +static int TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value); +#endif +static int TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value); +static int TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); +static int TIFFWriteDirectoryTagCheckedRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); +static int TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value); +#endif +static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value); +#endif +static int TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value); +static int TIFFWriteDirectoryTagCheckedIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value); +static int TIFFWriteDirectoryTagCheckedIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value); + +static int TIFFWriteDirectoryTagData(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 datatype, uint32 count, uint32 datalength, void* data); + +static int TIFFLinkDirectory(TIFF*); + +/* + * Write the contents of the current directory + * to the specified file. This routine doesn't + * handle overwriting a directory with auxiliary + * storage that's been changed. + */ +int +TIFFWriteDirectory(TIFF* tif) +{ + return TIFFWriteDirectorySec(tif,TRUE,TRUE,NULL); +} + +/* + * Similar to TIFFWriteDirectory(), writes the directory out + * but leaves all data structures in memory so that it can be + * written again. This will make a partially written TIFF file + * readable before it is successfully completed/closed. + */ +int +TIFFCheckpointDirectory(TIFF* tif) +{ + int rc; + /* Setup the strips arrays, if they haven't already been. */ + if (tif->tif_dir.td_stripoffset == NULL) + (void) TIFFSetupStrips(tif); + rc = TIFFWriteDirectorySec(tif,TRUE,FALSE,NULL); + (void) TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END)); + return rc; +} + +int +TIFFWriteCustomDirectory(TIFF* tif, uint64* pdiroff) +{ + return TIFFWriteDirectorySec(tif,FALSE,FALSE,pdiroff); +} + +/* + * Similar to TIFFWriteDirectory(), but if the directory has already + * been written once, it is relocated to the end of the file, in case it + * has changed in size. Note that this will result in the loss of the + * previously used directory space. + */ +int +TIFFRewriteDirectory( TIFF *tif ) +{ + static const char module[] = "TIFFRewriteDirectory"; + + /* We don't need to do anything special if it hasn't been written. */ + if( tif->tif_diroff == 0 ) + return TIFFWriteDirectory( tif ); + + /* + * Find and zero the pointer to this directory, so that TIFFLinkDirectory + * will cause it to be added after this directories current pre-link. + */ + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if (tif->tif_header.classic.tiff_diroff == tif->tif_diroff) + { + tif->tif_header.classic.tiff_diroff = 0; + tif->tif_diroff = 0; + + TIFFSeekFile(tif,4,SEEK_SET); + if (!WriteOK(tif, &(tif->tif_header.classic.tiff_diroff),4)) + { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error updating TIFF header"); + return (0); + } + } + else + { + uint32 nextdir; + nextdir = tif->tif_header.classic.tiff_diroff; + while(1) { + uint16 dircount; + uint32 nextnextdir; + + if (!SeekOK(tif, nextdir) || + !ReadOK(tif, &dircount, 2)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + (void) TIFFSeekFile(tif, + nextdir+2+dircount*12, SEEK_SET); + if (!ReadOK(tif, &nextnextdir, 4)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory link"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextnextdir); + if (nextnextdir==tif->tif_diroff) + { + uint32 m; + m=0; + (void) TIFFSeekFile(tif, + nextdir+2+dircount*12, SEEK_SET); + if (!WriteOK(tif, &m, 4)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + tif->tif_diroff=0; + break; + } + nextdir=nextnextdir; + } + } + } + else + { + if (tif->tif_header.big.tiff_diroff == tif->tif_diroff) + { + tif->tif_header.big.tiff_diroff = 0; + tif->tif_diroff = 0; + + TIFFSeekFile(tif,8,SEEK_SET); + if (!WriteOK(tif, &(tif->tif_header.big.tiff_diroff),8)) + { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error updating TIFF header"); + return (0); + } + } + else + { + uint64 nextdir; + nextdir = tif->tif_header.big.tiff_diroff; + while(1) { + uint64 dircount64; + uint16 dircount; + uint64 nextnextdir; + + if (!SeekOK(tif, nextdir) || + !ReadOK(tif, &dircount64, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>0xFFFF) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on tag count failed, likely corrupt TIFF"); + return (0); + } + dircount=(uint16)dircount64; + (void) TIFFSeekFile(tif, + nextdir+8+dircount*20, SEEK_SET); + if (!ReadOK(tif, &nextnextdir, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory link"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&nextnextdir); + if (nextnextdir==tif->tif_diroff) + { + uint64 m; + m=0; + (void) TIFFSeekFile(tif, + nextdir+8+dircount*20, SEEK_SET); + if (!WriteOK(tif, &m, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + tif->tif_diroff=0; + break; + } + nextdir=nextnextdir; + } + } + } + + /* + * Now use TIFFWriteDirectory() normally. + */ + + return TIFFWriteDirectory( tif ); +} + +static int +TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff) +{ + static const char module[] = "TIFFWriteDirectorySec"; + uint32 ndir; + TIFFDirEntry* dir; + uint32 dirsize; + void* dirmem; + uint32 m; + if (tif->tif_mode == O_RDONLY) + return (1); + + _TIFFFillStriles( tif ); + + /* + * Clear write state so that subsequent images with + * different characteristics get the right buffers + * setup for them. + */ + if (imagedone) + { + if (tif->tif_flags & TIFF_POSTENCODE) + { + tif->tif_flags &= ~TIFF_POSTENCODE; + if (!(*tif->tif_postencode)(tif)) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Error post-encoding before directory write"); + return (0); + } + } + (*tif->tif_close)(tif); /* shutdown encoder */ + /* + * Flush any data that might have been written + * by the compression close+cleanup routines. But + * be careful not to write stuff if we didn't add data + * in the previous steps as the "rawcc" data may well be + * a previously read tile/strip in mixed read/write mode. + */ + if (tif->tif_rawcc > 0 + && (tif->tif_flags & TIFF_BEENWRITING) != 0 ) + { + if( !TIFFFlushData1(tif) ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Error flushing data before directory write"); + return (0); + } + } + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) + { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawcc = 0; + tif->tif_rawdatasize = 0; + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = 0; + } + tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP); + } + dir=NULL; + dirmem=NULL; + dirsize=0; + while (1) + { + ndir=0; + if (isimage) + { + if (TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS)) + { + if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_IMAGEWIDTH,tif->tif_dir.td_imagewidth)) + goto bad; + if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_IMAGELENGTH,tif->tif_dir.td_imagelength)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_TILEDIMENSIONS)) + { + if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_TILEWIDTH,tif->tif_dir.td_tilewidth)) + goto bad; + if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_TILELENGTH,tif->tif_dir.td_tilelength)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_RESOLUTION)) + { + if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_XRESOLUTION,tif->tif_dir.td_xresolution)) + goto bad; + if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_YRESOLUTION,tif->tif_dir.td_yresolution)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_POSITION)) + { + if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_XPOSITION,tif->tif_dir.td_xposition)) + goto bad; + if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_YPOSITION,tif->tif_dir.td_yposition)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_SUBFILETYPE)) + { + if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_SUBFILETYPE,tif->tif_dir.td_subfiletype)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_BITSPERSAMPLE)) + { + if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_BITSPERSAMPLE,tif->tif_dir.td_bitspersample)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_COMPRESSION)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_COMPRESSION,tif->tif_dir.td_compression)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_PHOTOMETRIC,tif->tif_dir.td_photometric)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_THRESHHOLDING)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_THRESHHOLDING,tif->tif_dir.td_threshholding)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_FILLORDER)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_FILLORDER,tif->tif_dir.td_fillorder)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_ORIENTATION)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_ORIENTATION,tif->tif_dir.td_orientation)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_SAMPLESPERPIXEL,tif->tif_dir.td_samplesperpixel)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_ROWSPERSTRIP)) + { + if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_ROWSPERSTRIP,tif->tif_dir.td_rowsperstrip)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_MINSAMPLEVALUE)) + { + if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_MINSAMPLEVALUE,tif->tif_dir.td_minsamplevalue)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE)) + { + if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_MAXSAMPLEVALUE,tif->tif_dir.td_maxsamplevalue)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_PLANARCONFIG)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_PLANARCONFIG,tif->tif_dir.td_planarconfig)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_RESOLUTIONUNIT)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_RESOLUTIONUNIT,tif->tif_dir.td_resolutionunit)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_PAGENUMBER)) + { + if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_PAGENUMBER,2,&tif->tif_dir.td_pagenumber[0])) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_STRIPBYTECOUNTS)) + { + if (!isTiled(tif)) + { + if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount)) + goto bad; + } + else + { + if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount)) + goto bad; + } + } + if (TIFFFieldSet(tif,FIELD_STRIPOFFSETS)) + { + if (!isTiled(tif)) + { + if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset)) + goto bad; + } + else + { + if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset)) + goto bad; + } + } + if (TIFFFieldSet(tif,FIELD_COLORMAP)) + { + if (!TIFFWriteDirectoryTagColormap(tif,&ndir,dir)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_EXTRASAMPLES)) + { + if (tif->tif_dir.td_extrasamples) + { + uint16 na; + uint16* nb; + TIFFGetFieldDefaulted(tif,TIFFTAG_EXTRASAMPLES,&na,&nb); + if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_EXTRASAMPLES,na,nb)) + goto bad; + } + } + if (TIFFFieldSet(tif,FIELD_SAMPLEFORMAT)) + { + if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_SAMPLEFORMAT,tif->tif_dir.td_sampleformat)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE)) + { + if (!TIFFWriteDirectoryTagSampleformatArray(tif,&ndir,dir,TIFFTAG_SMINSAMPLEVALUE,tif->tif_dir.td_samplesperpixel,tif->tif_dir.td_sminsamplevalue)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE)) + { + if (!TIFFWriteDirectoryTagSampleformatArray(tif,&ndir,dir,TIFFTAG_SMAXSAMPLEVALUE,tif->tif_dir.td_samplesperpixel,tif->tif_dir.td_smaxsamplevalue)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_IMAGEDEPTH)) + { + if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_IMAGEDEPTH,tif->tif_dir.td_imagedepth)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_TILEDEPTH)) + { + if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_TILEDEPTH,tif->tif_dir.td_tiledepth)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_HALFTONEHINTS)) + { + if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_HALFTONEHINTS,2,&tif->tif_dir.td_halftonehints[0])) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_YCBCRSUBSAMPLING)) + { + if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_YCBCRSUBSAMPLING,2,&tif->tif_dir.td_ycbcrsubsampling[0])) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_YCBCRPOSITIONING)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_YCBCRPOSITIONING,tif->tif_dir.td_ycbcrpositioning)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_REFBLACKWHITE)) + { + if (!TIFFWriteDirectoryTagRationalArray(tif,&ndir,dir,TIFFTAG_REFERENCEBLACKWHITE,6,tif->tif_dir.td_refblackwhite)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_TRANSFERFUNCTION)) + { + if (!TIFFWriteDirectoryTagTransferfunction(tif,&ndir,dir)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_INKNAMES)) + { + if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,TIFFTAG_INKNAMES,tif->tif_dir.td_inknameslen,tif->tif_dir.td_inknames)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_SUBIFD)) + { + if (!TIFFWriteDirectoryTagSubifd(tif,&ndir,dir)) + goto bad; + } + { + uint32 n; + for (n=0; ntif_nfields; n++) { + const TIFFField* o; + o = tif->tif_fields[n]; + if ((o->field_bit>=FIELD_CODEC)&&(TIFFFieldSet(tif,o->field_bit))) + { + switch (o->get_field_type) + { + case TIFF_SETGET_ASCII: + { + uint32 pa; + char* pb; + assert(o->field_type==TIFF_ASCII); + assert(o->field_readcount==TIFF_VARIABLE); + assert(o->field_passcount==0); + TIFFGetField(tif,o->field_tag,&pb); + pa=(uint32)(strlen(pb)); + if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,o->field_tag,pa,pb)) + goto bad; + } + break; + case TIFF_SETGET_UINT16: + { + uint16 p; + assert(o->field_type==TIFF_SHORT); + assert(o->field_readcount==1); + assert(o->field_passcount==0); + TIFFGetField(tif,o->field_tag,&p); + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,o->field_tag,p)) + goto bad; + } + break; + case TIFF_SETGET_UINT32: + { + uint32 p; + assert(o->field_type==TIFF_LONG); + assert(o->field_readcount==1); + assert(o->field_passcount==0); + TIFFGetField(tif,o->field_tag,&p); + if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,o->field_tag,p)) + goto bad; + } + break; + case TIFF_SETGET_C32_UINT8: + { + uint32 pa; + void* pb; + assert(o->field_type==TIFF_UNDEFINED); + assert(o->field_readcount==TIFF_VARIABLE2); + assert(o->field_passcount==1); + TIFFGetField(tif,o->field_tag,&pa,&pb); + if (!TIFFWriteDirectoryTagUndefinedArray(tif,&ndir,dir,o->field_tag,pa,pb)) + goto bad; + } + break; + default: + assert(0); /* we should never get here */ + break; + } + } + } + } + } + for (m=0; m<(uint32)(tif->tif_dir.td_customValueCount); m++) + { + switch (tif->tif_dir.td_customValues[m].info->field_type) + { + case TIFF_ASCII: + if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_UNDEFINED: + if (!TIFFWriteDirectoryTagUndefinedArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_BYTE: + if (!TIFFWriteDirectoryTagByteArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_SBYTE: + if (!TIFFWriteDirectoryTagSbyteArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_SHORT: + if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_SSHORT: + if (!TIFFWriteDirectoryTagSshortArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_LONG: + if (!TIFFWriteDirectoryTagLongArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_SLONG: + if (!TIFFWriteDirectoryTagSlongArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_LONG8: + if (!TIFFWriteDirectoryTagLong8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_SLONG8: + if (!TIFFWriteDirectoryTagSlong8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_RATIONAL: + if (!TIFFWriteDirectoryTagRationalArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_SRATIONAL: + if (!TIFFWriteDirectoryTagSrationalArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_FLOAT: + if (!TIFFWriteDirectoryTagFloatArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_DOUBLE: + if (!TIFFWriteDirectoryTagDoubleArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_IFD: + if (!TIFFWriteDirectoryTagIfdArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_IFD8: + if (!TIFFWriteDirectoryTagIfdIfd8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + default: + assert(0); /* we should never get here */ + break; + } + } + if (dir!=NULL) + break; + dir=_TIFFmalloc(ndir*sizeof(TIFFDirEntry)); + if (dir==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + goto bad; + } + if (isimage) + { + if ((tif->tif_diroff==0)&&(!TIFFLinkDirectory(tif))) + goto bad; + } + else + tif->tif_diroff=(TIFFSeekFile(tif,0,SEEK_END)+1)&(~1); + if (pdiroff!=NULL) + *pdiroff=tif->tif_diroff; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + dirsize=2+ndir*12+4; + else + dirsize=8+ndir*20+8; + tif->tif_dataoff=tif->tif_diroff+dirsize; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + tif->tif_dataoff=(uint32)tif->tif_dataoff; + if ((tif->tif_dataofftif_diroff)||(tif->tif_dataoff<(uint64)dirsize)) + { + TIFFErrorExt(tif->tif_clientdata,module,"Maximum TIFF file size exceeded"); + goto bad; + } + if (tif->tif_dataoff&1) + tif->tif_dataoff++; + if (isimage) + tif->tif_curdir++; + } + if (isimage) + { + if (TIFFFieldSet(tif,FIELD_SUBIFD)&&(tif->tif_subifdoff==0)) + { + uint32 na; + TIFFDirEntry* nb; + for (na=0, nb=dir; ; na++, nb++) + { + assert(natdir_tag==TIFFTAG_SUBIFD) + break; + } + if (!(tif->tif_flags&TIFF_BIGTIFF)) + tif->tif_subifdoff=tif->tif_diroff+2+na*12+8; + else + tif->tif_subifdoff=tif->tif_diroff+8+na*20+12; + } + } + dirmem=_TIFFmalloc(dirsize); + if (dirmem==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + goto bad; + } + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint8* n; + uint32 nTmp; + TIFFDirEntry* o; + n=dirmem; + *(uint16*)n=ndir; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)n); + n+=2; + o=dir; + for (m=0; mtdir_tag; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)n); + n+=2; + *(uint16*)n=o->tdir_type; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)n); + n+=2; + nTmp = (uint32)o->tdir_count; + _TIFFmemcpy(n,&nTmp,4); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)n); + n+=4; + /* This is correct. The data has been */ + /* swabbed previously in TIFFWriteDirectoryTagData */ + _TIFFmemcpy(n,&o->tdir_offset,4); + n+=4; + o++; + } + nTmp = (uint32)tif->tif_nextdiroff; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&nTmp); + _TIFFmemcpy(n,&nTmp,4); + } + else + { + uint8* n; + TIFFDirEntry* o; + n=dirmem; + *(uint64*)n=ndir; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)n); + n+=8; + o=dir; + for (m=0; mtdir_tag; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)n); + n+=2; + *(uint16*)n=o->tdir_type; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)n); + n+=2; + _TIFFmemcpy(n,&o->tdir_count,8); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)n); + n+=8; + _TIFFmemcpy(n,&o->tdir_offset,8); + n+=8; + o++; + } + _TIFFmemcpy(n,&tif->tif_nextdiroff,8); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)n); + } + _TIFFfree(dir); + dir=NULL; + if (!SeekOK(tif,tif->tif_diroff)) + { + TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory"); + goto bad; + } + if (!WriteOK(tif,dirmem,(tmsize_t)dirsize)) + { + TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory"); + goto bad; + } + _TIFFfree(dirmem); + if (imagedone) + { + TIFFFreeDirectory(tif); + tif->tif_flags &= ~TIFF_DIRTYDIRECT; + tif->tif_flags &= ~TIFF_DIRTYSTRIP; + (*tif->tif_cleanup)(tif); + /* + * Reset directory-related state for subsequent + * directories. + */ + TIFFCreateDirectory(tif); + } + return(1); +bad: + if (dir!=NULL) + _TIFFfree(dir); + if (dirmem!=NULL) + _TIFFfree(dirmem); + return(0); +} + +static int +TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value) +{ + static const char module[] = "TIFFWriteDirectoryTagSampleformatArray"; + void* conv; + uint32 i; + int ok; + conv = _TIFFmalloc(count*sizeof(double)); + if (conv == NULL) + { + TIFFErrorExt(tif->tif_clientdata, module, "Out of memory"); + return (0); + } + + switch (tif->tif_dir.td_sampleformat) + { + case SAMPLEFORMAT_IEEEFP: + if (tif->tif_dir.td_bitspersample<=32) + { + for (i = 0; i < count; ++i) + ((float*)conv)[i] = (float)value[i]; + ok = TIFFWriteDirectoryTagFloatArray(tif,ndir,dir,tag,count,(float*)conv); + } + else + { + ok = TIFFWriteDirectoryTagDoubleArray(tif,ndir,dir,tag,count,value); + } + break; + case SAMPLEFORMAT_INT: + if (tif->tif_dir.td_bitspersample<=8) + { + for (i = 0; i < count; ++i) + ((int8*)conv)[i] = (int8)value[i]; + ok = TIFFWriteDirectoryTagSbyteArray(tif,ndir,dir,tag,count,(int8*)conv); + } + else if (tif->tif_dir.td_bitspersample<=16) + { + for (i = 0; i < count; ++i) + ((int16*)conv)[i] = (int16)value[i]; + ok = TIFFWriteDirectoryTagSshortArray(tif,ndir,dir,tag,count,(int16*)conv); + } + else + { + for (i = 0; i < count; ++i) + ((int32*)conv)[i] = (int32)value[i]; + ok = TIFFWriteDirectoryTagSlongArray(tif,ndir,dir,tag,count,(int32*)conv); + } + break; + case SAMPLEFORMAT_UINT: + if (tif->tif_dir.td_bitspersample<=8) + { + for (i = 0; i < count; ++i) + ((uint8*)conv)[i] = (uint8)value[i]; + ok = TIFFWriteDirectoryTagByteArray(tif,ndir,dir,tag,count,(uint8*)conv); + } + else if (tif->tif_dir.td_bitspersample<=16) + { + for (i = 0; i < count; ++i) + ((uint16*)conv)[i] = (uint16)value[i]; + ok = TIFFWriteDirectoryTagShortArray(tif,ndir,dir,tag,count,(uint16*)conv); + } + else + { + for (i = 0; i < count; ++i) + ((uint32*)conv)[i] = (uint32)value[i]; + ok = TIFFWriteDirectoryTagLongArray(tif,ndir,dir,tag,count,(uint32*)conv); + } + break; + default: + ok = 0; + } + + _TIFFfree(conv); + return (ok); +} + +#if 0 +static int +TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) +{ + switch (tif->tif_dir.td_sampleformat) + { + case SAMPLEFORMAT_IEEEFP: + if (tif->tif_dir.td_bitspersample<=32) + return(TIFFWriteDirectoryTagFloatPerSample(tif,ndir,dir,tag,(float)value)); + else + return(TIFFWriteDirectoryTagDoublePerSample(tif,ndir,dir,tag,value)); + case SAMPLEFORMAT_INT: + if (tif->tif_dir.td_bitspersample<=8) + return(TIFFWriteDirectoryTagSbytePerSample(tif,ndir,dir,tag,(int8)value)); + else if (tif->tif_dir.td_bitspersample<=16) + return(TIFFWriteDirectoryTagSshortPerSample(tif,ndir,dir,tag,(int16)value)); + else + return(TIFFWriteDirectoryTagSlongPerSample(tif,ndir,dir,tag,(int32)value)); + case SAMPLEFORMAT_UINT: + if (tif->tif_dir.td_bitspersample<=8) + return(TIFFWriteDirectoryTagBytePerSample(tif,ndir,dir,tag,(uint8)value)); + else if (tif->tif_dir.td_bitspersample<=16) + return(TIFFWriteDirectoryTagShortPerSample(tif,ndir,dir,tag,(uint16)value)); + else + return(TIFFWriteDirectoryTagLongPerSample(tif,ndir,dir,tag,(uint32)value)); + default: + return(1); + } +} +#endif + +static int +TIFFWriteDirectoryTagAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedAscii(tif,ndir,dir,tag,count,value)); +} + +static int +TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedUndefinedArray(tif,ndir,dir,tag,count,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedByte(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int +TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value) +{ + static const char module[] = "TIFFWriteDirectoryTagBytePerSample"; + uint8* m; + uint8* na; + uint16 nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint8)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +#ifdef notdef +static int +TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSbyte(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int +TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value) +{ + static const char module[] = "TIFFWriteDirectoryTagSbytePerSample"; + int8* m; + int8* na; + uint16 nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int8)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +static int +TIFFWriteDirectoryTagShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,value)); +} + +static int +TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,value)); +} + +static int +TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value) +{ + static const char module[] = "TIFFWriteDirectoryTagShortPerSample"; + uint16* m; + uint16* na; + uint16 nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint16)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSshort(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int +TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value) +{ + static const char module[] = "TIFFWriteDirectoryTagSshortPerSample"; + int16* m; + int16* na; + uint16 nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int16)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +static int +TIFFWriteDirectoryTagLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value)); +} + +static int +TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int +TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value) +{ + static const char module[] = "TIFFWriteDirectoryTagLongPerSample"; + uint32* m; + uint32* na; + uint16 nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint32)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +#ifdef notdef +static int +TIFFWriteDirectoryTagSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSlong(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int +TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value) +{ + static const char module[] = "TIFFWriteDirectoryTagSlongPerSample"; + int32* m; + int32* na; + uint16 nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int32)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +#ifdef notdef +static int +TIFFWriteDirectoryTagLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedLong8(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,tag,count,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSlong8(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSlong8Array(tif,ndir,dir,tag,count,value)); +} + +static int +TIFFWriteDirectoryTagRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedRational(tif,ndir,dir,tag,value)); +} + +static int +TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedRationalArray(tif,ndir,dir,tag,count,value)); +} + +static int +TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSrationalArray(tif,ndir,dir,tag,count,value)); +} + +#ifdef notdef +static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedFloat(tif,ndir,dir,tag,value)); +} +#endif + +static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value) +{ + static const char module[] = "TIFFWriteDirectoryTagFloatPerSample"; + float* m; + float* na; + uint16 nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(float)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +#ifdef notdef +static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedDouble(tif,ndir,dir,tag,value)); +} +#endif + +static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) +{ + static const char module[] = "TIFFWriteDirectoryTagDoublePerSample"; + double* m; + double* na; + uint16 nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(double)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +static int +TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,tag,count,value)); +} +#endif + +static int +TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + if (value<=0xFFFF) + return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,(uint16)value)); + else + return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value)); +} + +/************************************************************************/ +/* TIFFWriteDirectoryTagLongLong8Array() */ +/* */ +/* Write out LONG8 array as LONG8 for BigTIFF or LONG for */ +/* Classic TIFF with some checking. */ +/************************************************************************/ + +static int +TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) +{ + static const char module[] = "TIFFWriteDirectoryTagLongLong8Array"; + uint64* ma; + uint32 mb; + uint32* p; + uint32* q; + int o; + + /* is this just a counting pass? */ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + + /* We always write LONG8 for BigTIFF, no checking needed. */ + if( tif->tif_flags&TIFF_BIGTIFF ) + return TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir, + tag,count,value); + + /* + ** For classic tiff we want to verify everything is in range for LONG + ** and convert to long format. + */ + + p = _TIFFmalloc(count*sizeof(uint32)); + if (p==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + + for (q=p, ma=value, mb=0; mb0xFFFFFFFF) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Attempt to write value larger than 0xFFFFFFFF in Classic TIFF file."); + _TIFFfree(p); + return(0); + } + *q= (uint32)(*ma); + } + + o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p); + _TIFFfree(p); + + return(o); +} + +/************************************************************************/ +/* TIFFWriteDirectoryTagIfdIfd8Array() */ +/* */ +/* Write either IFD8 or IFD array depending on file type. */ +/************************************************************************/ + +static int +TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) +{ + static const char module[] = "TIFFWriteDirectoryTagIfdIfd8Array"; + uint64* ma; + uint32 mb; + uint32* p; + uint32* q; + int o; + + /* is this just a counting pass? */ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + + /* We always write IFD8 for BigTIFF, no checking needed. */ + if( tif->tif_flags&TIFF_BIGTIFF ) + return TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir, + tag,count,value); + + /* + ** For classic tiff we want to verify everything is in range for IFD + ** and convert to long format. + */ + + p = _TIFFmalloc(count*sizeof(uint32)); + if (p==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + + for (q=p, ma=value, mb=0; mb0xFFFFFFFF) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Attempt to write value larger than 0xFFFFFFFF in Classic TIFF file."); + _TIFFfree(p); + return(0); + } + *q= (uint32)(*ma); + } + + o=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,p); + _TIFFfree(p); + + return(o); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) +{ + static const char module[] = "TIFFWriteDirectoryTagShortLongLong8Array"; + uint64* ma; + uint32 mb; + uint8 n; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + n=0; + for (ma=value, mb=0; mb0xFFFF)) + n=1; + if ((n==1)&&(*ma>0xFFFFFFFF)) + { + n=2; + break; + } + } + if (n==0) + { + uint16* p; + uint16* q; + p=_TIFFmalloc(count*sizeof(uint16)); + if (p==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (ma=value, mb=0, q=p; mbtif_clientdata,module,"Out of memory"); + return(0); + } + for (ma=value, mb=0, q=p; mbtif_dir.td_bitspersample); + n=_TIFFmalloc(3*m*sizeof(uint16)); + if (n==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + _TIFFmemcpy(&n[0],tif->tif_dir.td_colormap[0],m*sizeof(uint16)); + _TIFFmemcpy(&n[m],tif->tif_dir.td_colormap[1],m*sizeof(uint16)); + _TIFFmemcpy(&n[2*m],tif->tif_dir.td_colormap[2],m*sizeof(uint16)); + o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_COLORMAP,3*m,n); + _TIFFfree(n); + return(o); +} + +static int +TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32* ndir, TIFFDirEntry* dir) +{ + static const char module[] = "TIFFWriteDirectoryTagTransferfunction"; + uint32 m; + uint16 n; + uint16* o; + int p; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=(1<tif_dir.td_bitspersample); + n=tif->tif_dir.td_samplesperpixel-tif->tif_dir.td_extrasamples; + /* + * Check if the table can be written as a single column, + * or if it must be written as 3 columns. Note that we + * write a 3-column tag if there are 2 samples/pixel and + * a single column of data won't suffice--hmm. + */ + if (n>3) + n=3; + if (n==3) + { + if (!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16))) + n=2; + } + if (n==2) + { + if (!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16))) + n=1; + } + if (n==0) + n=1; + o=_TIFFmalloc(n*m*sizeof(uint16)); + if (o==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + _TIFFmemcpy(&o[0],tif->tif_dir.td_transferfunction[0],m*sizeof(uint16)); + if (n>1) + _TIFFmemcpy(&o[m],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16)); + if (n>2) + _TIFFmemcpy(&o[2*m],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16)); + p=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_TRANSFERFUNCTION,n*m,o); + _TIFFfree(o); + return(p); +} + +static int +TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32* ndir, TIFFDirEntry* dir) +{ + static const char module[] = "TIFFWriteDirectoryTagSubifd"; + uint64 m; + int n; + if (tif->tif_dir.td_nsubifd==0) + return(1); + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=tif->tif_dataoff; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32* o; + uint64* pa; + uint32* pb; + uint16 p; + o=_TIFFmalloc(tif->tif_dir.td_nsubifd*sizeof(uint32)); + if (o==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + pa=tif->tif_dir.td_subifd; + pb=o; + for (p=0; p < tif->tif_dir.td_nsubifd; p++) + { + assert(pa != 0); + assert(*pa <= 0xFFFFFFFFUL); + *pb++=(uint32)(*pa++); + } + n=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,TIFFTAG_SUBIFD,tif->tif_dir.td_nsubifd,o); + _TIFFfree(o); + } + else + n=TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,TIFFTAG_SUBIFD,tif->tif_dir.td_nsubifd,tif->tif_dir.td_subifd); + if (!n) + return(0); + /* + * Total hack: if this directory includes a SubIFD + * tag then force the next directories to be + * written as ``sub directories'' of this one. This + * is used to write things like thumbnails and + * image masks that one wants to keep out of the + * normal directory linkage access mechanism. + */ + tif->tif_flags|=TIFF_INSUBIFD; + tif->tif_nsubifd=tif->tif_dir.td_nsubifd; + if (tif->tif_dir.td_nsubifd==1) + tif->tif_subifdoff=0; + else + tif->tif_subifdoff=m; + return(1); +} + +static int +TIFFWriteDirectoryTagCheckedAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value) +{ + assert(sizeof(char)==1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_ASCII,count,count,value)); +} + +static int +TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value) +{ + assert(sizeof(uint8)==1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_UNDEFINED,count,count,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value) +{ + assert(sizeof(uint8)==1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,1,1,&value)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value) +{ + assert(sizeof(uint8)==1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,count,count,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value) +{ + assert(sizeof(int8)==1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,1,1,&value)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value) +{ + assert(sizeof(int8)==1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,count,count,value)); +} + +static int +TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value) +{ + uint16 m; + assert(sizeof(uint16)==2); + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort(&m); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SHORT,1,2,&m)); +} + +static int +TIFFWriteDirectoryTagCheckedShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value) +{ + assert(count<0x80000000); + assert(sizeof(uint16)==2); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfShort(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SHORT,count,count*2,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value) +{ + int16 m; + assert(sizeof(int16)==2); + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16*)(&m)); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,1,2,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value) +{ + assert(count<0x80000000); + assert(sizeof(int16)==2); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfShort((uint16*)value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,count,count*2,value)); +} + +static int +TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value) +{ + uint32 m; + assert(sizeof(uint32)==4); + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&m); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG,1,4,&m)); +} + +static int +TIFFWriteDirectoryTagCheckedLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value) +{ + assert(count<0x40000000); + assert(sizeof(uint32)==4); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG,count,count*4,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value) +{ + int32 m; + assert(sizeof(int32)==4); + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong((uint32*)(&m)); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,1,4,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value) +{ + assert(count<0x40000000); + assert(sizeof(int32)==4); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong((uint32*)value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,count,count*4,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value) +{ + uint64 m; + assert(sizeof(uint64)==8); + assert(tif->tif_flags&TIFF_BIGTIFF); + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(&m); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,1,8,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) +{ + assert(count<0x20000000); + assert(sizeof(uint64)==8); + assert(tif->tif_flags&TIFF_BIGTIFF); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,count,count*8,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value) +{ + int64 m; + assert(sizeof(int64)==8); + assert(tif->tif_flags&TIFF_BIGTIFF); + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64*)(&m)); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,1,8,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value) +{ + assert(count<0x20000000); + assert(sizeof(int64)==8); + assert(tif->tif_flags&TIFF_BIGTIFF); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8((uint64*)value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,count,count*8,value)); +} + +static int +TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) +{ + uint32 m[2]; + assert(value>=0.0); + assert(sizeof(uint32)==4); + if (value<=0.0) + { + m[0]=0; + m[1]=1; + } + else if (value==(double)(uint32)value) + { + m[0]=(uint32)value; + m[1]=1; + } + else if (value<1.0) + { + m[0]=(uint32)(value*0xFFFFFFFF); + m[1]=0xFFFFFFFF; + } + else + { + m[0]=0xFFFFFFFF; + m[1]=(uint32)(0xFFFFFFFF/value); + } + if (tif->tif_flags&TIFF_SWAB) + { + TIFFSwabLong(&m[0]); + TIFFSwabLong(&m[1]); + } + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_RATIONAL,1,8,&m[0])); +} + +static int +TIFFWriteDirectoryTagCheckedRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value) +{ + static const char module[] = "TIFFWriteDirectoryTagCheckedRationalArray"; + uint32* m; + float* na; + uint32* nb; + uint32 nc; + int o; + assert(sizeof(uint32)==4); + m=_TIFFmalloc(count*2*sizeof(uint32)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=value, nb=m, nc=0; nctif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(m,count*2); + o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_RATIONAL,count,count*8,&m[0]); + _TIFFfree(m); + return(o); +} + +static int +TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value) +{ + static const char module[] = "TIFFWriteDirectoryTagCheckedSrationalArray"; + int32* m; + float* na; + int32* nb; + uint32 nc; + int o; + assert(sizeof(int32)==4); + m=_TIFFmalloc(count*2*sizeof(int32)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=value, nb=m, nc=0; nc-1.0) + { + nb[0]=-(int32)((-*na)*0x7FFFFFFF); + nb[1]=0x7FFFFFFF; + } + else + { + nb[0]=-0x7FFFFFFF; + nb[1]=(int32)(0x7FFFFFFF/(-*na)); + } + } + else + { + if (*na==(int32)(*na)) + { + nb[0]=(int32)(*na); + nb[1]=1; + } + else if (*na<1.0) + { + nb[0]=(int32)((*na)*0x7FFFFFFF); + nb[1]=0x7FFFFFFF; + } + else + { + nb[0]=0x7FFFFFFF; + nb[1]=(int32)(0x7FFFFFFF/(*na)); + } + } + } + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong((uint32*)m,count*2); + o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SRATIONAL,count,count*8,&m[0]); + _TIFFfree(m); + return(o); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value) +{ + float m; + assert(sizeof(float)==4); + m=value; + TIFFCvtNativeToIEEEFloat(tif,1,&m); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabFloat(&m); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_FLOAT,1,4,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value) +{ + assert(count<0x40000000); + assert(sizeof(float)==4); + TIFFCvtNativeToIEEEFloat(tif,count,&value); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfFloat(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_FLOAT,count,count*4,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value) +{ + double m; + assert(sizeof(double)==8); + m=value; + TIFFCvtNativeToIEEEDouble(tif,1,&m); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabDouble(&m); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_DOUBLE,1,8,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value) +{ + assert(count<0x20000000); + assert(sizeof(double)==8); + TIFFCvtNativeToIEEEDouble(tif,count,&value); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfDouble(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_DOUBLE,count,count*8,value)); +} + +static int +TIFFWriteDirectoryTagCheckedIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value) +{ + assert(count<0x40000000); + assert(sizeof(uint32)==4); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_IFD,count,count*4,value)); +} + +static int +TIFFWriteDirectoryTagCheckedIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) +{ + assert(count<0x20000000); + assert(sizeof(uint64)==8); + assert(tif->tif_flags&TIFF_BIGTIFF); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_IFD8,count,count*8,value)); +} + +static int +TIFFWriteDirectoryTagData(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 datatype, uint32 count, uint32 datalength, void* data) +{ + static const char module[] = "TIFFWriteDirectoryTagData"; + uint32 m; + m=0; + while (m<(*ndir)) + { + assert(dir[m].tdir_tag!=tag); + if (dir[m].tdir_tag>tag) + break; + m++; + } + if (m<(*ndir)) + { + uint32 n; + for (n=*ndir; n>m; n--) + dir[n]=dir[n-1]; + } + dir[m].tdir_tag=tag; + dir[m].tdir_type=datatype; + dir[m].tdir_count=count; + dir[m].tdir_offset.toff_long8 = 0; + if (datalength<=((tif->tif_flags&TIFF_BIGTIFF)?0x8U:0x4U)) + _TIFFmemcpy(&dir[m].tdir_offset,data,datalength); + else + { + uint64 na,nb; + na=tif->tif_dataoff; + nb=na+datalength; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + nb=(uint32)nb; + if ((nbtif_clientdata,module,"Maximum TIFF file size exceeded"); + return(0); + } + if (!SeekOK(tif,na)) + { + TIFFErrorExt(tif->tif_clientdata,module,"IO error writing tag data"); + return(0); + } + assert(datalength<0x80000000UL); + if (!WriteOK(tif,data,(tmsize_t)datalength)) + { + TIFFErrorExt(tif->tif_clientdata,module,"IO error writing tag data"); + return(0); + } + tif->tif_dataoff=nb; + if (tif->tif_dataoff&1) + tif->tif_dataoff++; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32 o; + o=(uint32)na; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&o); + _TIFFmemcpy(&dir[m].tdir_offset,&o,4); + } + else + { + dir[m].tdir_offset.toff_long8 = na; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(&dir[m].tdir_offset.toff_long8); + } + } + (*ndir)++; + return(1); +} + +/* + * Link the current directory into the directory chain for the file. + */ +static int +TIFFLinkDirectory(TIFF* tif) +{ + static const char module[] = "TIFFLinkDirectory"; + + tif->tif_diroff = (TIFFSeekFile(tif,0,SEEK_END)+1) &~ 1; + + /* + * Handle SubIFDs + */ + if (tif->tif_flags & TIFF_INSUBIFD) + { + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32 m; + m = (uint32)tif->tif_diroff; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&m); + (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET); + if (!WriteOK(tif, &m, 4)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing SubIFD directory link"); + return (0); + } + /* + * Advance to the next SubIFD or, if this is + * the last one configured, revert back to the + * normal directory linkage. + */ + if (--tif->tif_nsubifd) + tif->tif_subifdoff += 4; + else + tif->tif_flags &= ~TIFF_INSUBIFD; + return (1); + } + else + { + uint64 m; + m = tif->tif_diroff; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&m); + (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET); + if (!WriteOK(tif, &m, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing SubIFD directory link"); + return (0); + } + /* + * Advance to the next SubIFD or, if this is + * the last one configured, revert back to the + * normal directory linkage. + */ + if (--tif->tif_nsubifd) + tif->tif_subifdoff += 8; + else + tif->tif_flags &= ~TIFF_INSUBIFD; + return (1); + } + } + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32 m; + uint32 nextdir; + m = (uint32)(tif->tif_diroff); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&m); + if (tif->tif_header.classic.tiff_diroff == 0) { + /* + * First directory, overwrite offset in header. + */ + tif->tif_header.classic.tiff_diroff = (uint32) tif->tif_diroff; + (void) TIFFSeekFile(tif,4, SEEK_SET); + if (!WriteOK(tif, &m, 4)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing TIFF header"); + return (0); + } + return (1); + } + /* + * Not the first directory, search to the last and append. + */ + nextdir = tif->tif_header.classic.tiff_diroff; + while(1) { + uint16 dircount; + uint32 nextnextdir; + + if (!SeekOK(tif, nextdir) || + !ReadOK(tif, &dircount, 2)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + (void) TIFFSeekFile(tif, + nextdir+2+dircount*12, SEEK_SET); + if (!ReadOK(tif, &nextnextdir, 4)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory link"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextnextdir); + if (nextnextdir==0) + { + (void) TIFFSeekFile(tif, + nextdir+2+dircount*12, SEEK_SET); + if (!WriteOK(tif, &m, 4)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + break; + } + nextdir=nextnextdir; + } + } + else + { + uint64 m; + uint64 nextdir; + m = tif->tif_diroff; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&m); + if (tif->tif_header.big.tiff_diroff == 0) { + /* + * First directory, overwrite offset in header. + */ + tif->tif_header.big.tiff_diroff = tif->tif_diroff; + (void) TIFFSeekFile(tif,8, SEEK_SET); + if (!WriteOK(tif, &m, 8)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing TIFF header"); + return (0); + } + return (1); + } + /* + * Not the first directory, search to the last and append. + */ + nextdir = tif->tif_header.big.tiff_diroff; + while(1) { + uint64 dircount64; + uint16 dircount; + uint64 nextnextdir; + + if (!SeekOK(tif, nextdir) || + !ReadOK(tif, &dircount64, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>0xFFFF) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on tag count failed, likely corrupt TIFF"); + return (0); + } + dircount=(uint16)dircount64; + (void) TIFFSeekFile(tif, + nextdir+8+dircount*20, SEEK_SET); + if (!ReadOK(tif, &nextnextdir, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory link"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&nextnextdir); + if (nextnextdir==0) + { + (void) TIFFSeekFile(tif, + nextdir+8+dircount*20, SEEK_SET); + if (!WriteOK(tif, &m, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + break; + } + nextdir=nextnextdir; + } + } + return (1); +} + +/************************************************************************/ +/* TIFFRewriteField() */ +/* */ +/* Rewrite a field in the directory on disk without regard to */ +/* updating the TIFF directory structure in memory. Currently */ +/* only supported for field that already exist in the on-disk */ +/* directory. Mainly used for updating stripoffset / */ +/* stripbytecount values after the directory is already on */ +/* disk. */ +/* */ +/* Returns zero on failure, and one on success. */ +/************************************************************************/ + +int +_TIFFRewriteField(TIFF* tif, uint16 tag, TIFFDataType in_datatype, + tmsize_t count, void* data) +{ + static const char module[] = "TIFFResetField"; + /* const TIFFField* fip = NULL; */ + uint16 dircount; + tmsize_t dirsize; + uint8 direntry_raw[20]; + uint16 entry_tag = 0; + uint16 entry_type = 0; + uint64 entry_count = 0; + uint64 entry_offset = 0; + int value_in_entry = 0; + uint64 read_offset; + uint8 *buf_to_write = NULL; + TIFFDataType datatype; + +/* -------------------------------------------------------------------- */ +/* Find field definition. */ +/* -------------------------------------------------------------------- */ + /*fip =*/ TIFFFindField(tif, tag, TIFF_ANY); + +/* -------------------------------------------------------------------- */ +/* Do some checking this is a straight forward case. */ +/* -------------------------------------------------------------------- */ + if( isMapped(tif) ) + { + TIFFErrorExt( tif->tif_clientdata, module, + "Memory mapped files not currently supported for this operation." ); + return 0; + } + + if( tif->tif_diroff == 0 ) + { + TIFFErrorExt( tif->tif_clientdata, module, + "Attempt to reset field on directory not already on disk." ); + return 0; + } + +/* -------------------------------------------------------------------- */ +/* Read the directory entry count. */ +/* -------------------------------------------------------------------- */ + if (!SeekOK(tif, tif->tif_diroff)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Seek error accessing TIFF directory", + tif->tif_name); + return 0; + } + + read_offset = tif->tif_diroff; + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if (!ReadOK(tif, &dircount, sizeof (uint16))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + dirsize = 12; + read_offset += 2; + } else { + uint64 dircount64; + if (!ReadOK(tif, &dircount64, sizeof (uint64))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + dircount = (uint16)dircount64; + dirsize = 20; + read_offset += 8; + } + +/* -------------------------------------------------------------------- */ +/* Read through directory to find target tag. */ +/* -------------------------------------------------------------------- */ + while( dircount > 0 ) + { + if (!ReadOK(tif, direntry_raw, dirsize)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory entry.", + tif->tif_name); + return 0; + } + + memcpy( &entry_tag, direntry_raw + 0, sizeof(uint16) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort( &entry_tag ); + + if( entry_tag == tag ) + break; + + read_offset += dirsize; + } + + if( entry_tag != tag ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Could not find tag %d.", + tif->tif_name, tag ); + return 0; + } + +/* -------------------------------------------------------------------- */ +/* Extract the type, count and offset for this entry. */ +/* -------------------------------------------------------------------- */ + memcpy( &entry_type, direntry_raw + 2, sizeof(uint16) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort( &entry_type ); + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32 value; + + memcpy( &value, direntry_raw + 4, sizeof(uint32) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong( &value ); + entry_count = value; + + memcpy( &value, direntry_raw + 8, sizeof(uint32) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong( &value ); + entry_offset = value; + } + else + { + memcpy( &entry_count, direntry_raw + 4, sizeof(uint64) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8( &entry_count ); + + memcpy( &entry_offset, direntry_raw + 12, sizeof(uint64) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8( &entry_offset ); + } + +/* -------------------------------------------------------------------- */ +/* What data type do we want to write this as? */ +/* -------------------------------------------------------------------- */ + if( TIFFDataWidth(in_datatype) == 8 && !(tif->tif_flags&TIFF_BIGTIFF) ) + { + if( in_datatype == TIFF_LONG8 ) + datatype = TIFF_LONG; + else if( in_datatype == TIFF_SLONG8 ) + datatype = TIFF_SLONG; + else if( in_datatype == TIFF_IFD8 ) + datatype = TIFF_IFD; + else + datatype = in_datatype; + } + else + datatype = in_datatype; + +/* -------------------------------------------------------------------- */ +/* Prepare buffer of actual data to write. This includes */ +/* swabbing as needed. */ +/* -------------------------------------------------------------------- */ + buf_to_write = + (uint8 *)_TIFFCheckMalloc(tif, count, TIFFDataWidth(datatype), + "for field buffer."); + if (!buf_to_write) + return 0; + + if( datatype == in_datatype ) + memcpy( buf_to_write, data, count * TIFFDataWidth(datatype) ); + else if( datatype == TIFF_SLONG && in_datatype == TIFF_SLONG8 ) + { + tmsize_t i; + + for( i = 0; i < count; i++ ) + { + ((int32 *) buf_to_write)[i] = + (int32) ((int64 *) data)[i]; + if( (int64) ((int32 *) buf_to_write)[i] != ((int64 *) data)[i] ) + { + _TIFFfree( buf_to_write ); + TIFFErrorExt( tif->tif_clientdata, module, + "Value exceeds 32bit range of output type." ); + return 0; + } + } + } + else if( (datatype == TIFF_LONG && in_datatype == TIFF_LONG8) + || (datatype == TIFF_IFD && in_datatype == TIFF_IFD8) ) + { + tmsize_t i; + + for( i = 0; i < count; i++ ) + { + ((uint32 *) buf_to_write)[i] = + (uint32) ((uint64 *) data)[i]; + if( (uint64) ((uint32 *) buf_to_write)[i] != ((uint64 *) data)[i] ) + { + _TIFFfree( buf_to_write ); + TIFFErrorExt( tif->tif_clientdata, module, + "Value exceeds 32bit range of output type." ); + return 0; + } + } + } + + if( TIFFDataWidth(datatype) > 1 && (tif->tif_flags&TIFF_SWAB) ) + { + if( TIFFDataWidth(datatype) == 2 ) + TIFFSwabArrayOfShort( (uint16 *) buf_to_write, count ); + else if( TIFFDataWidth(datatype) == 4 ) + TIFFSwabArrayOfLong( (uint32 *) buf_to_write, count ); + else if( TIFFDataWidth(datatype) == 8 ) + TIFFSwabArrayOfLong8( (uint64 *) buf_to_write, count ); + } + +/* -------------------------------------------------------------------- */ +/* Is this a value that fits into the directory entry? */ +/* -------------------------------------------------------------------- */ + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if( TIFFDataWidth(datatype) * count <= 4 ) + { + entry_offset = read_offset + 8; + value_in_entry = 1; + } + } + else + { + if( TIFFDataWidth(datatype) * count <= 8 ) + { + entry_offset = read_offset + 12; + value_in_entry = 1; + } + } + +/* -------------------------------------------------------------------- */ +/* If the tag type, and count match, then we just write it out */ +/* over the old values without altering the directory entry at */ +/* all. */ +/* -------------------------------------------------------------------- */ + if( entry_count == (uint64)count && entry_type == (uint16) datatype ) + { + if (!SeekOK(tif, entry_offset)) { + _TIFFfree( buf_to_write ); + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Seek error accessing TIFF directory", + tif->tif_name); + return 0; + } + if (!WriteOK(tif, buf_to_write, count*TIFFDataWidth(datatype))) { + _TIFFfree( buf_to_write ); + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + + _TIFFfree( buf_to_write ); + return 1; + } + +/* -------------------------------------------------------------------- */ +/* Otherwise, we write the new tag data at the end of the file. */ +/* -------------------------------------------------------------------- */ + if( !value_in_entry ) + { + entry_offset = TIFFSeekFile(tif,0,SEEK_END); + + if (!WriteOK(tif, buf_to_write, count*TIFFDataWidth(datatype))) { + _TIFFfree( buf_to_write ); + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + + _TIFFfree( buf_to_write ); + } + else + { + memcpy( &entry_offset, buf_to_write, count*TIFFDataWidth(datatype)); + } + +/* -------------------------------------------------------------------- */ +/* Adjust the directory entry. */ +/* -------------------------------------------------------------------- */ + entry_type = datatype; + memcpy( direntry_raw + 2, &entry_type, sizeof(uint16) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort( (uint16 *) (direntry_raw + 2) ); + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32 value; + + value = (uint32) entry_count; + memcpy( direntry_raw + 4, &value, sizeof(uint32) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong( (uint32 *) (direntry_raw + 4) ); + + value = (uint32) entry_offset; + memcpy( direntry_raw + 8, &value, sizeof(uint32) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong( (uint32 *) (direntry_raw + 8) ); + } + else + { + memcpy( direntry_raw + 4, &entry_count, sizeof(uint64) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8( (uint64 *) (direntry_raw + 4) ); + + memcpy( direntry_raw + 12, &entry_offset, sizeof(uint64) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8( (uint64 *) (direntry_raw + 12) ); + } + +/* -------------------------------------------------------------------- */ +/* Write the directory entry out to disk. */ +/* -------------------------------------------------------------------- */ + if (!SeekOK(tif, read_offset )) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Seek error accessing TIFF directory", + tif->tif_name); + return 0; + } + + if (!WriteOK(tif, direntry_raw,dirsize)) + { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not write TIFF directory entry.", + tif->tif_name); + return 0; + } + + return 1; +} +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_dumpmode.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dumpmode.c new file mode 100644 index 0000000000..78ab03f608 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_dumpmode.c @@ -0,0 +1,146 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_dumpmode.c,v 1.14 2011-04-02 20:54:09 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * "Null" Compression Algorithm Support. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +static int +DumpFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +/* + * Encode a hunk of pixels. + */ +static int +DumpModeEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s) +{ + (void) s; + while (cc > 0) { + tmsize_t n; + + n = cc; + if (tif->tif_rawcc + n > tif->tif_rawdatasize) + n = tif->tif_rawdatasize - tif->tif_rawcc; + + assert( n > 0 ); + + /* + * Avoid copy if client has setup raw + * data buffer to avoid extra copy. + */ + if (tif->tif_rawcp != pp) + _TIFFmemcpy(tif->tif_rawcp, pp, n); + tif->tif_rawcp += n; + tif->tif_rawcc += n; + pp += n; + cc -= n; + if (tif->tif_rawcc >= tif->tif_rawdatasize && + !TIFFFlushData1(tif)) + return (-1); + } + return (1); +} + +/* + * Decode a hunk of pixels. + */ +static int +DumpModeDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) +{ + static const char module[] = "DumpModeDecode"; + (void) s; + if (tif->tif_rawcc < cc) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, +"Not enough data for scanline %lu, expected a request for at most %I64d bytes, got a request for %I64d bytes", + (unsigned long) tif->tif_row, + (signed __int64) tif->tif_rawcc, + (signed __int64) cc); +#else + TIFFErrorExt(tif->tif_clientdata, module, +"Not enough data for scanline %lu, expected a request for at most %lld bytes, got a request for %lld bytes", + (unsigned long) tif->tif_row, + (signed long long) tif->tif_rawcc, + (signed long long) cc); +#endif + return (0); + } + /* + * Avoid copy if client has setup raw + * data buffer to avoid extra copy. + */ + if (tif->tif_rawcp != buf) + _TIFFmemcpy(buf, tif->tif_rawcp, cc); + tif->tif_rawcp += cc; + tif->tif_rawcc -= cc; + return (1); +} + +/* + * Seek forwards nrows in the current strip. + */ +static int +DumpModeSeek(TIFF* tif, uint32 nrows) +{ + tif->tif_rawcp += nrows * tif->tif_scanlinesize; + tif->tif_rawcc -= nrows * tif->tif_scanlinesize; + return (1); +} + +/* + * Initialize dump mode. + */ +int +TIFFInitDumpMode(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_fixuptags = DumpFixupTags; + tif->tif_decoderow = DumpModeDecode; + tif->tif_decodestrip = DumpModeDecode; + tif->tif_decodetile = DumpModeDecode; + tif->tif_encoderow = DumpModeEncode; + tif->tif_encodestrip = DumpModeEncode; + tif->tif_encodetile = DumpModeEncode; + tif->tif_seek = DumpModeSeek; + return (1); +} +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_error.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_error.c new file mode 100644 index 0000000000..3a478c328e --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_error.c @@ -0,0 +1,85 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_error.c,v 1.5 2010-03-10 18:56:48 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +/*TIFFErrorHandlerExt _TIFFerrorHandlerExt = NULL;*/ +/* Modify here for use _TIFFerrorHandlerExt by Sunliang.Liu 20090715 */ +TIFFErrorHandler _TIFFerrorHandler = NULL; + +TIFFErrorHandler +TIFFSetErrorHandler(TIFFErrorHandler handler) +{ + TIFFErrorHandler prev = _TIFFerrorHandler; + _TIFFerrorHandler = handler; + return (prev); +} + +TIFFErrorHandlerExt +TIFFSetErrorHandlerExt(TIFFErrorHandlerExt handler) +{ + TIFFErrorHandlerExt prev = _TIFFerrorHandlerExt; + _TIFFerrorHandlerExt = handler; + return (prev); +} + +void +TIFFError(const char* module, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (_TIFFerrorHandler) + (*_TIFFerrorHandler)(module, fmt, ap); + if (_TIFFerrorHandlerExt) + (*_TIFFerrorHandlerExt)(0, module, fmt, ap); + va_end(ap); +} + +void +TIFFErrorExt(thandle_t fd, const char* module, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (_TIFFerrorHandler) + (*_TIFFerrorHandler)(module, fmt, ap); + if (_TIFFerrorHandlerExt) + (*_TIFFerrorHandlerExt)(fd, module, fmt, ap); + va_end(ap); +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_extension.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_extension.c new file mode 100644 index 0000000000..474cd790cd --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_extension.c @@ -0,0 +1,120 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_extension.c,v 1.7 2010-03-10 18:56:48 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Various routines support external extension of the tag set, and other + * application extension capabilities. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +int TIFFGetTagListCount( TIFF *tif ) + +{ + TIFFDirectory* td = &tif->tif_dir; + + return td->td_customValueCount; +} + +uint32 TIFFGetTagListEntry( TIFF *tif, int tag_index ) + +{ + TIFFDirectory* td = &tif->tif_dir; + + if( tag_index < 0 || tag_index >= td->td_customValueCount ) + return (uint32)(-1); + else + return td->td_customValues[tag_index].info->field_tag; +} + +/* +** This provides read/write access to the TIFFTagMethods within the TIFF +** structure to application code without giving access to the private +** TIFF structure. +*/ +TIFFTagMethods *TIFFAccessTagMethods( TIFF *tif ) + +{ + return &(tif->tif_tagmethods); +} + +void *TIFFGetClientInfo( TIFF *tif, const char *name ) + +{ + TIFFClientInfoLink *link = tif->tif_clientinfo; + + while( link != NULL && strcmp(link->name,name) != 0 ) + link = link->next; + + if( link != NULL ) + return link->data; + else + return NULL; +} + +void TIFFSetClientInfo( TIFF *tif, void *data, const char *name ) + +{ + TIFFClientInfoLink *link = tif->tif_clientinfo; + + /* + ** Do we have an existing link with this name? If so, just + ** set it. + */ + while( link != NULL && strcmp(link->name,name) != 0 ) + link = link->next; + + if( link != NULL ) + { + link->data = data; + return; + } + + /* + ** Create a new link. + */ + + link = (TIFFClientInfoLink *) _TIFFmalloc(sizeof(TIFFClientInfoLink)); + assert (link != NULL); + link->next = tif->tif_clientinfo; + link->name = (char *) _TIFFmalloc((tmsize_t)(strlen(name)+1)); + assert (link->name != NULL); + strcpy(link->name, name); + link->data = data; + + tif->tif_clientinfo = link; +} +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.c new file mode 100644 index 0000000000..986a3f48b9 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.c @@ -0,0 +1,1625 @@ +/* $Id: tif_fax3.c,v 1.74 2012-06-21 02:01:31 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1990-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#ifdef CCITT_SUPPORT +/* + * TIFF Library. + * + * CCITT Group 3 (T.4) and Group 4 (T.6) Compression Support. + * + * This file contains support for decoding and encoding TIFF + * compression algorithms 2, 3, 4, and 32771. + * + * Decoder support is derived, with permission, from the code + * in Frank Cringle's viewfax program; + * Copyright (C) 1990, 1995 Frank D. Cringle. + */ +#include "tif_fax3.h" +#define G3CODES +#include "t4.h" +#include + +/* + * Compression+decompression state blocks are + * derived from this ``base state'' block. + */ +typedef struct { + int rw_mode; /* O_RDONLY for decode, else encode */ + int mode; /* operating mode */ + tmsize_t rowbytes; /* bytes in a decoded scanline */ + uint32 rowpixels; /* pixels in a scanline */ + + uint16 cleanfaxdata; /* CleanFaxData tag */ + uint32 badfaxrun; /* BadFaxRun tag */ + uint32 badfaxlines; /* BadFaxLines tag */ + uint32 groupoptions; /* Group 3/4 options tag */ + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFPrintMethod printdir; /* super-class method */ +} Fax3BaseState; +#define Fax3State(tif) ((Fax3BaseState*) (tif)->tif_data) + +typedef enum { G3_1D, G3_2D } Ttag; +typedef struct { + Fax3BaseState b; + + /* Decoder state info */ + const unsigned char* bitmap; /* bit reversal table */ + uint32 data; /* current i/o byte/word */ + int bit; /* current i/o bit in byte */ + int EOLcnt; /* count of EOL codes recognized */ + TIFFFaxFillFunc fill; /* fill routine */ + uint32* runs; /* b&w runs for current/previous row */ + uint32* refruns; /* runs for reference line */ + uint32* curruns; /* runs for current line */ + + /* Encoder state info */ + Ttag tag; /* encoding state */ + unsigned char* refline; /* reference line for 2d decoding */ + int k; /* #rows left that can be 2d encoded */ + int maxk; /* max #rows that can be 2d encoded */ + + int line; +} Fax3CodecState; +#define DecoderState(tif) ((Fax3CodecState*) Fax3State(tif)) +#define EncoderState(tif) ((Fax3CodecState*) Fax3State(tif)) + +#define is2DEncoding(sp) (sp->b.groupoptions & GROUP3OPT_2DENCODING) +#define isAligned(p,t) ((((size_t)(p)) & (sizeof (t)-1)) == 0) + +/* + * Group 3 and Group 4 Decoding. + */ + +/* + * These macros glue the TIFF library state to + * the state expected by Frank's decoder. + */ +#define DECLARE_STATE(tif, sp, mod) \ + static const char module[] = mod; \ + Fax3CodecState* sp = DecoderState(tif); \ + int a0; /* reference element */ \ + int lastx = sp->b.rowpixels; /* last element in row */ \ + uint32 BitAcc; /* bit accumulator */ \ + int BitsAvail; /* # valid bits in BitAcc */ \ + int RunLength; /* length of current run */ \ + unsigned char* cp; /* next byte of input data */ \ + unsigned char* ep; /* end of input data */ \ + uint32* pa; /* place to stuff next run */ \ + uint32* thisrun; /* current row's run array */ \ + int EOLcnt; /* # EOL codes recognized */ \ + const unsigned char* bitmap = sp->bitmap; /* input data bit reverser */ \ + const TIFFFaxTabEnt* TabEnt +#define DECLARE_STATE_2D(tif, sp, mod) \ + DECLARE_STATE(tif, sp, mod); \ + int b1; /* next change on prev line */ \ + uint32* pb /* next run in reference line */\ +/* + * Load any state that may be changed during decoding. + */ +#define CACHE_STATE(tif, sp) do { \ + BitAcc = sp->data; \ + BitsAvail = sp->bit; \ + EOLcnt = sp->EOLcnt; \ + cp = (unsigned char*) tif->tif_rawcp; \ + ep = cp + tif->tif_rawcc; \ +} while (0) +/* + * Save state possibly changed during decoding. + */ +#define UNCACHE_STATE(tif, sp) do { \ + sp->bit = BitsAvail; \ + sp->data = BitAcc; \ + sp->EOLcnt = EOLcnt; \ + tif->tif_rawcc -= (tmsize_t)((uint8*) cp - tif->tif_rawcp); \ + tif->tif_rawcp = (uint8*) cp; \ +} while (0) + +/* + * Setup state for decoding a strip. + */ +static int +Fax3PreDecode(TIFF* tif, uint16 s) +{ + Fax3CodecState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + sp->bit = 0; /* force initial read */ + sp->data = 0; + sp->EOLcnt = 0; /* force initial scan for EOL */ + /* + * Decoder assumes lsb-to-msb bit order. Note that we select + * this here rather than in Fax3SetupState so that viewers can + * hold the image open, fiddle with the FillOrder tag value, + * and then re-decode the image. Otherwise they'd need to close + * and open the image to get the state reset. + */ + sp->bitmap = + TIFFGetBitRevTable(tif->tif_dir.td_fillorder != FILLORDER_LSB2MSB); + if (sp->refruns) { /* init reference line to white */ + sp->refruns[0] = (uint32) sp->b.rowpixels; + sp->refruns[1] = 0; + } + sp->line = 0; + return (1); +} + +/* + * Routine for handling various errors/conditions. + * Note how they are "glued into the decoder" by + * overriding the definitions used by the decoder. + */ + +static void +Fax3Unexpected(const char* module, TIFF* tif, uint32 line, uint32 a0) +{ + TIFFErrorExt(tif->tif_clientdata, module, "Bad code word at line %u of %s %u (x %u)", + line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0); +} +#define unexpected(table, a0) Fax3Unexpected(module, tif, sp->line, a0) + +static void +Fax3Extension(const char* module, TIFF* tif, uint32 line, uint32 a0) +{ + TIFFErrorExt(tif->tif_clientdata, module, + "Uncompressed data (not supported) at line %u of %s %u (x %u)", + line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0); +} +#define extension(a0) Fax3Extension(module, tif, sp->line, a0) + +static void +Fax3BadLength(const char* module, TIFF* tif, uint32 line, uint32 a0, uint32 lastx) +{ + TIFFWarningExt(tif->tif_clientdata, module, "%s at line %u of %s %u (got %u, expected %u)", + a0 < lastx ? "Premature EOL" : "Line length mismatch", + line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0, lastx); +} +#define badlength(a0,lastx) Fax3BadLength(module, tif, sp->line, a0, lastx) + +static void +Fax3PrematureEOF(const char* module, TIFF* tif, uint32 line, uint32 a0) +{ + TIFFWarningExt(tif->tif_clientdata, module, "Premature EOF at line %u of %s %u (x %u)", + line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0); +} +#define prematureEOF(a0) Fax3PrematureEOF(module, tif, sp->line, a0) + +#define Nop + +/* + * Decode the requested amount of G3 1D-encoded data. + */ +static int +Fax3Decode1D(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s) +{ + DECLARE_STATE(tif, sp, "Fax3Decode1D"); + (void) s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (-1); + } + CACHE_STATE(tif, sp); + thisrun = sp->curruns; + while (occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", tif->tif_row); + fflush(stdout); +#endif + SYNC_EOL(EOF1D); + EXPAND1D(EOF1Da); + (*sp->fill)(buf, thisrun, pa, lastx); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOF1D: /* premature EOF */ + CLEANUP_RUNS(); + EOF1Da: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} + +#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; } +/* + * Decode the requested amount of G3 2D-encoded data. + */ +static int +Fax3Decode2D(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s) +{ + DECLARE_STATE_2D(tif, sp, "Fax3Decode2D"); + int is1D; /* current line is 1d/2d-encoded */ + (void) s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (-1); + } + CACHE_STATE(tif, sp); + while (occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun = sp->curruns; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d EOLcnt = %d", + BitAcc, BitsAvail, EOLcnt); +#endif + SYNC_EOL(EOF2D); + NeedBits8(1, EOF2D); + is1D = GetBits(1); /* 1D/2D-encoding tag bit */ + ClrBits(1); +#ifdef FAX3_DEBUG + printf(" %s\n-------------------- %d\n", + is1D ? "1D" : "2D", tif->tif_row); + fflush(stdout); +#endif + pb = sp->refruns; + b1 = *pb++; + if (is1D) + EXPAND1D(EOF2Da); + else + EXPAND2D(EOF2Da); + (*sp->fill)(buf, thisrun, pa, lastx); + SETVALUE(0); /* imaginary change for reference */ + SWAP(uint32*, sp->curruns, sp->refruns); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOF2D: /* premature EOF */ + CLEANUP_RUNS(); + EOF2Da: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} +#undef SWAP + +/* + * The ZERO & FILL macros must handle spans < 2*sizeof(long) bytes. + * For machines with 64-bit longs this is <16 bytes; otherwise + * this is <8 bytes. We optimize the code here to reflect the + * machine characteristics. + */ +#if SIZEOF_UNSIGNED_LONG == 8 +# define FILL(n, cp) \ + switch (n) { \ + case 15:(cp)[14] = 0xff; case 14:(cp)[13] = 0xff; case 13: (cp)[12] = 0xff;\ + case 12:(cp)[11] = 0xff; case 11:(cp)[10] = 0xff; case 10: (cp)[9] = 0xff;\ + case 9: (cp)[8] = 0xff; case 8: (cp)[7] = 0xff; case 7: (cp)[6] = 0xff;\ + case 6: (cp)[5] = 0xff; case 5: (cp)[4] = 0xff; case 4: (cp)[3] = 0xff;\ + case 3: (cp)[2] = 0xff; case 2: (cp)[1] = 0xff; \ + case 1: (cp)[0] = 0xff; (cp) += (n); case 0: ; \ + } +# define ZERO(n, cp) \ + switch (n) { \ + case 15:(cp)[14] = 0; case 14:(cp)[13] = 0; case 13: (cp)[12] = 0; \ + case 12:(cp)[11] = 0; case 11:(cp)[10] = 0; case 10: (cp)[9] = 0; \ + case 9: (cp)[8] = 0; case 8: (cp)[7] = 0; case 7: (cp)[6] = 0; \ + case 6: (cp)[5] = 0; case 5: (cp)[4] = 0; case 4: (cp)[3] = 0; \ + case 3: (cp)[2] = 0; case 2: (cp)[1] = 0; \ + case 1: (cp)[0] = 0; (cp) += (n); case 0: ; \ + } +#else +# define FILL(n, cp) \ + switch (n) { \ + case 7: (cp)[6] = 0xff; case 6: (cp)[5] = 0xff; case 5: (cp)[4] = 0xff; \ + case 4: (cp)[3] = 0xff; case 3: (cp)[2] = 0xff; case 2: (cp)[1] = 0xff; \ + case 1: (cp)[0] = 0xff; (cp) += (n); case 0: ; \ + } +# define ZERO(n, cp) \ + switch (n) { \ + case 7: (cp)[6] = 0; case 6: (cp)[5] = 0; case 5: (cp)[4] = 0; \ + case 4: (cp)[3] = 0; case 3: (cp)[2] = 0; case 2: (cp)[1] = 0; \ + case 1: (cp)[0] = 0; (cp) += (n); case 0: ; \ + } +#endif + +/* + * Bit-fill a row according to the white/black + * runs generated during G3/G4 decoding. + */ +void +_TIFFFax3fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx) +{ + static const unsigned char _fillmasks[] = + { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; + unsigned char* cp; + uint32 x, bx, run,bx_;/* add bx_ = 8-bx for avoid ms evc compiler bug*/ + int32 n, nw; + long* lp; + + if ((erun-runs)&1) + *erun++ = 0; + x = 0; + for (; runs < erun; runs += 2) { + run = runs[0]; + if (x+run > lastx || run > lastx ) + run = runs[0] = (uint32) (lastx - x); + if (run) { + cp = buf + (x>>3); + bx = x&7; +// if (run > 8-bx) { +// if (bx) { /* align to byte boundary */ +// *cp++ &= 0xff << (8-bx); +// run -= 8-bx; +// } +//Modify by Sunliang.Liu 20090804 +//Detail: For avoid ms evc compiler bug in WCE ARMV4(I) Release + bx_ = 8-bx; + if (run > bx_) { + if (bx) { /* align to byte boundary */ + *cp++ &= 0xff << bx_; + run -= bx_; + } + if( (n = run >> 3) != 0 ) { /* multiple bytes to fill */ + if ((n/sizeof (long)) > 1) { + /* + * Align to longword boundary and fill. + */ + for (; n && !isAligned(cp, long); n--) + *cp++ = 0x00; + lp = (long*) cp; + nw = (int32)(n / sizeof (long)); + n -= nw * sizeof (long); + do { + *lp++ = 0L; + } while (--nw); + cp = (unsigned char*) lp; + } +#ifdef FAX3_DEBUG + printf("_TIFFFax3fillruns ZERO: %d\n",n); +#endif + ZERO(n, cp); + run &= 7; + } + if (run) + cp[0] &= 0xff >> run; + } else + cp[0] &= ~(_fillmasks[run]>>bx); + x += runs[0]; + } + run = runs[1]; + if (x+run > lastx || run > lastx ) + run = runs[1] = lastx - x; + if (run) { + cp = buf + (x>>3); + bx = x&7; + if (run > 8-bx) { + if (bx) { /* align to byte boundary */ + *cp++ |= 0xff >> bx; + run -= 8-bx; + } + if( (n = run>>3) != 0 ) { /* multiple bytes to fill */ + if ((n/sizeof (long)) > 1) { + /* + * Align to longword boundary and fill. + */ + for (; n && !isAligned(cp, long); n--) + *cp++ = 0xff; + lp = (long*) cp; + nw = (int32)(n / sizeof (long)); + n -= nw * sizeof (long); + do { + *lp++ = -1L; + } while (--nw); + cp = (unsigned char*) lp; + } +#ifdef FAX3_DEBUG + printf("_TIFFFax3fillruns FILL: %d\n",n); +#endif + FILL(n, cp); + run &= 7; + } + if (run) + cp[0] |= 0xff00 >> run; + } else + cp[0] |= _fillmasks[run]>>bx; + x += runs[1]; + } + } + assert(x == lastx); +} +#undef ZERO +#undef FILL + +static int +Fax3FixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +/* + * Setup G3/G4-related compression/decompression state + * before data is processed. This routine is called once + * per image -- it sets up different state based on whether + * or not decoding or encoding is being done and whether + * 1D- or 2D-encoded data is involved. + */ +static int +Fax3SetupState(TIFF* tif) +{ + static const char module[] = "Fax3SetupState"; + TIFFDirectory* td = &tif->tif_dir; + Fax3BaseState* sp = Fax3State(tif); + int needsRefLine; + Fax3CodecState* dsp = (Fax3CodecState*) Fax3State(tif); + tmsize_t rowbytes; + uint32 rowpixels, nruns; + + if (td->td_bitspersample != 1) { + TIFFErrorExt(tif->tif_clientdata, module, + "Bits/sample must be 1 for Group 3/4 encoding/decoding"); + return (0); + } + /* + * Calculate the scanline/tile widths. + */ + if (isTiled(tif)) { + rowbytes = TIFFTileRowSize(tif); + rowpixels = td->td_tilewidth; + } else { + rowbytes = TIFFScanlineSize(tif); + rowpixels = td->td_imagewidth; + } + sp->rowbytes = rowbytes; + sp->rowpixels = rowpixels; + /* + * Allocate any additional space required for decoding/encoding. + */ + needsRefLine = ( + (sp->groupoptions & GROUP3OPT_2DENCODING) || + td->td_compression == COMPRESSION_CCITTFAX4 + ); + + /* + Assure that allocation computations do not overflow. + + TIFFroundup and TIFFSafeMultiply return zero on integer overflow + */ + dsp->runs=(uint32*) NULL; + nruns = TIFFroundup_32(rowpixels,32); + if (needsRefLine) { + nruns = TIFFSafeMultiply(uint32,nruns,2); + } + if ((nruns == 0) || (TIFFSafeMultiply(uint32,nruns,2) == 0)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Row pixels integer overflow (rowpixels %u)", + rowpixels); + return (0); + } + dsp->runs = (uint32*) _TIFFCheckMalloc(tif, + TIFFSafeMultiply(uint32,nruns,2), + sizeof (uint32), + "for Group 3/4 run arrays"); + if (dsp->runs == NULL) + return (0); + memset( dsp->runs, 0, TIFFSafeMultiply(uint32,nruns,2)*sizeof(uint32)); + dsp->curruns = dsp->runs; + if (needsRefLine) + dsp->refruns = dsp->runs + nruns; + else + dsp->refruns = NULL; + if (td->td_compression == COMPRESSION_CCITTFAX3 + && is2DEncoding(dsp)) { /* NB: default is 1D routine */ + tif->tif_decoderow = Fax3Decode2D; + tif->tif_decodestrip = Fax3Decode2D; + tif->tif_decodetile = Fax3Decode2D; + } + + if (needsRefLine) { /* 2d encoding */ + Fax3CodecState* esp = EncoderState(tif); + /* + * 2d encoding requires a scanline + * buffer for the ``reference line''; the + * scanline against which delta encoding + * is referenced. The reference line must + * be initialized to be ``white'' (done elsewhere). + */ + esp->refline = (unsigned char*) _TIFFmalloc(rowbytes); + if (esp->refline == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for Group 3/4 reference line"); + return (0); + } + } else /* 1d encoding */ + EncoderState(tif)->refline = NULL; + + return (1); +} + +/* + * CCITT Group 3 FAX Encoding. + */ + +#define Fax3FlushBits(tif, sp) { \ + if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) \ + (void) TIFFFlushData1(tif); \ + *(tif)->tif_rawcp++ = (uint8) (sp)->data; \ + (tif)->tif_rawcc++; \ + (sp)->data = 0, (sp)->bit = 8; \ +} +#define _FlushBits(tif) { \ + if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) \ + (void) TIFFFlushData1(tif); \ + *(tif)->tif_rawcp++ = (uint8) data; \ + (tif)->tif_rawcc++; \ + data = 0, bit = 8; \ +} +static const int _msbmask[9] = + { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; +#define _PutBits(tif, bits, length) { \ + while (length > bit) { \ + data |= bits >> (length - bit); \ + length -= bit; \ + _FlushBits(tif); \ + } \ + assert( length < 9 ); \ + data |= (bits & _msbmask[length]) << (bit - length); \ + bit -= length; \ + if (bit == 0) \ + _FlushBits(tif); \ +} + +/* + * Write a variable-length bit-value to + * the output stream. Values are + * assumed to be at most 16 bits. + */ +static void +Fax3PutBits(TIFF* tif, unsigned int bits, unsigned int length) +{ + Fax3CodecState* sp = EncoderState(tif); + unsigned int bit = sp->bit; + int data = sp->data; + + _PutBits(tif, bits, length); + + sp->data = data; + sp->bit = bit; +} + +/* + * Write a code to the output stream. + */ +#define putcode(tif, te) Fax3PutBits(tif, (te)->code, (te)->length) + +#ifdef FAX3_DEBUG +#define DEBUG_COLOR(w) (tab == TIFFFaxWhiteCodes ? w "W" : w "B") +#define DEBUG_PRINT(what,len) { \ + int t; \ + printf("%08X/%-2d: %s%5d\t", data, bit, DEBUG_COLOR(what), len); \ + for (t = length-1; t >= 0; t--) \ + putchar(code & (1<bit; + int data = sp->data; + unsigned int code, length; + + while (span >= 2624) { + const tableentry* te = &tab[63 + (2560>>6)]; + code = te->code, length = te->length; +#ifdef FAX3_DEBUG + DEBUG_PRINT("MakeUp", te->runlen); +#endif + _PutBits(tif, code, length); + span -= te->runlen; + } + if (span >= 64) { + const tableentry* te = &tab[63 + (span>>6)]; + assert(te->runlen == 64*(span>>6)); + code = te->code, length = te->length; +#ifdef FAX3_DEBUG + DEBUG_PRINT("MakeUp", te->runlen); +#endif + _PutBits(tif, code, length); + span -= te->runlen; + } + code = tab[span].code, length = tab[span].length; +#ifdef FAX3_DEBUG + DEBUG_PRINT(" Term", tab[span].runlen); +#endif + _PutBits(tif, code, length); + + sp->data = data; + sp->bit = bit; +} + +/* + * Write an EOL code to the output stream. The zero-fill + * logic for byte-aligning encoded scanlines is handled + * here. We also handle writing the tag bit for the next + * scanline when doing 2d encoding. + */ +static void +Fax3PutEOL(TIFF* tif) +{ + Fax3CodecState* sp = EncoderState(tif); + unsigned int bit = sp->bit; + int data = sp->data; + unsigned int code, length, tparm; + + if (sp->b.groupoptions & GROUP3OPT_FILLBITS) { + /* + * Force bit alignment so EOL will terminate on + * a byte boundary. That is, force the bit alignment + * to 16-12 = 4 before putting out the EOL code. + */ + int align = 8 - 4; + if (align != sp->bit) { + if (align > sp->bit) + align = sp->bit + (8 - align); + else + align = sp->bit - align; + code = 0; + tparm=align; + _PutBits(tif, 0, tparm); + } + } + code = EOL, length = 12; + if (is2DEncoding(sp)) + code = (code<<1) | (sp->tag == G3_1D), length++; + _PutBits(tif, code, length); + + sp->data = data; + sp->bit = bit; +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +Fax3PreEncode(TIFF* tif, uint16 s) +{ + Fax3CodecState* sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + sp->bit = 8; + sp->data = 0; + sp->tag = G3_1D; + /* + * This is necessary for Group 4; otherwise it isn't + * needed because the first scanline of each strip ends + * up being copied into the refline. + */ + if (sp->refline) + _TIFFmemset(sp->refline, 0x00, sp->b.rowbytes); + if (is2DEncoding(sp)) { + float res = tif->tif_dir.td_yresolution; + /* + * The CCITT spec says that when doing 2d encoding, you + * should only do it on K consecutive scanlines, where K + * depends on the resolution of the image being encoded + * (2 for <= 200 lpi, 4 for > 200 lpi). Since the directory + * code initializes td_yresolution to 0, this code will + * select a K of 2 unless the YResolution tag is set + * appropriately. (Note also that we fudge a little here + * and use 150 lpi to avoid problems with units conversion.) + */ + if (tif->tif_dir.td_resolutionunit == RESUNIT_CENTIMETER) + res *= 2.54f; /* convert to inches */ + sp->maxk = (res > 150 ? 4 : 2); + sp->k = sp->maxk-1; + } else + sp->k = sp->maxk = 0; + sp->line = 0; + return (1); +} + +static const unsigned char zeroruns[256] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 - 0xff */ +}; +static const unsigned char oneruns[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xa0 - 0xaf */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xb0 - 0xbf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 - 0xcf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 - 0xdf */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 - 0xef */ + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, /* 0xf0 - 0xff */ +}; + +/* + * On certain systems it pays to inline + * the routines that find pixel spans. + */ +#ifdef VAXC +static int32 find0span(unsigned char*, int32, int32); +static int32 find1span(unsigned char*, int32, int32); +#pragma inline(find0span,find1span) +#endif + +/* + * Find a span of ones or zeros using the supplied + * table. The ``base'' of the bit string is supplied + * along with the start+end bit indices. + */ +inline static int32 +find0span(unsigned char* bp, int32 bs, int32 be) +{ + int32 bits = be - bs; + int32 n, span; + + bp += bs>>3; + /* + * Check partial byte on lhs. + */ + if (bits > 0 && (n = (bs & 7))) { + span = zeroruns[(*bp << n) & 0xff]; + if (span > 8-n) /* table value too generous */ + span = 8-n; + if (span > bits) /* constrain span to bit range */ + span = bits; + if (n+span < 8) /* doesn't extend to edge of byte */ + return (span); + bits -= span; + bp++; + } else + span = 0; + if (bits >= (int32)(2 * 8 * sizeof(long))) { + long* lp; + /* + * Align to longword boundary and check longwords. + */ + while (!isAligned(bp, long)) { + if (*bp != 0x00) + return (span + zeroruns[*bp]); + span += 8, bits -= 8; + bp++; + } + lp = (long*) bp; + while ((bits >= (int32)(8 * sizeof(long))) && (0 == *lp)) { + span += 8*sizeof (long), bits -= 8*sizeof (long); + lp++; + } + bp = (unsigned char*) lp; + } + /* + * Scan full bytes for all 0's. + */ + while (bits >= 8) { + if (*bp != 0x00) /* end of run */ + return (span + zeroruns[*bp]); + span += 8, bits -= 8; + bp++; + } + /* + * Check partial byte on rhs. + */ + if (bits > 0) { + n = zeroruns[*bp]; + span += (n > bits ? bits : n); + } + return (span); +} + +inline static int32 +find1span(unsigned char* bp, int32 bs, int32 be) +{ + int32 bits = be - bs; + int32 n, span; + + bp += bs>>3; + /* + * Check partial byte on lhs. + */ + if (bits > 0 && (n = (bs & 7))) { + span = oneruns[(*bp << n) & 0xff]; + if (span > 8-n) /* table value too generous */ + span = 8-n; + if (span > bits) /* constrain span to bit range */ + span = bits; + if (n+span < 8) /* doesn't extend to edge of byte */ + return (span); + bits -= span; + bp++; + } else + span = 0; + if (bits >= (int32)(2 * 8 * sizeof(long))) { + long* lp; + /* + * Align to longword boundary and check longwords. + */ + while (!isAligned(bp, long)) { + if (*bp != 0xff) + return (span + oneruns[*bp]); + span += 8, bits -= 8; + bp++; + } + lp = (long*) bp; + while ((bits >= (int32)(8 * sizeof(long))) && (~0 == *lp)) { + span += 8*sizeof (long), bits -= 8*sizeof (long); + lp++; + } + bp = (unsigned char*) lp; + } + /* + * Scan full bytes for all 1's. + */ + while (bits >= 8) { + if (*bp != 0xff) /* end of run */ + return (span + oneruns[*bp]); + span += 8, bits -= 8; + bp++; + } + /* + * Check partial byte on rhs. + */ + if (bits > 0) { + n = oneruns[*bp]; + span += (n > bits ? bits : n); + } + return (span); +} + +/* + * Return the offset of the next bit in the range + * [bs..be] that is different from the specified + * color. The end, be, is returned if no such bit + * exists. + */ +#define finddiff(_cp, _bs, _be, _color) \ + (_bs + (_color ? find1span(_cp,_bs,_be) : find0span(_cp,_bs,_be))) +/* + * Like finddiff, but also check the starting bit + * against the end in case start > end. + */ +#define finddiff2(_cp, _bs, _be, _color) \ + (_bs < _be ? finddiff(_cp,_bs,_be,_color) : _be) + +/* + * 1d-encode a row of pixels. The encoding is + * a sequence of all-white or all-black spans + * of pixels encoded with Huffman codes. + */ +static int +Fax3Encode1DRow(TIFF* tif, unsigned char* bp, uint32 bits) +{ + Fax3CodecState* sp = EncoderState(tif); + int32 span; + uint32 bs = 0; + + for (;;) { + span = find0span(bp, bs, bits); /* white span */ + putspan(tif, span, TIFFFaxWhiteCodes); + bs += span; + if (bs >= bits) + break; + span = find1span(bp, bs, bits); /* black span */ + putspan(tif, span, TIFFFaxBlackCodes); + bs += span; + if (bs >= bits) + break; + } + if (sp->b.mode & (FAXMODE_BYTEALIGN|FAXMODE_WORDALIGN)) { + if (sp->bit != 8) /* byte-align */ + Fax3FlushBits(tif, sp); + if ((sp->b.mode&FAXMODE_WORDALIGN) && + !isAligned(tif->tif_rawcp, uint16)) + Fax3FlushBits(tif, sp); + } + return (1); +} + +static const tableentry horizcode = + { 3, 0x1, 0 }; /* 001 */ +static const tableentry passcode = + { 4, 0x1, 0 }; /* 0001 */ +static const tableentry vcodes[7] = { + { 7, 0x03, 0 }, /* 0000 011 */ + { 6, 0x03, 0 }, /* 0000 11 */ + { 3, 0x03, 0 }, /* 011 */ + { 1, 0x1, 0 }, /* 1 */ + { 3, 0x2, 0 }, /* 010 */ + { 6, 0x02, 0 }, /* 0000 10 */ + { 7, 0x02, 0 } /* 0000 010 */ +}; + +/* + * 2d-encode a row of pixels. Consult the CCITT + * documentation for the algorithm. + */ +static int +Fax3Encode2DRow(TIFF* tif, unsigned char* bp, unsigned char* rp, uint32 bits) +{ +#define PIXEL(buf,ix) ((((buf)[(ix)>>3]) >> (7-((ix)&7))) & 1) + uint32 a0 = 0; + uint32 a1 = (PIXEL(bp, 0) != 0 ? 0 : finddiff(bp, 0, bits, 0)); + uint32 b1 = (PIXEL(rp, 0) != 0 ? 0 : finddiff(rp, 0, bits, 0)); + uint32 a2, b2; + + for (;;) { + b2 = finddiff2(rp, b1, bits, PIXEL(rp,b1)); + if (b2 >= a1) { + int32 d = b1 - a1; + if (!(-3 <= d && d <= 3)) { /* horizontal mode */ + a2 = finddiff2(bp, a1, bits, PIXEL(bp,a1)); + putcode(tif, &horizcode); + if (a0+a1 == 0 || PIXEL(bp, a0) == 0) { + putspan(tif, a1-a0, TIFFFaxWhiteCodes); + putspan(tif, a2-a1, TIFFFaxBlackCodes); + } else { + putspan(tif, a1-a0, TIFFFaxBlackCodes); + putspan(tif, a2-a1, TIFFFaxWhiteCodes); + } + a0 = a2; + } else { /* vertical mode */ + putcode(tif, &vcodes[d+3]); + a0 = a1; + } + } else { /* pass mode */ + putcode(tif, &passcode); + a0 = b2; + } + if (a0 >= bits) + break; + a1 = finddiff(bp, a0, bits, PIXEL(bp,a0)); + b1 = finddiff(rp, a0, bits, !PIXEL(bp,a0)); + b1 = finddiff(rp, b1, bits, PIXEL(bp,a0)); + } + return (1); +#undef PIXEL +} + +/* + * Encode a buffer of pixels. + */ +static int +Fax3Encode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + static const char module[] = "Fax3Encode"; + Fax3CodecState* sp = EncoderState(tif); + (void) s; + if (cc % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be written"); + return (0); + } + while (cc > 0) { + if ((sp->b.mode & FAXMODE_NOEOL) == 0) + Fax3PutEOL(tif); + if (is2DEncoding(sp)) { + if (sp->tag == G3_1D) { + if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels)) + return (0); + sp->tag = G3_2D; + } else { + if (!Fax3Encode2DRow(tif, bp, sp->refline, + sp->b.rowpixels)) + return (0); + sp->k--; + } + if (sp->k == 0) { + sp->tag = G3_1D; + sp->k = sp->maxk-1; + } else + _TIFFmemcpy(sp->refline, bp, sp->b.rowbytes); + } else { + if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels)) + return (0); + } + bp += sp->b.rowbytes; + cc -= sp->b.rowbytes; + } + return (1); +} + +static int +Fax3PostEncode(TIFF* tif) +{ + Fax3CodecState* sp = EncoderState(tif); + + if (sp->bit != 8) + Fax3FlushBits(tif, sp); + return (1); +} + +static void +Fax3Close(TIFF* tif) +{ + if ((Fax3State(tif)->mode & FAXMODE_NORTC) == 0) { + Fax3CodecState* sp = EncoderState(tif); + unsigned int code = EOL; + unsigned int length = 12; + int i; + + if (is2DEncoding(sp)) + code = (code<<1) | (sp->tag == G3_1D), length++; + for (i = 0; i < 6; i++) + Fax3PutBits(tif, code, length); + Fax3FlushBits(tif, sp); + } +} + +static void +Fax3Cleanup(TIFF* tif) +{ + Fax3CodecState* sp = DecoderState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->b.vgetparent; + tif->tif_tagmethods.vsetfield = sp->b.vsetparent; + tif->tif_tagmethods.printdir = sp->b.printdir; + + if (sp->runs) + _TIFFfree(sp->runs); + if (sp->refline) + _TIFFfree(sp->refline); + + _TIFFfree(tif->tif_data); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +#define FIELD_BADFAXLINES (FIELD_CODEC+0) +#define FIELD_CLEANFAXDATA (FIELD_CODEC+1) +#define FIELD_BADFAXRUN (FIELD_CODEC+2) + +#define FIELD_OPTIONS (FIELD_CODEC+7) + +static const TIFFField faxFields[] = { + { TIFFTAG_FAXMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "FaxMode", NULL }, + { TIFFTAG_FAXFILLFUNC, 0, 0, TIFF_ANY, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "FaxFillFunc", NULL }, + { TIFFTAG_BADFAXLINES, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_BADFAXLINES, TRUE, FALSE, "BadFaxLines", NULL }, + { TIFFTAG_CLEANFAXDATA, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UINT16, FIELD_CLEANFAXDATA, TRUE, FALSE, "CleanFaxData", NULL }, + { TIFFTAG_CONSECUTIVEBADFAXLINES, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_BADFAXRUN, TRUE, FALSE, "ConsecutiveBadFaxLines", NULL }}; +static const TIFFField fax3Fields[] = { + { TIFFTAG_GROUP3OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_OPTIONS, FALSE, FALSE, "Group3Options", NULL }, +}; +static const TIFFField fax4Fields[] = { + { TIFFTAG_GROUP4OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_OPTIONS, FALSE, FALSE, "Group4Options", NULL }, +}; + +static int +Fax3VSetField(TIFF* tif, uint32 tag, va_list ap) +{ + Fax3BaseState* sp = Fax3State(tif); + const TIFFField* fip; + + assert(sp != 0); + assert(sp->vsetparent != 0); + + switch (tag) { + case TIFFTAG_FAXMODE: + sp->mode = (int) va_arg(ap, int); + return 1; /* NB: pseudo tag */ + case TIFFTAG_FAXFILLFUNC: + DecoderState(tif)->fill = va_arg(ap, TIFFFaxFillFunc); + return 1; /* NB: pseudo tag */ + case TIFFTAG_GROUP3OPTIONS: + /* XXX: avoid reading options if compression mismatches. */ + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX3) + sp->groupoptions = (uint32) va_arg(ap, uint32); + break; + case TIFFTAG_GROUP4OPTIONS: + /* XXX: avoid reading options if compression mismatches. */ + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) + sp->groupoptions = (uint32) va_arg(ap, uint32); + break; + case TIFFTAG_BADFAXLINES: + sp->badfaxlines = (uint32) va_arg(ap, uint32); + break; + case TIFFTAG_CLEANFAXDATA: + sp->cleanfaxdata = (uint16) va_arg(ap, uint16_vap); + break; + case TIFFTAG_CONSECUTIVEBADFAXLINES: + sp->badfaxrun = (uint32) va_arg(ap, uint32); + break; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + + if ((fip = TIFFFieldWithTag(tif, tag))) + TIFFSetFieldBit(tif, fip->field_bit); + else + return 0; + + tif->tif_flags |= TIFF_DIRTYDIRECT; + return 1; +} + +static int +Fax3VGetField(TIFF* tif, uint32 tag, va_list ap) +{ + Fax3BaseState* sp = Fax3State(tif); + + assert(sp != 0); + + switch (tag) { + case TIFFTAG_FAXMODE: + *va_arg(ap, int*) = sp->mode; + break; + case TIFFTAG_FAXFILLFUNC: + *va_arg(ap, TIFFFaxFillFunc*) = DecoderState(tif)->fill; + break; + case TIFFTAG_GROUP3OPTIONS: + case TIFFTAG_GROUP4OPTIONS: + *va_arg(ap, uint32*) = sp->groupoptions; + break; + case TIFFTAG_BADFAXLINES: + *va_arg(ap, uint32*) = sp->badfaxlines; + break; + case TIFFTAG_CLEANFAXDATA: + *va_arg(ap, uint16*) = sp->cleanfaxdata; + break; + case TIFFTAG_CONSECUTIVEBADFAXLINES: + *va_arg(ap, uint32*) = sp->badfaxrun; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static void +Fax3PrintDir(TIFF* tif, FILE* fd, long flags) +{ + Fax3BaseState* sp = Fax3State(tif); + + assert(sp != 0); + + (void) flags; + if (TIFFFieldSet(tif,FIELD_OPTIONS)) { + const char* sep = " "; + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) { + fprintf(fd, " Group 4 Options:"); + if (sp->groupoptions & GROUP4OPT_UNCOMPRESSED) + fprintf(fd, "%suncompressed data", sep); + } else { + + fprintf(fd, " Group 3 Options:"); + if (sp->groupoptions & GROUP3OPT_2DENCODING) + fprintf(fd, "%s2-d encoding", sep), sep = "+"; + if (sp->groupoptions & GROUP3OPT_FILLBITS) + fprintf(fd, "%sEOL padding", sep), sep = "+"; + if (sp->groupoptions & GROUP3OPT_UNCOMPRESSED) + fprintf(fd, "%suncompressed data", sep); + } + fprintf(fd, " (%lu = 0x%lx)\n", + (unsigned long) sp->groupoptions, + (unsigned long) sp->groupoptions); + } + if (TIFFFieldSet(tif,FIELD_CLEANFAXDATA)) { + fprintf(fd, " Fax Data:"); + switch (sp->cleanfaxdata) { + case CLEANFAXDATA_CLEAN: + fprintf(fd, " clean"); + break; + case CLEANFAXDATA_REGENERATED: + fprintf(fd, " receiver regenerated"); + break; + case CLEANFAXDATA_UNCLEAN: + fprintf(fd, " uncorrected errors"); + break; + } + fprintf(fd, " (%u = 0x%x)\n", + sp->cleanfaxdata, sp->cleanfaxdata); + } + if (TIFFFieldSet(tif,FIELD_BADFAXLINES)) + fprintf(fd, " Bad Fax Lines: %lu\n", + (unsigned long) sp->badfaxlines); + if (TIFFFieldSet(tif,FIELD_BADFAXRUN)) + fprintf(fd, " Consecutive Bad Fax Lines: %lu\n", + (unsigned long) sp->badfaxrun); + if (sp->printdir) + (*sp->printdir)(tif, fd, flags); +} + +static int +InitCCITTFax3(TIFF* tif) +{ + static const char module[] = "InitCCITTFax3"; + Fax3BaseState* sp; + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, faxFields, TIFFArrayCount(faxFields))) { + TIFFErrorExt(tif->tif_clientdata, "InitCCITTFax3", + "Merging common CCITT Fax codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8*) + _TIFFmalloc(sizeof (Fax3CodecState)); + + if (tif->tif_data == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for state block"); + return (0); + } + + sp = Fax3State(tif); + sp->rw_mode = tif->tif_mode; + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = Fax3VGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = Fax3VSetField; /* hook for codec tags */ + sp->printdir = tif->tif_tagmethods.printdir; + tif->tif_tagmethods.printdir = Fax3PrintDir; /* hook for codec tags */ + sp->groupoptions = 0; + + if (sp->rw_mode == O_RDONLY) /* FIXME: improve for in place update */ + tif->tif_flags |= TIFF_NOBITREV; /* decoder does bit reversal */ + DecoderState(tif)->runs = NULL; + TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, _TIFFFax3fillruns); + EncoderState(tif)->refline = NULL; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = Fax3FixupTags; + tif->tif_setupdecode = Fax3SetupState; + tif->tif_predecode = Fax3PreDecode; + tif->tif_decoderow = Fax3Decode1D; + tif->tif_decodestrip = Fax3Decode1D; + tif->tif_decodetile = Fax3Decode1D; + tif->tif_setupencode = Fax3SetupState; + tif->tif_preencode = Fax3PreEncode; + tif->tif_postencode = Fax3PostEncode; + tif->tif_encoderow = Fax3Encode; + tif->tif_encodestrip = Fax3Encode; + tif->tif_encodetile = Fax3Encode; + tif->tif_close = Fax3Close; + tif->tif_cleanup = Fax3Cleanup; + + return (1); +} + +int +TIFFInitCCITTFax3(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, fax3Fields, + TIFFArrayCount(fax3Fields))) { + TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax3", + "Merging CCITT Fax 3 codec-specific tags failed"); + return 0; + } + + /* + * The default format is Class/F-style w/o RTC. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_CLASSF); + } else + return 01; +} + +/* + * CCITT Group 4 (T.6) Facsimile-compatible + * Compression Scheme Support. + */ + +#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; } +/* + * Decode the requested amount of G4-encoded data. + */ +static int +Fax4Decode(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s) +{ +#ifdef FAX3_DEBUG + FILE* file; +#endif + DECLARE_STATE_2D(tif, sp, "Fax4Decode"); + + (void) s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (-1); + } + CACHE_STATE(tif, sp); + while (occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun = sp->curruns; + pb = sp->refruns; + b1 = *pb++; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", tif->tif_row); + fflush(stdout); +#endif + EXPAND2D(EOFG4); + if (EOLcnt) + goto EOFG4; + (*sp->fill)(buf, thisrun, pa, lastx); +#ifdef FAX3_DEBUG + file = fopen("fillbuf.txt", "a"); + fwrite(buf, sp->b.rowbytes, 1, file); + fclose(file); +#endif + SETVALUE(0); /* imaginary change for reference */ + SWAP(uint32*, sp->curruns, sp->refruns); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOFG4: + NeedBits16( 13, BADG4 ); + BADG4: +#ifdef FAX3_DEBUG + if( GetBits(13) != 0x1001 ) + fputs( "Bad EOFB\n", stderr ); +#endif + ClrBits( 13 ); + (*sp->fill)(buf, thisrun, pa, lastx); +#ifdef FAX3_DEBUG + file = fopen("fillbuf.txt", "a"); + fwrite(buf, sp->b.rowbytes, 1, file); + fclose(file); +#endif + UNCACHE_STATE(tif, sp); + return ( sp->line ? 1 : -1); /* don't error on badly-terminated strips */ + } + UNCACHE_STATE(tif, sp); + return (1); +} +#undef SWAP + +/* + * Encode the requested amount of data. + */ +static int +Fax4Encode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + static const char module[] = "Fax4Encode"; + Fax3CodecState *sp = EncoderState(tif); + (void) s; + if (cc % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be written"); + return (0); + } + while (cc > 0) { + if (!Fax3Encode2DRow(tif, bp, sp->refline, sp->b.rowpixels)) + return (0); + _TIFFmemcpy(sp->refline, bp, sp->b.rowbytes); + bp += sp->b.rowbytes; + cc -= sp->b.rowbytes; + } + return (1); +} + +static int +Fax4PostEncode(TIFF* tif) +{ + Fax3CodecState *sp = EncoderState(tif); + + /* terminate strip w/ EOFB */ + Fax3PutBits(tif, EOL, 12); + Fax3PutBits(tif, EOL, 12); + if (sp->bit != 8) + Fax3FlushBits(tif, sp); + return (1); +} + +int +TIFFInitCCITTFax4(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, fax4Fields, + TIFFArrayCount(fax4Fields))) { + TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax4", + "Merging CCITT Fax 4 codec-specific tags failed"); + return 0; + } + + tif->tif_decoderow = Fax4Decode; + tif->tif_decodestrip = Fax4Decode; + tif->tif_decodetile = Fax4Decode; + tif->tif_encoderow = Fax4Encode; + tif->tif_encodestrip = Fax4Encode; + tif->tif_encodetile = Fax4Encode; + tif->tif_postencode = Fax4PostEncode; + /* + * Suppress RTC at the end of each strip. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_NORTC); + } else + return (0); +} + +/* + * CCITT Group 3 1-D Modified Huffman RLE Compression Support. + * (Compression algorithms 2 and 32771) + */ + +/* + * Decode the requested amount of RLE-encoded data. + */ +static int +Fax3DecodeRLE(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s) +{ + DECLARE_STATE(tif, sp, "Fax3DecodeRLE"); + int mode = sp->b.mode; + (void) s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (-1); + } + CACHE_STATE(tif, sp); + thisrun = sp->curruns; + while (occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", tif->tif_row); + fflush(stdout); +#endif + EXPAND1D(EOFRLE); + (*sp->fill)(buf, thisrun, pa, lastx); + /* + * Cleanup at the end of the row. + */ + if (mode & FAXMODE_BYTEALIGN) { + int n = BitsAvail - (BitsAvail &~ 7); + ClrBits(n); + } else if (mode & FAXMODE_WORDALIGN) { + int n = BitsAvail - (BitsAvail &~ 15); + ClrBits(n); + if (BitsAvail == 0 && !isAligned(cp, uint16)) + cp++; + } + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOFRLE: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} + +int +TIFFInitCCITTRLE(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + tif->tif_decoderow = Fax3DecodeRLE; + tif->tif_decodestrip = Fax3DecodeRLE; + tif->tif_decodetile = Fax3DecodeRLE; + /* + * Suppress RTC+EOLs when encoding and byte-align data. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, + FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_BYTEALIGN); + } else + return (0); +} + +int +TIFFInitCCITTRLEW(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + tif->tif_decoderow = Fax3DecodeRLE; + tif->tif_decodestrip = Fax3DecodeRLE; + tif->tif_decodetile = Fax3DecodeRLE; + /* + * Suppress RTC+EOLs when encoding and word-align data. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, + FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_WORDALIGN); + } else + return (0); +} +#endif /* CCITT_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.h b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.h new file mode 100644 index 0000000000..b0f46c9a43 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3.h @@ -0,0 +1,538 @@ +/* $Id: tif_fax3.h,v 1.9 2011-03-10 20:23:07 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1990-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _FAX3_ +#define _FAX3_ +/* + * TIFF Library. + * + * CCITT Group 3 (T.4) and Group 4 (T.6) Decompression Support. + * + * Decoder support is derived, with permission, from the code + * in Frank Cringle's viewfax program; + * Copyright (C) 1990, 1995 Frank D. Cringle. + */ +#include "tiff.h" + +/* + * To override the default routine used to image decoded + * spans one can use the pseduo tag TIFFTAG_FAXFILLFUNC. + * The routine must have the type signature given below; + * for example: + * + * fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx) + * + * where buf is place to set the bits, runs is the array of b&w run + * lengths (white then black), erun is the last run in the array, and + * lastx is the width of the row in pixels. Fill routines can assume + * the run array has room for at least lastx runs and can overwrite + * data in the run array as needed (e.g. to append zero runs to bring + * the count up to a nice multiple). + */ +typedef void (*TIFFFaxFillFunc)(unsigned char*, uint32*, uint32*, uint32); + +/* + * The default run filler; made external for other decoders. + */ +#if defined(__cplusplus) +extern "C" { +#endif +extern void _TIFFFax3fillruns(unsigned char*, uint32*, uint32*, uint32); +#if defined(__cplusplus) +} +#endif + + +/* finite state machine codes */ +#define S_Null 0 +#define S_Pass 1 +#define S_Horiz 2 +#define S_V0 3 +#define S_VR 4 +#define S_VL 5 +#define S_Ext 6 +#define S_TermW 7 +#define S_TermB 8 +#define S_MakeUpW 9 +#define S_MakeUpB 10 +#define S_MakeUp 11 +#define S_EOL 12 + +typedef struct { /* state table entry */ + unsigned char State; /* see above */ + unsigned char Width; /* width of code in bits */ + uint32 Param; /* unsigned 32-bit run length in bits */ +} TIFFFaxTabEnt; + +extern const TIFFFaxTabEnt TIFFFaxMainTable[]; +extern const TIFFFaxTabEnt TIFFFaxWhiteTable[]; +extern const TIFFFaxTabEnt TIFFFaxBlackTable[]; + +/* + * The following macros define the majority of the G3/G4 decoder + * algorithm using the state tables defined elsewhere. To build + * a decoder you need some setup code and some glue code. Note + * that you may also need/want to change the way the NeedBits* + * macros get input data if, for example, you know the data to be + * decoded is properly aligned and oriented (doing so before running + * the decoder can be a big performance win). + * + * Consult the decoder in the TIFF library for an idea of what you + * need to define and setup to make use of these definitions. + * + * NB: to enable a debugging version of these macros define FAX3_DEBUG + * before including this file. Trace output goes to stdout. + */ + +#ifndef EndOfData +#define EndOfData() (cp >= ep) +#endif +/* + * Need <=8 or <=16 bits of input data. Unlike viewfax we + * cannot use/assume a word-aligned, properly bit swizzled + * input data set because data may come from an arbitrarily + * aligned, read-only source such as a memory-mapped file. + * Note also that the viewfax decoder does not check for + * running off the end of the input data buffer. This is + * possible for G3-encoded data because it prescans the input + * data to count EOL markers, but can cause problems for G4 + * data. In any event, we don't prescan and must watch for + * running out of data since we can't permit the library to + * scan past the end of the input data buffer. + * + * Finally, note that we must handle remaindered data at the end + * of a strip specially. The coder asks for a fixed number of + * bits when scanning for the next code. This may be more bits + * than are actually present in the data stream. If we appear + * to run out of data but still have some number of valid bits + * remaining then we makeup the requested amount with zeros and + * return successfully. If the returned data is incorrect then + * we should be called again and get a premature EOF error; + * otherwise we should get the right answer. + */ +#ifndef NeedBits8 +#define NeedBits8(n,eoflab) do { \ + if (BitsAvail < (n)) { \ + if (EndOfData()) { \ + if (BitsAvail == 0) /* no valid bits */ \ + goto eoflab; \ + BitsAvail = (n); /* pad with zeros */ \ + } else { \ + BitAcc |= ((uint32) bitmap[*cp++])<>= (n); \ +} while (0) + +#ifdef FAX3_DEBUG +static const char* StateNames[] = { + "Null ", + "Pass ", + "Horiz ", + "V0 ", + "VR ", + "VL ", + "Ext ", + "TermW ", + "TermB ", + "MakeUpW", + "MakeUpB", + "MakeUp ", + "EOL ", +}; +#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0') +#define LOOKUP8(wid,tab,eoflab) do { \ + int t; \ + NeedBits8(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \ + StateNames[TabEnt->State], TabEnt->Param); \ + for (t = 0; t < TabEnt->Width; t++) \ + DEBUG_SHOW; \ + putchar('\n'); \ + fflush(stdout); \ + ClrBits(TabEnt->Width); \ +} while (0) +#define LOOKUP16(wid,tab,eoflab) do { \ + int t; \ + NeedBits16(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \ + StateNames[TabEnt->State], TabEnt->Param); \ + for (t = 0; t < TabEnt->Width; t++) \ + DEBUG_SHOW; \ + putchar('\n'); \ + fflush(stdout); \ + ClrBits(TabEnt->Width); \ +} while (0) + +#define SETVALUE(x) do { \ + *pa++ = RunLength + (x); \ + printf("SETVALUE: %d\t%d\n", RunLength + (x), a0); \ + a0 += x; \ + RunLength = 0; \ +} while (0) +#else +#define LOOKUP8(wid,tab,eoflab) do { \ + NeedBits8(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + ClrBits(TabEnt->Width); \ +} while (0) +#define LOOKUP16(wid,tab,eoflab) do { \ + NeedBits16(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + ClrBits(TabEnt->Width); \ +} while (0) + +/* + * Append a run to the run length array for the + * current row and reset decoding state. + */ +#define SETVALUE(x) do { \ + *pa++ = RunLength + (x); \ + a0 += (x); \ + RunLength = 0; \ +} while (0) +#endif + +/* + * Synchronize input decoding at the start of each + * row by scanning for an EOL (if appropriate) and + * skipping any trash data that might be present + * after a decoding error. Note that the decoding + * done elsewhere that recognizes an EOL only consumes + * 11 consecutive zero bits. This means that if EOLcnt + * is non-zero then we still need to scan for the final flag + * bit that is part of the EOL code. + */ +#define SYNC_EOL(eoflab) do { \ + if (EOLcnt == 0) { \ + for (;;) { \ + NeedBits16(11,eoflab); \ + if (GetBits(11) == 0) \ + break; \ + ClrBits(1); \ + } \ + } \ + for (;;) { \ + NeedBits8(8,eoflab); \ + if (GetBits(8)) \ + break; \ + ClrBits(8); \ + } \ + while (GetBits(1) == 0) \ + ClrBits(1); \ + ClrBits(1); /* EOL bit */ \ + EOLcnt = 0; /* reset EOL counter/flag */ \ +} while (0) + +/* + * Cleanup the array of runs after decoding a row. + * We adjust final runs to insure the user buffer is not + * overwritten and/or undecoded area is white filled. + */ +#define CLEANUP_RUNS() do { \ + if (RunLength) \ + SETVALUE(0); \ + if (a0 != lastx) { \ + badlength(a0, lastx); \ + while (a0 > lastx && pa > thisrun) \ + a0 -= *--pa; \ + if (a0 < lastx) { \ + if (a0 < 0) \ + a0 = 0; \ + if ((pa-thisrun)&1) \ + SETVALUE(0); \ + SETVALUE(lastx - a0); \ + } else if (a0 > lastx) { \ + SETVALUE(lastx); \ + SETVALUE(0); \ + } \ + } \ +} while (0) + +/* + * Decode a line of 1D-encoded data. + * + * The line expanders are written as macros so that they can be reused + * but still have direct access to the local variables of the "calling" + * function. + * + * Note that unlike the original version we have to explicitly test for + * a0 >= lastx after each black/white run is decoded. This is because + * the original code depended on the input data being zero-padded to + * insure the decoder recognized an EOL before running out of data. + */ +#define EXPAND1D(eoflab) do { \ + for (;;) { \ + for (;;) { \ + LOOKUP16(12, TIFFFaxWhiteTable, eof1d); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto done1d; \ + case S_TermW: \ + SETVALUE(TabEnt->Param); \ + goto doneWhite1d; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("WhiteTable", a0); \ + goto done1d; \ + } \ + } \ + doneWhite1d: \ + if (a0 >= lastx) \ + goto done1d; \ + for (;;) { \ + LOOKUP16(13, TIFFFaxBlackTable, eof1d); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto done1d; \ + case S_TermB: \ + SETVALUE(TabEnt->Param); \ + goto doneBlack1d; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("BlackTable", a0); \ + goto done1d; \ + } \ + } \ + doneBlack1d: \ + if (a0 >= lastx) \ + goto done1d; \ + if( *(pa-1) == 0 && *(pa-2) == 0 ) \ + pa -= 2; \ + } \ +eof1d: \ + prematureEOF(a0); \ + CLEANUP_RUNS(); \ + goto eoflab; \ +done1d: \ + CLEANUP_RUNS(); \ +} while (0) + +/* + * Update the value of b1 using the array + * of runs for the reference line. + */ +#define CHECK_b1 do { \ + if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \ + b1 += pb[0] + pb[1]; \ + pb += 2; \ + } \ +} while (0) + +/* + * Expand a row of 2D-encoded data. + */ +#define EXPAND2D(eoflab) do { \ + while (a0 < lastx) { \ + LOOKUP8(7, TIFFFaxMainTable, eof2d); \ + switch (TabEnt->State) { \ + case S_Pass: \ + CHECK_b1; \ + b1 += *pb++; \ + RunLength += b1 - a0; \ + a0 = b1; \ + b1 += *pb++; \ + break; \ + case S_Horiz: \ + if ((pa-thisrun)&1) { \ + for (;;) { /* black first */ \ + LOOKUP16(13, TIFFFaxBlackTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVALUE(TabEnt->Param); \ + goto doneWhite2da; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badBlack2d; \ + } \ + } \ + doneWhite2da:; \ + for (;;) { /* then white */ \ + LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVALUE(TabEnt->Param); \ + goto doneBlack2da; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badWhite2d; \ + } \ + } \ + doneBlack2da:; \ + } else { \ + for (;;) { /* white first */ \ + LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVALUE(TabEnt->Param); \ + goto doneWhite2db; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badWhite2d; \ + } \ + } \ + doneWhite2db:; \ + for (;;) { /* then black */ \ + LOOKUP16(13, TIFFFaxBlackTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVALUE(TabEnt->Param); \ + goto doneBlack2db; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badBlack2d; \ + } \ + } \ + doneBlack2db:; \ + } \ + CHECK_b1; \ + break; \ + case S_V0: \ + CHECK_b1; \ + SETVALUE(b1 - a0); \ + b1 += *pb++; \ + break; \ + case S_VR: \ + CHECK_b1; \ + SETVALUE(b1 - a0 + TabEnt->Param); \ + b1 += *pb++; \ + break; \ + case S_VL: \ + CHECK_b1; \ + if (b1 <= (int) (a0 + TabEnt->Param)) { \ + if (b1 < (int) (a0 + TabEnt->Param) || pa != thisrun) { \ + unexpected("VL", a0); \ + goto eol2d; \ + } \ + } \ + SETVALUE(b1 - a0 - TabEnt->Param); \ + b1 -= *--pb; \ + break; \ + case S_Ext: \ + *pa++ = lastx - a0; \ + extension(a0); \ + goto eol2d; \ + case S_EOL: \ + *pa++ = lastx - a0; \ + NeedBits8(4,eof2d); \ + if (GetBits(4)) \ + unexpected("EOL", a0); \ + ClrBits(4); \ + EOLcnt = 1; \ + goto eol2d; \ + default: \ + badMain2d: \ + unexpected("MainTable", a0); \ + goto eol2d; \ + badBlack2d: \ + unexpected("BlackTable", a0); \ + goto eol2d; \ + badWhite2d: \ + unexpected("WhiteTable", a0); \ + goto eol2d; \ + eof2d: \ + prematureEOF(a0); \ + CLEANUP_RUNS(); \ + goto eoflab; \ + } \ + } \ + if (RunLength) { \ + if (RunLength + a0 < lastx) { \ + /* expect a final V0 */ \ + NeedBits8(1,eof2d); \ + if (!GetBits(1)) \ + goto badMain2d; \ + ClrBits(1); \ + } \ + SETVALUE(0); \ + } \ +eol2d: \ + CLEANUP_RUNS(); \ +} while (0) +#endif /* _FAX3_ */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3sm.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3sm.c new file mode 100644 index 0000000000..47a532cbd6 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_fax3sm.c @@ -0,0 +1,1263 @@ +/* WARNING, this file was automatically generated by the + mkg3states program */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiff.h" +#include "tif_fax3.h" + const TIFFFaxTabEnt TIFFFaxMainTable[128] = { +{12,7,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0}, +{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{5,6,2},{3,1,0},{5,3,1},{3,1,0}, +{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0}, +{4,3,1},{3,1,0},{5,7,3},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0}, +{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{4,6,2},{3,1,0}, +{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0}, +{2,3,0},{3,1,0},{4,3,1},{3,1,0},{6,7,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0}, +{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0}, +{5,6,2},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0}, +{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{4,7,3},{3,1,0},{5,3,1},{3,1,0}, +{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0}, +{4,3,1},{3,1,0},{4,6,2},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0}, +{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0} +}; + const TIFFFaxTabEnt TIFFFaxWhiteTable[4096] = { +{12,11,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1792},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6}, +{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3}, +{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15}, +{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17}, +{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128}, +{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5}, +{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6}, +{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1856},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8}, +{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5}, +{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14}, +{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16}, +{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128}, +{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9}, +{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4}, +{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6}, +{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15}, +{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{11,12,2112},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6}, +{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7}, +{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8}, +{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16}, +{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128}, +{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5}, +{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3}, +{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2368},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6}, +{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3}, +{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15}, +{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17}, +{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128}, +{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5}, +{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6}, +{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8}, +{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5}, +{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14}, +{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16}, +{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128}, +{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{11,12,1984},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9}, +{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4}, +{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6}, +{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15}, +{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1920},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6}, +{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3}, +{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15}, +{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17}, +{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128}, +{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5}, +{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6}, +{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2240},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8}, +{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5}, +{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14}, +{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16}, +{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128}, +{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9}, +{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4}, +{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6}, +{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15}, +{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{11,12,2496},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6}, +{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7}, +{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8}, +{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{12,11,0},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16}, +{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128}, +{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5}, +{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3}, +{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1792},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6}, +{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3}, +{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15}, +{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17}, +{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128}, +{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5}, +{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6}, +{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8}, +{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5}, +{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14}, +{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16}, +{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128}, +{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{11,11,1856},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9}, +{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4}, +{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6}, +{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15}, +{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2176},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6}, +{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3}, +{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15}, +{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17}, +{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128}, +{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5}, +{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6}, +{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2432},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8}, +{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5}, +{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14}, +{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16}, +{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128}, +{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9}, +{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4}, +{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6}, +{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15}, +{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{11,12,2048},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6}, +{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7}, +{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8}, +{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16}, +{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128}, +{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5}, +{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3}, +{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1920},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6}, +{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3}, +{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15}, +{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17}, +{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128}, +{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5}, +{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6}, +{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8}, +{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5}, +{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14}, +{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16}, +{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128}, +{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{11,12,2304},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9}, +{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4}, +{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6}, +{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15}, +{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2560},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7} +}; + const TIFFFaxTabEnt TIFFFaxBlackTable[8192] = { +{12,11,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,23},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,25},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,128},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,56},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,30},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,57},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,21},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,54},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,52},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,48},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2112},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,44},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,36},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,384},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,28},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,60},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,40},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2368},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,12,1984},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,50},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,34},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1664},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,26},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1408},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,32},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,61},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,42},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,13,1024},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,768},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,62},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2240},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,46},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,38},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,512},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,19},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2496},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,25},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,12,192},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1280},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,31},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,58},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,21},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,896},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,640},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,49},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2176},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,45},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,37},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,12,448},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,29},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,1536},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,41},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2432},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2048},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,51},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,35},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,320},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,27},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,59},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,33},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,256},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,43},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,1152},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,55},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,63},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,12,2304},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,47},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,39},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,53},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2560},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,25},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,12,128},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,56},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,30},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,57},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,21},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,54},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,52},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,48},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2112},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,44},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,36},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,12,384},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,28},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,60},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,40},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,12,2368},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,1984},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,50},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,34},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,13,1728},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,26},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,1472},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,32},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,61},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,42},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1088},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,832},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,62},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2240},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,46},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,38},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,576},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2496},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,25},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,192},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1344},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,31},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1856},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,58},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,21},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,13,960},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,704},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,49},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2176},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,45},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,37},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,448},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,29},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1600},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,41},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2432},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2048},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,51},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,35},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,12,320},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,27},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,59},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,33},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,256},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,43},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1216},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,55},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,63},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2304},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,47},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,39},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,53},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2560},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2} +}; +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_flush.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_flush.c new file mode 100644 index 0000000000..075b3bcf33 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_flush.c @@ -0,0 +1,121 @@ +/* $Id: tif_flush.c,v 1.9 2010-03-31 06:40:10 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +int +TIFFFlush(TIFF* tif) +{ + if( tif->tif_mode == O_RDONLY ) + return 1; + + if (!TIFFFlushData(tif)) + return (0); + + /* In update (r+) mode we try to detect the case where + only the strip/tile map has been altered, and we try to + rewrite only that portion of the directory without + making any other changes */ + + if( (tif->tif_flags & TIFF_DIRTYSTRIP) + && !(tif->tif_flags & TIFF_DIRTYDIRECT) + && tif->tif_mode == O_RDWR ) + { + uint64 *offsets=NULL, *sizes=NULL; + + if( TIFFIsTiled(tif) ) + { + if( TIFFGetField( tif, TIFFTAG_TILEOFFSETS, &offsets ) + && TIFFGetField( tif, TIFFTAG_TILEBYTECOUNTS, &sizes ) + && _TIFFRewriteField( tif, TIFFTAG_TILEOFFSETS, TIFF_LONG8, + tif->tif_dir.td_nstrips, offsets ) + && _TIFFRewriteField( tif, TIFFTAG_TILEBYTECOUNTS, TIFF_LONG8, + tif->tif_dir.td_nstrips, sizes ) ) + { + tif->tif_flags &= ~TIFF_DIRTYSTRIP; + tif->tif_flags &= ~TIFF_BEENWRITING; + return 1; + } + } + else + { + if( TIFFGetField( tif, TIFFTAG_STRIPOFFSETS, &offsets ) + && TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &sizes ) + && _TIFFRewriteField( tif, TIFFTAG_STRIPOFFSETS, TIFF_LONG8, + tif->tif_dir.td_nstrips, offsets ) + && _TIFFRewriteField( tif, TIFFTAG_STRIPBYTECOUNTS, TIFF_LONG8, + tif->tif_dir.td_nstrips, sizes ) ) + { + tif->tif_flags &= ~TIFF_DIRTYSTRIP; + tif->tif_flags &= ~TIFF_BEENWRITING; + return 1; + } + } + } + + if ((tif->tif_flags & (TIFF_DIRTYDIRECT|TIFF_DIRTYSTRIP)) + && !TIFFRewriteDirectory(tif)) + return (0); + + return (1); +} + +/* + * Flush buffered data to the file. + * + * Frank Warmerdam'2000: I modified this to return 1 if TIFF_BEENWRITING + * is not set, so that TIFFFlush() will proceed to write out the directory. + * The documentation says returning 1 is an error indicator, but not having + * been writing isn't exactly a an error. Hopefully this doesn't cause + * problems for other people. + */ +int +TIFFFlushData(TIFF* tif) +{ + if ((tif->tif_flags & TIFF_BEENWRITING) == 0) + return (1); + if (tif->tif_flags & TIFF_POSTENCODE) { + tif->tif_flags &= ~TIFF_POSTENCODE; + if (!(*tif->tif_postencode)(tif)) + return (0); + } + return (TIFFFlushData1(tif)); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_getimage.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_getimage.c new file mode 100644 index 0000000000..a5d7a44e19 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_getimage.c @@ -0,0 +1,2991 @@ +/* $Id: tif_getimage.c,v 1.82 2012-06-06 00:17:49 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library + * + * Read and return a packed RGBA image. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#include + +static int gtTileContig(TIFFRGBAImage*, uint32*, uint32, uint32); +static int gtTileSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); +static int gtStripContig(TIFFRGBAImage*, uint32*, uint32, uint32); +static int gtStripSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); +static int PickContigCase(TIFFRGBAImage*); +static int PickSeparateCase(TIFFRGBAImage*); + +static int BuildMapUaToAa(TIFFRGBAImage* img); +static int BuildMapBitdepth16To8(TIFFRGBAImage* img); + +static const char photoTag[] = "PhotometricInterpretation"; + +/* + * Helper constants used in Orientation tag handling + */ +#define FLIP_VERTICALLY 0x01 +#define FLIP_HORIZONTALLY 0x02 + +/* + * Color conversion constants. We will define display types here. + */ + +static const TIFFDisplay display_sRGB = { + { /* XYZ -> luminance matrix */ + { 3.2410F, -1.5374F, -0.4986F }, + { -0.9692F, 1.8760F, 0.0416F }, + { 0.0556F, -0.2040F, 1.0570F } + }, + 100.0F, 100.0F, 100.0F, /* Light o/p for reference white */ + 255, 255, 255, /* Pixel values for ref. white */ + 1.0F, 1.0F, 1.0F, /* Residual light o/p for black pixel */ + 2.4F, 2.4F, 2.4F, /* Gamma values for the three guns */ +}; + +/* + * Check the image to see if TIFFReadRGBAImage can deal with it. + * 1/0 is returned according to whether or not the image can + * be handled. If 0 is returned, emsg contains the reason + * why it is being rejected. + */ +int +TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) +{ + TIFFDirectory* td = &tif->tif_dir; + uint16 photometric; + int colorchannels; + + if (!tif->tif_decodestatus) { + sprintf(emsg, "Sorry, requested compression method is not configured"); + return (0); + } + switch (td->td_bitspersample) { + case 1: + case 2: + case 4: + case 8: + case 16: + break; + default: + sprintf(emsg, "Sorry, can not handle images with %d-bit samples", + td->td_bitspersample); + return (0); + } + colorchannels = td->td_samplesperpixel - td->td_extrasamples; + if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) { + switch (colorchannels) { + case 1: + photometric = PHOTOMETRIC_MINISBLACK; + break; + case 3: + photometric = PHOTOMETRIC_RGB; + break; + default: + sprintf(emsg, "Missing needed %s tag", photoTag); + return (0); + } + } + switch (photometric) { + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_PALETTE: + if (td->td_planarconfig == PLANARCONFIG_CONTIG + && td->td_samplesperpixel != 1 + && td->td_bitspersample < 8 ) { + sprintf(emsg, + "Sorry, can not handle contiguous data with %s=%d, " + "and %s=%d and Bits/Sample=%d", + photoTag, photometric, + "Samples/pixel", td->td_samplesperpixel, + td->td_bitspersample); + return (0); + } + /* + * We should likely validate that any extra samples are either + * to be ignored, or are alpha, and if alpha we should try to use + * them. But for now we won't bother with this. + */ + break; + case PHOTOMETRIC_YCBCR: + /* + * TODO: if at all meaningful and useful, make more complete + * support check here, or better still, refactor to let supporting + * code decide whether there is support and what meaningfull + * error to return + */ + break; + case PHOTOMETRIC_RGB: + if (colorchannels < 3) { + sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", + "Color channels", colorchannels); + return (0); + } + break; + case PHOTOMETRIC_SEPARATED: + { + uint16 inkset; + TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); + if (inkset != INKSET_CMYK) { + sprintf(emsg, + "Sorry, can not handle separated image with %s=%d", + "InkSet", inkset); + return 0; + } + if (td->td_samplesperpixel < 4) { + sprintf(emsg, + "Sorry, can not handle separated image with %s=%d", + "Samples/pixel", td->td_samplesperpixel); + return 0; + } + break; + } + case PHOTOMETRIC_LOGL: + if (td->td_compression != COMPRESSION_SGILOG) { + sprintf(emsg, "Sorry, LogL data must have %s=%d", + "Compression", COMPRESSION_SGILOG); + return (0); + } + break; + case PHOTOMETRIC_LOGLUV: + if (td->td_compression != COMPRESSION_SGILOG && + td->td_compression != COMPRESSION_SGILOG24) { + sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", + "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); + return (0); + } + if (td->td_planarconfig != PLANARCONFIG_CONTIG) { + sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", + "Planarconfiguration", td->td_planarconfig); + return (0); + } + break; + case PHOTOMETRIC_CIELAB: + break; + default: + sprintf(emsg, "Sorry, can not handle image with %s=%d", + photoTag, photometric); + return (0); + } + return (1); +} + +void +TIFFRGBAImageEnd(TIFFRGBAImage* img) +{ + if (img->Map) + _TIFFfree(img->Map), img->Map = NULL; + if (img->BWmap) + _TIFFfree(img->BWmap), img->BWmap = NULL; + if (img->PALmap) + _TIFFfree(img->PALmap), img->PALmap = NULL; + if (img->ycbcr) + _TIFFfree(img->ycbcr), img->ycbcr = NULL; + if (img->cielab) + _TIFFfree(img->cielab), img->cielab = NULL; + if (img->UaToAa) + _TIFFfree(img->UaToAa), img->UaToAa = NULL; + if (img->Bitdepth16To8) + _TIFFfree(img->Bitdepth16To8), img->Bitdepth16To8 = NULL; + + if( img->redcmap ) { + _TIFFfree( img->redcmap ); + _TIFFfree( img->greencmap ); + _TIFFfree( img->bluecmap ); + img->redcmap = img->greencmap = img->bluecmap = NULL; + } +} + +static int +isCCITTCompression(TIFF* tif) +{ + uint16 compress; + TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress); + return (compress == COMPRESSION_CCITTFAX3 || + compress == COMPRESSION_CCITTFAX4 || + compress == COMPRESSION_CCITTRLE || + compress == COMPRESSION_CCITTRLEW); +} + +int +TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) +{ + uint16* sampleinfo; + uint16 extrasamples; + uint16 planarconfig; + uint16 compress; + int colorchannels; + uint16 *red_orig, *green_orig, *blue_orig; + int n_color; + + /* Initialize to normal values */ + img->row_offset = 0; + img->col_offset = 0; + img->redcmap = NULL; + img->greencmap = NULL; + img->bluecmap = NULL; + img->req_orientation = ORIENTATION_BOTLEFT; /* It is the default */ + + img->tif = tif; + img->stoponerr = stop; + TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample); + switch (img->bitspersample) { + case 1: + case 2: + case 4: + case 8: + case 16: + break; + default: + sprintf(emsg, "Sorry, can not handle images with %d-bit samples", + img->bitspersample); + goto fail_return; + } + img->alpha = 0; + TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel); + TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, + &extrasamples, &sampleinfo); + if (extrasamples >= 1) + { + switch (sampleinfo[0]) { + case EXTRASAMPLE_UNSPECIFIED: /* Workaround for some images without */ + if (img->samplesperpixel > 3) /* correct info about alpha channel */ + img->alpha = EXTRASAMPLE_ASSOCALPHA; + break; + case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */ + case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */ + img->alpha = sampleinfo[0]; + break; + } + } + +#ifdef DEFAULT_EXTRASAMPLE_AS_ALPHA + if( !TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) + img->photometric = PHOTOMETRIC_MINISWHITE; + + if( extrasamples == 0 + && img->samplesperpixel == 4 + && img->photometric == PHOTOMETRIC_RGB ) + { + img->alpha = EXTRASAMPLE_ASSOCALPHA; + extrasamples = 1; + } +#endif + + colorchannels = img->samplesperpixel - extrasamples; + TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress); + TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig); + if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) { + switch (colorchannels) { + case 1: + if (isCCITTCompression(tif)) + img->photometric = PHOTOMETRIC_MINISWHITE; + else + img->photometric = PHOTOMETRIC_MINISBLACK; + break; + case 3: + img->photometric = PHOTOMETRIC_RGB; + break; + default: + sprintf(emsg, "Missing needed %s tag", photoTag); + goto fail_return; + } + } + switch (img->photometric) { + case PHOTOMETRIC_PALETTE: + if (!TIFFGetField(tif, TIFFTAG_COLORMAP, + &red_orig, &green_orig, &blue_orig)) { + sprintf(emsg, "Missing required \"Colormap\" tag"); + goto fail_return; + } + + /* copy the colormaps so we can modify them */ + n_color = (1L << img->bitspersample); + img->redcmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); + img->greencmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); + img->bluecmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); + if( !img->redcmap || !img->greencmap || !img->bluecmap ) { + sprintf(emsg, "Out of memory for colormap copy"); + goto fail_return; + } + + _TIFFmemcpy( img->redcmap, red_orig, n_color * 2 ); + _TIFFmemcpy( img->greencmap, green_orig, n_color * 2 ); + _TIFFmemcpy( img->bluecmap, blue_orig, n_color * 2 ); + + /* fall thru... */ + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + if (planarconfig == PLANARCONFIG_CONTIG + && img->samplesperpixel != 1 + && img->bitspersample < 8 ) { + sprintf(emsg, + "Sorry, can not handle contiguous data with %s=%d, " + "and %s=%d and Bits/Sample=%d", + photoTag, img->photometric, + "Samples/pixel", img->samplesperpixel, + img->bitspersample); + goto fail_return; + } + break; + case PHOTOMETRIC_YCBCR: + /* It would probably be nice to have a reality check here. */ + if (planarconfig == PLANARCONFIG_CONTIG) + /* can rely on libjpeg to convert to RGB */ + /* XXX should restore current state on exit */ + switch (compress) { + case COMPRESSION_JPEG: + /* + * TODO: when complete tests verify complete desubsampling + * and YCbCr handling, remove use of TIFFTAG_JPEGCOLORMODE in + * favor of tif_getimage.c native handling + */ + TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + img->photometric = PHOTOMETRIC_RGB; + break; + default: + /* do nothing */; + break; + } + /* + * TODO: if at all meaningful and useful, make more complete + * support check here, or better still, refactor to let supporting + * code decide whether there is support and what meaningfull + * error to return + */ + break; + case PHOTOMETRIC_RGB: + if (colorchannels < 3) { + sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", + "Color channels", colorchannels); + goto fail_return; + } + break; + case PHOTOMETRIC_SEPARATED: + { + uint16 inkset; + TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); + if (inkset != INKSET_CMYK) { + sprintf(emsg, "Sorry, can not handle separated image with %s=%d", + "InkSet", inkset); + goto fail_return; + } + if (img->samplesperpixel < 4) { + sprintf(emsg, "Sorry, can not handle separated image with %s=%d", + "Samples/pixel", img->samplesperpixel); + goto fail_return; + } + } + break; + case PHOTOMETRIC_LOGL: + if (compress != COMPRESSION_SGILOG) { + sprintf(emsg, "Sorry, LogL data must have %s=%d", + "Compression", COMPRESSION_SGILOG); + goto fail_return; + } + TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); + img->photometric = PHOTOMETRIC_MINISBLACK; /* little white lie */ + img->bitspersample = 8; + break; + case PHOTOMETRIC_LOGLUV: + if (compress != COMPRESSION_SGILOG && compress != COMPRESSION_SGILOG24) { + sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", + "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); + goto fail_return; + } + if (planarconfig != PLANARCONFIG_CONTIG) { + sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", + "Planarconfiguration", planarconfig); + return (0); + } + TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); + img->photometric = PHOTOMETRIC_RGB; /* little white lie */ + img->bitspersample = 8; + break; + case PHOTOMETRIC_CIELAB: + break; + default: + sprintf(emsg, "Sorry, can not handle image with %s=%d", + photoTag, img->photometric); + goto fail_return; + } + img->Map = NULL; + img->BWmap = NULL; + img->PALmap = NULL; + img->ycbcr = NULL; + img->cielab = NULL; + img->UaToAa = NULL; + img->Bitdepth16To8 = NULL; + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height); + TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation); + img->isContig = + !(planarconfig == PLANARCONFIG_SEPARATE && img->samplesperpixel > 1); + if (img->isContig) { + if (!PickContigCase(img)) { + sprintf(emsg, "Sorry, can not handle image"); + goto fail_return; + } + } else { + if (!PickSeparateCase(img)) { + sprintf(emsg, "Sorry, can not handle image"); + goto fail_return; + } + } + return 1; + + fail_return: + _TIFFfree( img->redcmap ); + _TIFFfree( img->greencmap ); + _TIFFfree( img->bluecmap ); + img->redcmap = img->greencmap = img->bluecmap = NULL; + return 0; +} + +int +TIFFRGBAImageGet(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + if (img->get == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No \"get\" routine setup"); + return (0); + } + if (img->put.any == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), + "No \"put\" routine setupl; probably can not handle image format"); + return (0); + } + return (*img->get)(img, raster, w, h); +} + +/* + * Read the specified image into an ABGR-format rastertaking in account + * specified orientation. + */ +int +TIFFReadRGBAImageOriented(TIFF* tif, + uint32 rwidth, uint32 rheight, uint32* raster, + int orientation, int stop) +{ + char emsg[1024] = ""; + TIFFRGBAImage img; + int ok; + + if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, stop, emsg)) { + img.req_orientation = orientation; + /* XXX verify rwidth and rheight against width and height */ + ok = TIFFRGBAImageGet(&img, raster+(rheight-img.height)*rwidth, + rwidth, img.height); + TIFFRGBAImageEnd(&img); + } else { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); + ok = 0; + } + return (ok); +} + +/* + * Read the specified image into an ABGR-format raster. Use bottom left + * origin for raster by default. + */ +int +TIFFReadRGBAImage(TIFF* tif, + uint32 rwidth, uint32 rheight, uint32* raster, int stop) +{ + return TIFFReadRGBAImageOriented(tif, rwidth, rheight, raster, + ORIENTATION_BOTLEFT, stop); +} + +static int +setorientation(TIFFRGBAImage* img) +{ + switch (img->orientation) { + case ORIENTATION_TOPLEFT: + case ORIENTATION_LEFTTOP: + if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_HORIZONTALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_VERTICALLY; + else + return 0; + case ORIENTATION_TOPRIGHT: + case ORIENTATION_RIGHTTOP: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_HORIZONTALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else + return 0; + case ORIENTATION_BOTRIGHT: + case ORIENTATION_RIGHTBOT: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_HORIZONTALLY; + else + return 0; + case ORIENTATION_BOTLEFT: + case ORIENTATION_LEFTBOT: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_HORIZONTALLY; + else + return 0; + default: /* NOTREACHED */ + return 0; + } +} + +/* + * Get an tile-organized image that has + * PlanarConfiguration contiguous if SamplesPerPixel > 1 + * or + * SamplesPerPixel == 1 + */ +static int +gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileContigRoutine put = img->put.contig; + uint32 col, row, y, rowstoread; + tmsize_t pos; + uint32 tw, th; + unsigned char* buf; + int32 fromskew, toskew; + uint32 nrow; + int ret = 1, flip; + + buf = (unsigned char*) _TIFFmalloc(TIFFTileSize(tif)); + if (buf == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "No space for tile buffer"); + return (0); + } + _TIFFmemset(buf, 0, TIFFTileSize(tif)); + TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); + TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(tw + w); + } + else { + y = 0; + toskew = -(int32)(tw - w); + } + + for (row = 0; row < h; row += nrow) + { + rowstoread = th - (row + img->row_offset) % th; + nrow = (row + rowstoread > h ? h - row : rowstoread); + for (col = 0; col < w; col += tw) + { + if (TIFFReadTile(tif, buf, col+img->col_offset, + row+img->row_offset, 0, 0)==(tmsize_t)(-1) && img->stoponerr) + { + ret = 0; + break; + } + + pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); + + if (col + tw > w) + { + /* + * Tile is clipped horizontally. Calculate + * visible portion and skewing factors. + */ + uint32 npix = w - col; + fromskew = tw - npix; + (*put)(img, raster+y*w+col, col, y, + npix, nrow, fromskew, toskew + fromskew, buf + pos); + } + else + { + (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, buf + pos); + } + } + + y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); + } + _TIFFfree(buf); + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } + } + } + + return (ret); +} + +/* + * Get an tile-organized image that has + * SamplesPerPixel > 1 + * PlanarConfiguration separated + * We assume that all such images are RGB. + */ +static int +gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileSeparateRoutine put = img->put.separate; + uint32 col, row, y, rowstoread; + tmsize_t pos; + uint32 tw, th; + unsigned char* buf; + unsigned char* p0; + unsigned char* p1; + unsigned char* p2; + unsigned char* pa; + tmsize_t tilesize; + tmsize_t bufsize; + int32 fromskew, toskew; + int alpha = img->alpha; + uint32 nrow; + int ret = 1, flip; + int colorchannels; + + tilesize = TIFFTileSize(tif); + bufsize = TIFFSafeMultiply(tmsize_t,alpha?4:3,tilesize); + if (bufsize == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtTileSeparate"); + return (0); + } + buf = (unsigned char*) _TIFFmalloc(bufsize); + if (buf == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "No space for tile buffer"); + return (0); + } + _TIFFmemset(buf, 0, bufsize); + p0 = buf; + p1 = p0 + tilesize; + p2 = p1 + tilesize; + pa = (alpha?(p2+tilesize):NULL); + TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); + TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(tw + w); + } + else { + y = 0; + toskew = -(int32)(tw - w); + } + + switch( img->photometric ) + { + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_PALETTE: + colorchannels = 1; + p2 = p1 = p0; + break; + + default: + colorchannels = 3; + break; + } + + for (row = 0; row < h; row += nrow) + { + rowstoread = th - (row + img->row_offset) % th; + nrow = (row + rowstoread > h ? h - row : rowstoread); + for (col = 0; col < w; col += tw) + { + if (TIFFReadTile(tif, p0, col+img->col_offset, + row+img->row_offset,0,0)==(tmsize_t)(-1) && img->stoponerr) + { + ret = 0; + break; + } + if (colorchannels > 1 + && TIFFReadTile(tif, p1, col+img->col_offset, + row+img->row_offset,0,1) == (tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; + break; + } + if (colorchannels > 1 + && TIFFReadTile(tif, p2, col+img->col_offset, + row+img->row_offset,0,2) == (tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; + break; + } + if (alpha + && TIFFReadTile(tif,pa,col+img->col_offset, + row+img->row_offset,0,colorchannels) == (tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; + break; + } + + pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); + + if (col + tw > w) + { + /* + * Tile is clipped horizontally. Calculate + * visible portion and skewing factors. + */ + uint32 npix = w - col; + fromskew = tw - npix; + (*put)(img, raster+y*w+col, col, y, + npix, nrow, fromskew, toskew + fromskew, + p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); + } else { + (*put)(img, raster+y*w+col, col, y, + tw, nrow, 0, toskew, p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); + } + } + + y += (flip & FLIP_VERTICALLY ?-(int32) nrow : (int32) nrow); + } + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } + } + } + + _TIFFfree(buf); + return (ret); +} + +/* + * Get a strip-organized image that has + * PlanarConfiguration contiguous if SamplesPerPixel > 1 + * or + * SamplesPerPixel == 1 + */ +static int +gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileContigRoutine put = img->put.contig; + uint32 row, y, nrow, nrowsub, rowstoread; + tmsize_t pos; + unsigned char* buf; + uint32 rowsperstrip; + uint16 subsamplinghor,subsamplingver; + uint32 imagewidth = img->width; + tmsize_t scanline; + int32 fromskew, toskew; + int ret = 1, flip; + + buf = (unsigned char*) _TIFFmalloc(TIFFStripSize(tif)); + if (buf == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer"); + return (0); + } + _TIFFmemset(buf, 0, TIFFStripSize(tif)); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(w + w); + } else { + y = 0; + toskew = -(int32)(w - w); + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver); + scanline = TIFFScanlineSize(tif); + fromskew = (w < imagewidth ? imagewidth - w : 0); + for (row = 0; row < h; row += nrow) + { + rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; + nrow = (row + rowstoread > h ? h - row : rowstoread); + nrowsub = nrow; + if ((nrowsub%subsamplingver)!=0) + nrowsub+=subsamplingver-nrowsub%subsamplingver; + if (TIFFReadEncodedStrip(tif, + TIFFComputeStrip(tif,row+img->row_offset, 0), + buf, + ((row + img->row_offset)%rowsperstrip + nrowsub) * scanline)==(tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; + break; + } + + pos = ((row + img->row_offset) % rowsperstrip) * scanline; + (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, buf + pos); + y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); + } + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } + } + } + + _TIFFfree(buf); + return (ret); +} + +/* + * Get a strip-organized image with + * SamplesPerPixel > 1 + * PlanarConfiguration separated + * We assume that all such images are RGB. + */ +static int +gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileSeparateRoutine put = img->put.separate; + unsigned char *buf; + unsigned char *p0, *p1, *p2, *pa; + uint32 row, y, nrow, rowstoread; + tmsize_t pos; + tmsize_t scanline; + uint32 rowsperstrip, offset_row; + uint32 imagewidth = img->width; + tmsize_t stripsize; + tmsize_t bufsize; + int32 fromskew, toskew; + int alpha = img->alpha; + int ret = 1, flip, colorchannels; + + stripsize = TIFFStripSize(tif); + bufsize = TIFFSafeMultiply(tmsize_t,alpha?4:3,stripsize); + if (bufsize == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtStripSeparate"); + return (0); + } + p0 = buf = (unsigned char *)_TIFFmalloc(bufsize); + if (buf == 0) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer"); + return (0); + } + _TIFFmemset(buf, 0, bufsize); + p1 = p0 + stripsize; + p2 = p1 + stripsize; + pa = (alpha?(p2+stripsize):NULL); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(w + w); + } + else { + y = 0; + toskew = -(int32)(w - w); + } + + switch( img->photometric ) + { + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_PALETTE: + colorchannels = 1; + p2 = p1 = p0; + break; + + default: + colorchannels = 3; + break; + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + scanline = TIFFScanlineSize(tif); + fromskew = (w < imagewidth ? imagewidth - w : 0); + for (row = 0; row < h; row += nrow) + { + rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; + nrow = (row + rowstoread > h ? h - row : rowstoread); + offset_row = row + img->row_offset; + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0), + p0, ((row + img->row_offset)%rowsperstrip + nrow) * scanline)==(tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; + break; + } + if (colorchannels > 1 + && TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1), + p1, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) == (tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; + break; + } + if (colorchannels > 1 + && TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2), + p2, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) == (tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; + break; + } + if (alpha) + { + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, colorchannels), + pa, ((row + img->row_offset)%rowsperstrip + nrow) * scanline)==(tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; + break; + } + } + + pos = ((row + img->row_offset) % rowsperstrip) * scanline; + (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, p0 + pos, p1 + pos, + p2 + pos, (alpha?(pa+pos):NULL)); + y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); + } + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } + } + } + + _TIFFfree(buf); + return (ret); +} + +/* + * The following routines move decoded data returned + * from the TIFF library into rasters filled with packed + * ABGR pixels (i.e. suitable for passing to lrecwrite.) + * + * The routines have been created according to the most + * important cases and optimized. PickContigCase and + * PickSeparateCase analyze the parameters and select + * the appropriate "get" and "put" routine to use. + */ +#define REPEAT8(op) REPEAT4(op); REPEAT4(op) +#define REPEAT4(op) REPEAT2(op); REPEAT2(op) +#define REPEAT2(op) op; op +#define CASE8(x,op) \ + switch (x) { \ + case 7: op; case 6: op; case 5: op; \ + case 4: op; case 3: op; case 2: op; \ + case 1: op; \ + } +#define CASE4(x,op) switch (x) { case 3: op; case 2: op; case 1: op; } +#define NOP + +#define UNROLL8(w, op1, op2) { \ + uint32 _x; \ + for (_x = w; _x >= 8; _x -= 8) { \ + op1; \ + REPEAT8(op2); \ + } \ + if (_x > 0) { \ + op1; \ + CASE8(_x,op2); \ + } \ +} +#define UNROLL4(w, op1, op2) { \ + uint32 _x; \ + for (_x = w; _x >= 4; _x -= 4) { \ + op1; \ + REPEAT4(op2); \ + } \ + if (_x > 0) { \ + op1; \ + CASE4(_x,op2); \ + } \ +} +#define UNROLL2(w, op1, op2) { \ + uint32 _x; \ + for (_x = w; _x >= 2; _x -= 2) { \ + op1; \ + REPEAT2(op2); \ + } \ + if (_x) { \ + op1; \ + op2; \ + } \ +} + +#define SKEW(r,g,b,skew) { r += skew; g += skew; b += skew; } +#define SKEW4(r,g,b,a,skew) { r += skew; g += skew; b += skew; a+= skew; } + +#define A1 (((uint32)0xffL)<<24) +#define PACK(r,g,b) \ + ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|A1) +#define PACK4(r,g,b,a) \ + ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|((uint32)(a)<<24)) +#define W2B(v) (((v)>>8)&0xff) +/* TODO: PACKW should have be made redundant in favor of Bitdepth16To8 LUT */ +#define PACKW(r,g,b) \ + ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|A1) +#define PACKW4(r,g,b,a) \ + ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|((uint32)W2B(a)<<24)) + +#define DECLAREContigPutFunc(name) \ +static void name(\ + TIFFRGBAImage* img, \ + uint32* cp, \ + uint32 x, uint32 y, \ + uint32 w, uint32 h, \ + int32 fromskew, int32 toskew, \ + unsigned char* pp \ +) + +/* + * 8-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put8bitcmaptile) +{ + uint32** PALmap = img->PALmap; + int samplesperpixel = img->samplesperpixel; + + (void) y; + while (h-- > 0) { + for (x = w; x-- > 0;) + { + *cp++ = PALmap[*pp][0]; + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 4-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put4bitcmaptile) +{ + uint32** PALmap = img->PALmap; + + (void) x; (void) y; + fromskew /= 2; + while (h-- > 0) { + uint32* bw; + UNROLL2(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 2-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put2bitcmaptile) +{ + uint32** PALmap = img->PALmap; + + (void) x; (void) y; + fromskew /= 4; + while (h-- > 0) { + uint32* bw; + UNROLL4(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 1-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put1bitcmaptile) +{ + uint32** PALmap = img->PALmap; + + (void) x; (void) y; + fromskew /= 8; + while (h-- > 0) { + uint32* bw; + UNROLL8(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(putgreytile) +{ + int samplesperpixel = img->samplesperpixel; + uint32** BWmap = img->BWmap; + + (void) y; + while (h-- > 0) { + for (x = w; x-- > 0;) + { + *cp++ = BWmap[*pp][0]; + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit greyscale with associated alpha => colormap/RGBA + */ +DECLAREContigPutFunc(putagreytile) +{ + int samplesperpixel = img->samplesperpixel; + uint32** BWmap = img->BWmap; + + (void) y; + while (h-- > 0) { + for (x = w; x-- > 0;) + { + *cp++ = BWmap[*pp][0] & (*(pp+1) << 24 | ~A1); + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 16-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(put16bitbwtile) +{ + int samplesperpixel = img->samplesperpixel; + uint32** BWmap = img->BWmap; + + (void) y; + while (h-- > 0) { + uint16 *wp = (uint16 *) pp; + + for (x = w; x-- > 0;) + { + /* use high order byte of 16bit value */ + + *cp++ = BWmap[*wp >> 8][0]; + pp += 2 * samplesperpixel; + wp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 1-bit bilevel => colormap/RGB + */ +DECLAREContigPutFunc(put1bitbwtile) +{ + uint32** BWmap = img->BWmap; + + (void) x; (void) y; + fromskew /= 8; + while (h-- > 0) { + uint32* bw; + UNROLL8(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 2-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(put2bitbwtile) +{ + uint32** BWmap = img->BWmap; + + (void) x; (void) y; + fromskew /= 4; + while (h-- > 0) { + uint32* bw; + UNROLL4(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 4-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(put4bitbwtile) +{ + uint32** BWmap = img->BWmap; + + (void) x; (void) y; + fromskew /= 2; + while (h-- > 0) { + uint32* bw; + UNROLL2(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit packed samples, no Map => RGB + */ +DECLAREContigPutFunc(putRGBcontig8bittile) +{ + int samplesperpixel = img->samplesperpixel; + + (void) x; (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + UNROLL8(w, NOP, + *cp++ = PACK(pp[0], pp[1], pp[2]); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit packed samples => RGBA w/ associated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBAAcontig8bittile) +{ + int samplesperpixel = img->samplesperpixel; + + (void) x; (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + UNROLL8(w, NOP, + *cp++ = PACK4(pp[0], pp[1], pp[2], pp[3]); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit packed samples => RGBA w/ unassociated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBUAcontig8bittile) +{ + int samplesperpixel = img->samplesperpixel; + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + uint32 r, g, b, a; + uint8* m; + for (x = w; x-- > 0;) { + a = pp[3]; + m = img->UaToAa+(a<<8); + r = m[pp[0]]; + g = m[pp[1]]; + b = m[pp[2]]; + *cp++ = PACK4(r,g,b,a); + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 16-bit packed samples => RGB + */ +DECLAREContigPutFunc(putRGBcontig16bittile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 *wp = (uint16 *)pp; + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + *cp++ = PACK(img->Bitdepth16To8[wp[0]], + img->Bitdepth16To8[wp[1]], + img->Bitdepth16To8[wp[2]]); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } +} + +/* + * 16-bit packed samples => RGBA w/ associated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBAAcontig16bittile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 *wp = (uint16 *)pp; + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + *cp++ = PACK4(img->Bitdepth16To8[wp[0]], + img->Bitdepth16To8[wp[1]], + img->Bitdepth16To8[wp[2]], + img->Bitdepth16To8[wp[3]]); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } +} + +/* + * 16-bit packed samples => RGBA w/ unassociated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBUAcontig16bittile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 *wp = (uint16 *)pp; + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + uint32 r,g,b,a; + uint8* m; + for (x = w; x-- > 0;) { + a = img->Bitdepth16To8[wp[3]]; + m = img->UaToAa+(a<<8); + r = m[img->Bitdepth16To8[wp[0]]]; + g = m[img->Bitdepth16To8[wp[1]]]; + b = m[img->Bitdepth16To8[wp[2]]]; + *cp++ = PACK4(r,g,b,a); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } +} + +/* + * 8-bit packed CMYK samples w/o Map => RGB + * + * NB: The conversion of CMYK->RGB is *very* crude. + */ +/*DECLAREContigPutFunc(putRGBcontig8bitCMYKtile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 r, g, b, k; + + (void) x; (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + UNROLL8(w, NOP, + k = 255 - pp[3]; + r = (k*(255-pp[0]))/255; + g = (k*(255-pp[1]))/255; + b = (k*(255-pp[2]))/255; + *cp++ = PACK(r, g, b); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; +}*/ +/* Modify in 20090723 by Sunliang.Liu */ +DECLAREContigPutFunc(putRGBcontig8bitCMYKtile) +{ + int samplesperpixel = img->samplesperpixel; + uint8 r, g, b, k; + + (void) x; (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + UNROLL8(w, NOP, + if(!TIFFCmyk2Rgb(img->tif->tif_clientdata,pp[0],pp[1],pp[2],pp[3], + &r,&g,&b)){ + k = 255 - pp[3]; + r = (k*(255-pp[0]))/255; + g = (k*(255-pp[1]))/255; + b = (k*(255-pp[2]))/255; + } + + *cp++ = PACK(r, g, b); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; + } +} + +/* + * 16-bit packed CMYK samples w/o Map => RGB(8-bit) + * + * NB: The conversion of CMYK->RGB is *very* crude. + */ +DECLAREContigPutFunc(putRGBcontig16bitCMYKtile) +{ + int samplesperpixel = img->samplesperpixel; + uint16* wp = (uint16*)pp; + uint8 C, M, Y, K; + uint8 r, g, b; + + (void) x; (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + UNROLL8(w, NOP, + C = wp[0]>>8;M = wp[1]>>8;Y = wp[2]>>8;K = wp[3]>>8; + if(!TIFFCmyk2Rgb(img->tif->tif_clientdata,C,M,Y,K, + &r,&g,&b)){ + K = 255 - K; + r = (K*(255-C))/255; + g = (K*(255-M))/255; + b = (K*(255-Y))/255; + } + + *cp++ = PACK(r, g, b); + wp += samplesperpixel); + cp += toskew; + wp += fromskew; + } +} + +/* + * 8-bit packed CMYK samples w/Map => RGB + * + * NB: The conversion of CMYK->RGB is *very* crude. + */ +/* +DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile) +{ + int samplesperpixel = img->samplesperpixel; + TIFFRGBValue* Map = img->Map; + uint16 r, g, b, k; + + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + k = 255 - pp[3]; + r = (k*(255-pp[0]))/255; + g = (k*(255-pp[1]))/255; + b = (k*(255-pp[2]))/255; + *cp++ = PACK(Map[r], Map[g], Map[b]); + pp += samplesperpixel; + } + pp += fromskew; + cp += toskew; + } +}*/ +/* Modify in 20090723 by Sunliang.Liu */ +DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile) +{ + int samplesperpixel = img->samplesperpixel; + TIFFRGBValue* Map = img->Map; + uint8 r, g, b, k; + + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + if(!TIFFCmyk2Rgb(img->tif->tif_clientdata,pp[0],pp[1],pp[2],pp[3], + &r,&g,&b)){ + k = 255 - pp[3]; + r = (k*(255-pp[0]))/255; + g = (k*(255-pp[1]))/255; + b = (k*(255-pp[2]))/255; + } + *cp++ = PACK(Map[r], Map[g], Map[b]); + pp += samplesperpixel; + } + pp += fromskew; + cp += toskew; + } +} + +/* + * 16-bit packed CMYK samples w/Map => RGB(8-bit) + * + * NB: The conversion of CMYK->RGB is *very* crude. + */ +DECLAREContigPutFunc(putRGBcontig16bitCMYKMaptile) +{ + int samplesperpixel = img->samplesperpixel; + TIFFRGBValue* Map = img->Map; + uint16* wp = (uint16*)pp; + uint8 C, M, Y, K; + uint8 r, g, b; + + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + C = wp[0]>>8;M = wp[1]>>8;Y = wp[2]>>8;K = wp[3]>>8; + if(!TIFFCmyk2Rgb(img->tif->tif_clientdata,C,M,Y,K, + &r,&g,&b)){ + K = 255 - K; + r = (K*(255-C))/255; + g = (K*(255-M))/255; + b = (K*(255-Y))/255; + } + *cp++ = PACK(Map[r], Map[g], Map[b]); + wp += samplesperpixel; + } + wp += fromskew; + cp += toskew; + } +} + +#define DECLARESepPutFunc(name) \ +static void name(\ + TIFFRGBAImage* img,\ + uint32* cp,\ + uint32 x, uint32 y, \ + uint32 w, uint32 h,\ + int32 fromskew, int32 toskew,\ + unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a\ +) + +/* + * 8-bit unpacked samples => RGB + */ +DECLARESepPutFunc(putRGBseparate8bittile) +{ + (void) img; (void) x; (void) y; (void) a; + while (h-- > 0) { + UNROLL8(w, NOP, *cp++ = PACK(*r++, *g++, *b++)); + SKEW(r, g, b, fromskew); + cp += toskew; + } +} + +/* + * 8-bit unpacked samples => RGBA w/ associated alpha + */ +DECLARESepPutFunc(putRGBAAseparate8bittile) +{ + (void) img; (void) x; (void) y; + while (h-- > 0) { + UNROLL8(w, NOP, *cp++ = PACK4(*r++, *g++, *b++, *a++)); + SKEW4(r, g, b, a, fromskew); + cp += toskew; + } +} + +/* + * 8-bit unpacked CMYK samples => RGBA + */ +DECLARESepPutFunc(putCMYKseparate8bittile) +{ + (void) img; (void) y; + while (h-- > 0) { + uint32 rv, gv, bv, kv; + for (x = w; x-- > 0;) { + kv = 255 - *a++; + rv = (kv*(255-*r++))/255; + gv = (kv*(255-*g++))/255; + bv = (kv*(255-*b++))/255; + *cp++ = PACK4(rv,gv,bv,255); + } + SKEW4(r, g, b, a, fromskew); + cp += toskew; + } +} + +/* + * 8-bit unpacked samples => RGBA w/ unassociated alpha + */ +DECLARESepPutFunc(putRGBUAseparate8bittile) +{ + (void) img; (void) y; + while (h-- > 0) { + uint32 rv, gv, bv, av; + uint8* m; + for (x = w; x-- > 0;) { + av = *a++; + m = img->UaToAa+(av<<8); + rv = m[*r++]; + gv = m[*g++]; + bv = m[*b++]; + *cp++ = PACK4(rv,gv,bv,av); + } + SKEW4(r, g, b, a, fromskew); + cp += toskew; + } +} + +/* + * 16-bit unpacked samples => RGB + */ +DECLARESepPutFunc(putRGBseparate16bittile) +{ + uint16 *wr = (uint16*) r; + uint16 *wg = (uint16*) g; + uint16 *wb = (uint16*) b; + (void) img; (void) y; (void) a; + while (h-- > 0) { + for (x = 0; x < w; x++) + *cp++ = PACK(img->Bitdepth16To8[*wr++], + img->Bitdepth16To8[*wg++], + img->Bitdepth16To8[*wb++]); + SKEW(wr, wg, wb, fromskew); + cp += toskew; + } +} + +/* + * 16-bit unpacked samples => RGBA w/ associated alpha + */ +DECLARESepPutFunc(putRGBAAseparate16bittile) +{ + uint16 *wr = (uint16*) r; + uint16 *wg = (uint16*) g; + uint16 *wb = (uint16*) b; + uint16 *wa = (uint16*) a; + (void) img; (void) y; + while (h-- > 0) { + for (x = 0; x < w; x++) + *cp++ = PACK4(img->Bitdepth16To8[*wr++], + img->Bitdepth16To8[*wg++], + img->Bitdepth16To8[*wb++], + img->Bitdepth16To8[*wa++]); + SKEW4(wr, wg, wb, wa, fromskew); + cp += toskew; + } +} + +/* + * 16-bit unpacked samples => RGBA w/ unassociated alpha + */ +DECLARESepPutFunc(putRGBUAseparate16bittile) +{ + uint16 *wr = (uint16*) r; + uint16 *wg = (uint16*) g; + uint16 *wb = (uint16*) b; + uint16 *wa = (uint16*) a; + (void) img; (void) y; + while (h-- > 0) { + uint32 r,g,b,a; + uint8* m; + for (x = w; x-- > 0;) { + a = img->Bitdepth16To8[*wa++]; + m = img->UaToAa+(a<<8); + r = m[img->Bitdepth16To8[*wr++]]; + g = m[img->Bitdepth16To8[*wg++]]; + b = m[img->Bitdepth16To8[*wb++]]; + *cp++ = PACK4(r,g,b,a); + } + SKEW4(wr, wg, wb, wa, fromskew); + cp += toskew; + } +} + +/* + * 8-bit packed CIE L*a*b 1976 samples => RGB + */ +DECLAREContigPutFunc(putcontig8bitCIELab) +{ + float X, Y, Z; + uint32 r, g, b; + (void) y; + fromskew *= 3; + while (h-- > 0) { + for (x = w; x-- > 0;) { + TIFFCIELabToXYZ(img->cielab, + (unsigned char)pp[0], + (signed char)pp[1], + (signed char)pp[2], + &X, &Y, &Z); + TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b); + *cp++ = PACK(r, g, b); + pp += 3; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * YCbCr -> RGB conversion and packing routines. + */ + +#define YCbCrtoRGB(dst, Y) { \ + uint32 r, g, b; \ + TIFFYCbCrtoRGB(img->ycbcr, (Y), Cb, Cr, &r, &g, &b); \ + dst = PACK(r, g, b); \ +} + +/* + * 8-bit packed YCbCr samples => RGB + * This function is generic for different sampling sizes, + * and can handle blocks sizes that aren't multiples of the + * sampling size. However, it is substantially less optimized + * than the specific sampling cases. It is used as a fallback + * for difficult blocks. + */ +#ifdef notdef +static void putcontig8bitYCbCrGenericTile( + TIFFRGBAImage* img, + uint32* cp, + uint32 x, uint32 y, + uint32 w, uint32 h, + int32 fromskew, int32 toskew, + unsigned char* pp, + int h_group, + int v_group ) + +{ + uint32* cp1 = cp+w+toskew; + uint32* cp2 = cp1+w+toskew; + uint32* cp3 = cp2+w+toskew; + int32 incr = 3*w+4*toskew; + int32 Cb, Cr; + int group_size = v_group * h_group + 2; + + (void) y; + fromskew = (fromskew * group_size) / h_group; + + for( yy = 0; yy < h; yy++ ) + { + unsigned char *pp_line; + int y_line_group = yy / v_group; + int y_remainder = yy - y_line_group * v_group; + + pp_line = pp + v_line_group * + + + for( xx = 0; xx < w; xx++ ) + { + Cb = pp + } + } + for (; h >= 4; h -= 4) { + x = w>>2; + do { + Cb = pp[16]; + Cr = pp[17]; + + YCbCrtoRGB(cp [0], pp[ 0]); + YCbCrtoRGB(cp [1], pp[ 1]); + YCbCrtoRGB(cp [2], pp[ 2]); + YCbCrtoRGB(cp [3], pp[ 3]); + YCbCrtoRGB(cp1[0], pp[ 4]); + YCbCrtoRGB(cp1[1], pp[ 5]); + YCbCrtoRGB(cp1[2], pp[ 6]); + YCbCrtoRGB(cp1[3], pp[ 7]); + YCbCrtoRGB(cp2[0], pp[ 8]); + YCbCrtoRGB(cp2[1], pp[ 9]); + YCbCrtoRGB(cp2[2], pp[10]); + YCbCrtoRGB(cp2[3], pp[11]); + YCbCrtoRGB(cp3[0], pp[12]); + YCbCrtoRGB(cp3[1], pp[13]); + YCbCrtoRGB(cp3[2], pp[14]); + YCbCrtoRGB(cp3[3], pp[15]); + + cp += 4, cp1 += 4, cp2 += 4, cp3 += 4; + pp += 18; + } while (--x); + cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; + pp += fromskew; + } +} +#endif + +/* + * 8-bit packed YCbCr samples w/ 4,4 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr44tile) +{ + uint32* cp1 = cp+w+toskew; + uint32* cp2 = cp1+w+toskew; + uint32* cp3 = cp2+w+toskew; + int32 incr = 3*w+4*toskew; + + (void) y; + /* adjust fromskew */ + fromskew = (fromskew * 18) / 4; + if ((h & 3) == 0 && (w & 3) == 0) { + for (; h >= 4; h -= 4) { + x = w>>2; + do { + int32 Cb = pp[16]; + int32 Cr = pp[17]; + + YCbCrtoRGB(cp [0], pp[ 0]); + YCbCrtoRGB(cp [1], pp[ 1]); + YCbCrtoRGB(cp [2], pp[ 2]); + YCbCrtoRGB(cp [3], pp[ 3]); + YCbCrtoRGB(cp1[0], pp[ 4]); + YCbCrtoRGB(cp1[1], pp[ 5]); + YCbCrtoRGB(cp1[2], pp[ 6]); + YCbCrtoRGB(cp1[3], pp[ 7]); + YCbCrtoRGB(cp2[0], pp[ 8]); + YCbCrtoRGB(cp2[1], pp[ 9]); + YCbCrtoRGB(cp2[2], pp[10]); + YCbCrtoRGB(cp2[3], pp[11]); + YCbCrtoRGB(cp3[0], pp[12]); + YCbCrtoRGB(cp3[1], pp[13]); + YCbCrtoRGB(cp3[2], pp[14]); + YCbCrtoRGB(cp3[3], pp[15]); + + cp += 4, cp1 += 4, cp2 += 4, cp3 += 4; + pp += 18; + } while (--x); + cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; + pp += fromskew; + } + } else { + while (h > 0) { + for (x = w; x > 0;) { + int32 Cb = pp[16]; + int32 Cr = pp[17]; + switch (x) { + default: + switch (h) { + default: YCbCrtoRGB(cp3[3], pp[15]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[3], pp[11]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 3: + switch (h) { + default: YCbCrtoRGB(cp3[2], pp[14]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[2], pp[10]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 2: + switch (h) { + default: YCbCrtoRGB(cp3[1], pp[13]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[1], pp[ 9]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) { + default: YCbCrtoRGB(cp3[0], pp[12]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[0], pp[ 8]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + } + if (x < 4) { + cp += x; cp1 += x; cp2 += x; cp3 += x; + x = 0; + } + else { + cp += 4; cp1 += 4; cp2 += 4; cp3 += 4; + x -= 4; + } + pp += 18; + } + if (h <= 4) + break; + h -= 4; + cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; + pp += fromskew; + } + } +} + +/* + * 8-bit packed YCbCr samples w/ 4,2 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr42tile) +{ + uint32* cp1 = cp+w+toskew; + int32 incr = 2*toskew+w; + + (void) y; + fromskew = (fromskew * 10) / 4; + if ((h & 3) == 0 && (w & 1) == 0) { + for (; h >= 2; h -= 2) { + x = w>>2; + do { + int32 Cb = pp[8]; + int32 Cr = pp[9]; + + YCbCrtoRGB(cp [0], pp[0]); + YCbCrtoRGB(cp [1], pp[1]); + YCbCrtoRGB(cp [2], pp[2]); + YCbCrtoRGB(cp [3], pp[3]); + YCbCrtoRGB(cp1[0], pp[4]); + YCbCrtoRGB(cp1[1], pp[5]); + YCbCrtoRGB(cp1[2], pp[6]); + YCbCrtoRGB(cp1[3], pp[7]); + + cp += 4, cp1 += 4; + pp += 10; + } while (--x); + cp += incr, cp1 += incr; + pp += fromskew; + } + } else { + while (h > 0) { + for (x = w; x > 0;) { + int32 Cb = pp[8]; + int32 Cr = pp[9]; + switch (x) { + default: + switch (h) { + default: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 3: + switch (h) { + default: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 2: + switch (h) { + default: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) { + default: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + } + if (x < 4) { + cp += x; cp1 += x; + x = 0; + } + else { + cp += 4; cp1 += 4; + x -= 4; + } + pp += 10; + } + if (h <= 2) + break; + h -= 2; + cp += incr, cp1 += incr; + pp += fromskew; + } + } +} + +/* + * 8-bit packed YCbCr samples w/ 4,1 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr41tile) +{ + (void) y; + /* XXX adjust fromskew */ + do { + x = w>>2; + do { + int32 Cb = pp[4]; + int32 Cr = pp[5]; + + YCbCrtoRGB(cp [0], pp[0]); + YCbCrtoRGB(cp [1], pp[1]); + YCbCrtoRGB(cp [2], pp[2]); + YCbCrtoRGB(cp [3], pp[3]); + + cp += 4; + pp += 6; + } while (--x); + + if( (w&3) != 0 ) + { + int32 Cb = pp[4]; + int32 Cr = pp[5]; + + switch( (w&3) ) { + case 3: YCbCrtoRGB(cp [2], pp[2]); + case 2: YCbCrtoRGB(cp [1], pp[1]); + case 1: YCbCrtoRGB(cp [0], pp[0]); + case 0: break; + } + + cp += (w&3); + pp += 6; + } + + cp += toskew; + pp += fromskew; + } while (--h); + +} + +/* + * 8-bit packed YCbCr samples w/ 2,2 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr22tile) +{ + uint32* cp2; + int32 incr = 2*toskew+w; + (void) y; + fromskew = (fromskew / 2) * 6; + cp2 = cp+w+toskew; + while (h>=2) { + x = w; + while (x>=2) { + uint32 Cb = pp[4]; + uint32 Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + YCbCrtoRGB(cp2[0], pp[2]); + YCbCrtoRGB(cp2[1], pp[3]); + cp += 2; + cp2 += 2; + pp += 6; + x -= 2; + } + if (x==1) { + uint32 Cb = pp[4]; + uint32 Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp2[0], pp[2]); + cp ++ ; + cp2 ++ ; + pp += 6; + } + cp += incr; + cp2 += incr; + pp += fromskew; + h-=2; + } + if (h==1) { + x = w; + while (x>=2) { + uint32 Cb = pp[4]; + uint32 Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + cp += 2; + cp2 += 2; + pp += 6; + x -= 2; + } + if (x==1) { + uint32 Cb = pp[4]; + uint32 Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + } + } +} + +/* + * 8-bit packed YCbCr samples w/ 2,1 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr21tile) +{ + (void) y; + fromskew = (fromskew * 4) / 2; + do { + x = w>>1; + do { + int32 Cb = pp[2]; + int32 Cr = pp[3]; + + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + + cp += 2; + pp += 4; + } while (--x); + + if( (w&1) != 0 ) + { + int32 Cb = pp[2]; + int32 Cr = pp[3]; + + YCbCrtoRGB(cp[0], pp[0]); + + cp += 1; + pp += 4; + } + + cp += toskew; + pp += fromskew; + } while (--h); +} + +/* + * 8-bit packed YCbCr samples w/ 1,2 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr12tile) +{ + uint32* cp2; + int32 incr = 2*toskew+w; + (void) y; + fromskew = (fromskew / 2) * 4; + cp2 = cp+w+toskew; + while (h>=2) { + x = w; + do { + uint32 Cb = pp[2]; + uint32 Cr = pp[3]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp2[0], pp[1]); + cp ++; + cp2 ++; + pp += 4; + } while (--x); + cp += incr; + cp2 += incr; + pp += fromskew; + h-=2; + } + if (h==1) { + x = w; + do { + uint32 Cb = pp[2]; + uint32 Cr = pp[3]; + YCbCrtoRGB(cp[0], pp[0]); + cp ++; + pp += 4; + } while (--x); + } +} + +/* + * 8-bit packed YCbCr samples w/ no subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr11tile) +{ + (void) y; + fromskew *= 3; + do { + x = w; /* was x = w>>1; patched 2000/09/25 warmerda@home.com */ + do { + int32 Cb = pp[1]; + int32 Cr = pp[2]; + + YCbCrtoRGB(*cp++, pp[0]); + + pp += 3; + } while (--x); + cp += toskew; + pp += fromskew; + } while (--h); +} + +/* + * 8-bit packed YCbCr samples w/ no subsampling => RGB + */ +DECLARESepPutFunc(putseparate8bitYCbCr11tile) +{ + (void) y; + (void) a; + /* TODO: naming of input vars is still off, change obfuscating declaration inside define, or resolve obfuscation */ + while (h-- > 0) { + x = w; + do { + uint32 dr, dg, db; + TIFFYCbCrtoRGB(img->ycbcr,*r++,*g++,*b++,&dr,&dg,&db); + *cp++ = PACK(dr,dg,db); + } while (--x); + SKEW(r, g, b, fromskew); + cp += toskew; + } +} +#undef YCbCrtoRGB + +static int +initYCbCrConversion(TIFFRGBAImage* img) +{ + static const char module[] = "initYCbCrConversion"; + + float *luma, *refBlackWhite; + + if (img->ycbcr == NULL) { + img->ycbcr = (TIFFYCbCrToRGB*) _TIFFmalloc( + TIFFroundup_32(sizeof (TIFFYCbCrToRGB), sizeof (long)) + + 4*256*sizeof (TIFFRGBValue) + + 2*256*sizeof (int) + + 3*256*sizeof (int32) + ); + if (img->ycbcr == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, module, + "No space for YCbCr->RGB conversion state"); + return (0); + } + } + + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &luma); + TIFFGetFieldDefaulted(img->tif, TIFFTAG_REFERENCEBLACKWHITE, + &refBlackWhite); + if (TIFFYCbCrToRGBInit(img->ycbcr, luma, refBlackWhite) < 0) + return(0); + return (1); +} + +static tileContigRoutine +initCIELabConversion(TIFFRGBAImage* img) +{ + static const char module[] = "initCIELabConversion"; + + float *whitePoint; + float refWhite[3]; + + if (!img->cielab) { + img->cielab = (TIFFCIELabToRGB *) + _TIFFmalloc(sizeof(TIFFCIELabToRGB)); + if (!img->cielab) { + TIFFErrorExt(img->tif->tif_clientdata, module, + "No space for CIE L*a*b*->RGB conversion state."); + return NULL; + } + } + + TIFFGetFieldDefaulted(img->tif, TIFFTAG_WHITEPOINT, &whitePoint); + refWhite[1] = 100.0F; + refWhite[0] = whitePoint[0] / whitePoint[1] * refWhite[1]; + refWhite[2] = (1.0F - whitePoint[0] - whitePoint[1]) + / whitePoint[1] * refWhite[1]; + if (TIFFCIELabToRGBInit(img->cielab, &display_sRGB, refWhite) < 0) { + TIFFErrorExt(img->tif->tif_clientdata, module, + "Failed to initialize CIE L*a*b*->RGB conversion state."); + _TIFFfree(img->cielab); + return NULL; + } + + return (tileContigRoutine)putcontig8bitCIELab; +} + +/* + * Greyscale images with less than 8 bits/sample are handled + * with a table to avoid lots of shifts and masks. The table + * is setup so that put*bwtile (below) can retrieve 8/bitspersample + * pixel values simply by indexing into the table with one + * number. + */ +static int +makebwmap(TIFFRGBAImage* img) +{ + TIFFRGBValue* Map = img->Map; + int bitspersample = img->bitspersample; + int nsamples = 8 / bitspersample; + int i; + uint32* p; + + if( nsamples == 0 ) + nsamples = 1; + + img->BWmap = (uint32**) _TIFFmalloc( + 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); + if (img->BWmap == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for B&W mapping table"); + return (0); + } + p = (uint32*)(img->BWmap + 256); + for (i = 0; i < 256; i++) { + TIFFRGBValue c; + img->BWmap[i] = p; + switch (bitspersample) { +#define GREY(x) c = Map[x]; *p++ = PACK(c,c,c); + case 1: + GREY(i>>7); + GREY((i>>6)&1); + GREY((i>>5)&1); + GREY((i>>4)&1); + GREY((i>>3)&1); + GREY((i>>2)&1); + GREY((i>>1)&1); + GREY(i&1); + break; + case 2: + GREY(i>>6); + GREY((i>>4)&3); + GREY((i>>2)&3); + GREY(i&3); + break; + case 4: + GREY(i>>4); + GREY(i&0xf); + break; + case 8: + case 16: + GREY(i); + break; + } +#undef GREY + } + return (1); +} + +/* + * Construct a mapping table to convert from the range + * of the data samples to [0,255] --for display. This + * process also handles inverting B&W images when needed. + */ +static int +setupMap(TIFFRGBAImage* img) +{ + int32 x, range; + + range = (int32)((1L<bitspersample)-1); + + /* treat 16 bit the same as eight bit */ + if( img->bitspersample == 16 ) + range = (int32) 255; + + img->Map = (TIFFRGBValue*) _TIFFmalloc((range+1) * sizeof (TIFFRGBValue)); + if (img->Map == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), + "No space for photometric conversion table"); + return (0); + } + if (img->photometric == PHOTOMETRIC_MINISWHITE) { + for (x = 0; x <= range; x++) + img->Map[x] = (TIFFRGBValue) (((range - x) * 255) / range); + } else { + for (x = 0; x <= range; x++) + img->Map[x] = (TIFFRGBValue) ((x * 255) / range); + } + if (img->bitspersample <= 16 && + (img->photometric == PHOTOMETRIC_MINISBLACK || + img->photometric == PHOTOMETRIC_MINISWHITE)) { + /* + * Use photometric mapping table to construct + * unpacking tables for samples <= 8 bits. + */ + if (!makebwmap(img)) + return (0); + /* no longer need Map, free it */ + _TIFFfree(img->Map), img->Map = NULL; + } + return (1); +} + +static int +checkcmap(TIFFRGBAImage* img) +{ + uint16* r = img->redcmap; + uint16* g = img->greencmap; + uint16* b = img->bluecmap; + long n = 1L<bitspersample; + + while (n-- > 0) + if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) + return (16); + return (8); +} + +static void +cvtcmap(TIFFRGBAImage* img) +{ + uint16* r = img->redcmap; + uint16* g = img->greencmap; + uint16* b = img->bluecmap; + long i; + + for (i = (1L<bitspersample)-1; i >= 0; i--) { +#define CVT(x) ((uint16)((x)>>8)) + r[i] = CVT(r[i]); + g[i] = CVT(g[i]); + b[i] = CVT(b[i]); +#undef CVT + } +} + +/* + * Palette images with <= 8 bits/sample are handled + * with a table to avoid lots of shifts and masks. The table + * is setup so that put*cmaptile (below) can retrieve 8/bitspersample + * pixel values simply by indexing into the table with one + * number. + */ +static int +makecmap(TIFFRGBAImage* img) +{ + int bitspersample = img->bitspersample; + int nsamples = 8 / bitspersample; + uint16* r = img->redcmap; + uint16* g = img->greencmap; + uint16* b = img->bluecmap; + uint32 *p; + int i; + + img->PALmap = (uint32**) _TIFFmalloc( + 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); + if (img->PALmap == NULL) { + TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for Palette mapping table"); + return (0); + } + p = (uint32*)(img->PALmap + 256); + for (i = 0; i < 256; i++) { + TIFFRGBValue c; + img->PALmap[i] = p; +#define CMAP(x) c = (TIFFRGBValue) x; *p++ = PACK(r[c]&0xff, g[c]&0xff, b[c]&0xff); + switch (bitspersample) { + case 1: + CMAP(i>>7); + CMAP((i>>6)&1); + CMAP((i>>5)&1); + CMAP((i>>4)&1); + CMAP((i>>3)&1); + CMAP((i>>2)&1); + CMAP((i>>1)&1); + CMAP(i&1); + break; + case 2: + CMAP(i>>6); + CMAP((i>>4)&3); + CMAP((i>>2)&3); + CMAP(i&3); + break; + case 4: + CMAP(i>>4); + CMAP(i&0xf); + break; + case 8: + CMAP(i); + break; + } +#undef CMAP + } + return (1); +} + +/* + * Construct any mapping table used + * by the associated put routine. + */ +static int +buildMap(TIFFRGBAImage* img) +{ + switch (img->photometric) { + case PHOTOMETRIC_RGB: + case PHOTOMETRIC_YCBCR: + case PHOTOMETRIC_SEPARATED: + if (img->bitspersample == 8) + break; + /* fall thru... */ + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_MINISWHITE: + if (!setupMap(img)) + return (0); + break; + case PHOTOMETRIC_PALETTE: + /* + * Convert 16-bit colormap to 8-bit (unless it looks + * like an old-style 8-bit colormap). + */ + if (checkcmap(img) == 16) + cvtcmap(img); + else + TIFFWarningExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "Assuming 8-bit colormap"); + /* + * Use mapping table and colormap to construct + * unpacking tables for samples < 8 bits. + */ + if (img->bitspersample <= 8 && !makecmap(img)) + return (0); + break; + } + return (1); +} + +/* + * Select the appropriate conversion routine for packed data. + */ +static int +PickContigCase(TIFFRGBAImage* img) +{ + img->get = TIFFIsTiled(img->tif) ? gtTileContig : gtStripContig; + img->put.contig = NULL; + switch (img->photometric) { + case PHOTOMETRIC_RGB: + switch (img->bitspersample) { + case 8: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + img->put.contig = putRGBAAcontig8bittile; + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + if (BuildMapUaToAa(img)) + img->put.contig = putRGBUAcontig8bittile; + } + else + img->put.contig = putRGBcontig8bittile; + break; + case 16: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + { + if (BuildMapBitdepth16To8(img)) + img->put.contig = putRGBAAcontig16bittile; + } + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + if (BuildMapBitdepth16To8(img) && + BuildMapUaToAa(img)) + img->put.contig = putRGBUAcontig16bittile; + } + else + { + if (BuildMapBitdepth16To8(img)) + img->put.contig = putRGBcontig16bittile; + } + break; + } + break; + case PHOTOMETRIC_SEPARATED: + if (buildMap(img)) { + if (img->bitspersample == 8) { + if (!img->Map) + img->put.contig = putRGBcontig8bitCMYKtile; + else + img->put.contig = putRGBcontig8bitCMYKMaptile; + } + else if(img->bitspersample == 16) /*LiuSunliang added 16bpp CMYK support.*/ + { + if (!img->Map) + img->put.contig = putRGBcontig16bitCMYKtile; + else + img->put.contig = putRGBcontig16bitCMYKMaptile; + } + } + break; + case PHOTOMETRIC_PALETTE: + if (buildMap(img)) { + switch (img->bitspersample) { + case 8: + img->put.contig = put8bitcmaptile; + break; + case 4: + img->put.contig = put4bitcmaptile; + break; + case 2: + img->put.contig = put2bitcmaptile; + break; + case 1: + img->put.contig = put1bitcmaptile; + break; + } + } + break; + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + if (buildMap(img)) { + switch (img->bitspersample) { + case 16: + img->put.contig = put16bitbwtile; + break; + case 8: + if (img->alpha && img->samplesperpixel == 2) + img->put.contig = putagreytile; + else + img->put.contig = putgreytile; + break; + case 4: + img->put.contig = put4bitbwtile; + break; + case 2: + img->put.contig = put2bitbwtile; + break; + case 1: + img->put.contig = put1bitbwtile; + break; + } + } + break; + case PHOTOMETRIC_YCBCR: + if ((img->bitspersample==8) && (img->samplesperpixel==3)) + { + if (initYCbCrConversion(img)!=0) + { + /* + * The 6.0 spec says that subsampling must be + * one of 1, 2, or 4, and that vertical subsampling + * must always be <= horizontal subsampling; so + * there are only a few possibilities and we just + * enumerate the cases. + * Joris: added support for the [1,2] case, nonetheless, to accomodate + * some OJPEG files + */ + uint16 SubsamplingHor; + uint16 SubsamplingVer; + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &SubsamplingHor, &SubsamplingVer); + switch ((SubsamplingHor<<4)|SubsamplingVer) { + case 0x44: + img->put.contig = putcontig8bitYCbCr44tile; + break; + case 0x42: + img->put.contig = putcontig8bitYCbCr42tile; + break; + case 0x41: + img->put.contig = putcontig8bitYCbCr41tile; + break; + case 0x22: + img->put.contig = putcontig8bitYCbCr22tile; + break; + case 0x21: + img->put.contig = putcontig8bitYCbCr21tile; + break; + case 0x12: + img->put.contig = putcontig8bitYCbCr12tile; + break; + case 0x11: + img->put.contig = putcontig8bitYCbCr11tile; + break; + } + } + } + break; + case PHOTOMETRIC_CIELAB: + if (buildMap(img)) { + if (img->bitspersample == 8) + img->put.contig = initCIELabConversion(img); + break; + } + } + return ((img->get!=NULL) && (img->put.contig!=NULL)); +} + +/* + * Select the appropriate conversion routine for unpacked data. + * + * NB: we assume that unpacked single channel data is directed + * to the "packed routines. + */ +static int +PickSeparateCase(TIFFRGBAImage* img) +{ + img->get = TIFFIsTiled(img->tif) ? gtTileSeparate : gtStripSeparate; + img->put.separate = NULL; + switch (img->photometric) { + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + /* greyscale images processed pretty much as RGB by gtTileSeparate */ + case PHOTOMETRIC_RGB: + switch (img->bitspersample) { + case 8: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + img->put.separate = putRGBAAseparate8bittile; + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + if (BuildMapUaToAa(img)) + img->put.separate = putRGBUAseparate8bittile; + } + else + img->put.separate = putRGBseparate8bittile; + break; + case 16: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + { + if (BuildMapBitdepth16To8(img)) + img->put.separate = putRGBAAseparate16bittile; + } + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + if (BuildMapBitdepth16To8(img) && + BuildMapUaToAa(img)) + img->put.separate = putRGBUAseparate16bittile; + } + else + { + if (BuildMapBitdepth16To8(img)) + img->put.separate = putRGBseparate16bittile; + } + break; + } + break; + case PHOTOMETRIC_SEPARATED: + if (img->bitspersample == 8 && img->samplesperpixel == 4) + { + img->alpha = 1; // Not alpha, but seems like the only way to get 4th band + img->put.separate = putCMYKseparate8bittile; + } + break; + case PHOTOMETRIC_YCBCR: + if ((img->bitspersample==8) && (img->samplesperpixel==3)) + { + if (initYCbCrConversion(img)!=0) + { + uint16 hs, vs; + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs); + switch ((hs<<4)|vs) { + case 0x11: + img->put.separate = putseparate8bitYCbCr11tile; + break; + /* TODO: add other cases here */ + } + } + } + break; + } + return ((img->get!=NULL) && (img->put.separate!=NULL)); +} + +static int +BuildMapUaToAa(TIFFRGBAImage* img) +{ + static const char module[]="BuildMapUaToAa"; + uint8* m; + uint16 na,nv; + assert(img->UaToAa==NULL); + img->UaToAa=_TIFFmalloc(65536); + if (img->UaToAa==NULL) + { + TIFFErrorExt(img->tif->tif_clientdata,module,"Out of memory"); + return(0); + } + m=img->UaToAa; + for (na=0; na<256; na++) + { + for (nv=0; nv<256; nv++) + *m++=(nv*na+127)/255; + } + return(1); +} + +static int +BuildMapBitdepth16To8(TIFFRGBAImage* img) +{ + static const char module[]="BuildMapBitdepth16To8"; + uint8* m; + uint32 n; + assert(img->Bitdepth16To8==NULL); + img->Bitdepth16To8=_TIFFmalloc(65536); + if (img->Bitdepth16To8==NULL) + { + TIFFErrorExt(img->tif->tif_clientdata,module,"Out of memory"); + return(0); + } + m=img->Bitdepth16To8; + for (n=0; n<65536; n++) + *m++=(n+128)/257; + return(1); +} + + +/* + * Read a whole strip off data from the file, and convert to RGBA form. + * If this is the last strip, then it will only contain the portion of + * the strip that is actually within the image space. The result is + * organized in bottom to top form. + */ + + +int +TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster ) + +{ + char emsg[1024] = ""; + TIFFRGBAImage img; + int ok; + uint32 rowsperstrip, rows_to_read; + + if( TIFFIsTiled( tif ) ) + { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), + "Can't use TIFFReadRGBAStrip() with tiled file."); + return (0); + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + if( (row % rowsperstrip) != 0 ) + { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), + "Row passed to TIFFReadRGBAStrip() must be first in a strip."); + return (0); + } + + if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, 0, emsg)) { + + img.row_offset = row; + img.col_offset = 0; + + if( row + rowsperstrip > img.height ) + rows_to_read = img.height - row; + else + rows_to_read = rowsperstrip; + + ok = TIFFRGBAImageGet(&img, raster, img.width, rows_to_read ); + + TIFFRGBAImageEnd(&img); + } else { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); + ok = 0; + } + + return (ok); +} + +/* + * Read a whole tile off data from the file, and convert to RGBA form. + * The returned RGBA data is organized from bottom to top of tile, + * and may include zeroed areas if the tile extends off the image. + */ + +int +TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) + +{ + char emsg[1024] = ""; + TIFFRGBAImage img; + int ok; + uint32 tile_xsize, tile_ysize; + uint32 read_xsize, read_ysize; + uint32 i_row; + + /* + * Verify that our request is legal - on a tile file, and on a + * tile boundary. + */ + + if( !TIFFIsTiled( tif ) ) + { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), + "Can't use TIFFReadRGBATile() with stripped file."); + return (0); + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize); + TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize); + if( (col % tile_xsize) != 0 || (row % tile_ysize) != 0 ) + { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), + "Row/col passed to TIFFReadRGBATile() must be top" + "left corner of a tile."); + return (0); + } + + /* + * Setup the RGBA reader. + */ + + if (!TIFFRGBAImageOK(tif, emsg) + || !TIFFRGBAImageBegin(&img, tif, 0, emsg)) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); + return( 0 ); + } + + /* + * The TIFFRGBAImageGet() function doesn't allow us to get off the + * edge of the image, even to fill an otherwise valid tile. So we + * figure out how much we can read, and fix up the tile buffer to + * a full tile configuration afterwards. + */ + + if( row + tile_ysize > img.height ) + read_ysize = img.height - row; + else + read_ysize = tile_ysize; + + if( col + tile_xsize > img.width ) + read_xsize = img.width - col; + else + read_xsize = tile_xsize; + + /* + * Read the chunk of imagery. + */ + + img.row_offset = row; + img.col_offset = col; + + ok = TIFFRGBAImageGet(&img, raster, read_xsize, read_ysize ); + + TIFFRGBAImageEnd(&img); + + /* + * If our read was incomplete we will need to fix up the tile by + * shifting the data around as if a full tile of data is being returned. + * + * This is all the more complicated because the image is organized in + * bottom to top format. + */ + + if( read_xsize == tile_xsize && read_ysize == tile_ysize ) + return( ok ); + + for( i_row = 0; i_row < read_ysize; i_row++ ) { + memmove( raster + (tile_ysize - i_row - 1) * tile_xsize, + raster + (read_ysize - i_row - 1) * read_xsize, + read_xsize * sizeof(uint32) ); + _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize+read_xsize, + 0, sizeof(uint32) * (tile_xsize - read_xsize) ); + } + + for( i_row = read_ysize; i_row < tile_ysize; i_row++ ) { + _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize, + 0, sizeof(uint32) * tile_xsize ); + } + + return (ok); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_jpeg.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_jpeg.c new file mode 100644 index 0000000000..84f0f9e66d --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_jpeg.c @@ -0,0 +1,2311 @@ +/* $Id: tif_jpeg.c,v 1.111 2012-07-06 18:48:04 bfriesen Exp $ */ + +/* + * Copyright (c) 1994-1997 Sam Leffler + * Copyright (c) 1994-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN + +#include "tiffiop.h" +#ifdef JPEG_SUPPORT + +/* + * TIFF Library + * + * JPEG Compression support per TIFF Technical Note #2 + * (*not* per the original TIFF 6.0 spec). + * + * This file is simply an interface to the libjpeg library written by + * the Independent JPEG Group. You need release 5 or later of the IJG + * code, which you can find on the Internet at ftp.uu.net:/graphics/jpeg/. + * + * Contributed by Tom Lane . + */ +#include + +int TIFFFillStrip(TIFF* tif, uint32 strip); +int TIFFFillTile(TIFF* tif, uint32 tile); +int TIFFReInitJPEG_12( TIFF *tif, int scheme, int is_encode ); + +/* We undefine FAR to avoid conflict with JPEG definition */ + +#ifdef FAR +#undef FAR +#endif + +/* + Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is + not defined. Unfortunately, the MinGW and Borland compilers include + a typedef for INT32, which causes a conflict. MSVC does not include + a conficting typedef given the headers which are included. +*/ +#if defined(__BORLANDC__) || defined(__MINGW32__) +# define XMD_H 1 +#endif + +/* + The windows RPCNDR.H file defines boolean, but defines it with the + unsigned char size. You should compile JPEG library using appropriate + definitions in jconfig.h header, but many users compile library in wrong + way. That causes errors of the following type: + + "JPEGLib: JPEG parameter struct mismatch: library thinks size is 432, + caller expects 464" + + For such users we wil fix the problem here. See install.doc file from + the JPEG library distribution for details. +*/ + +/* Define "boolean" as unsigned char, not int, per Windows custom. */ +#if defined(WIN32) && !defined(__MINGW32__) +# ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ + typedef unsigned char boolean; +# endif +# define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +#endif + +#ifndef _FX_JPEG_TURBO_ + #include "../../libjpeg/jpeglib.h" + #include "../../libjpeg/jerror.h" +#else + #include "../../libjpeg-turbo/jpeglib.h" + #include "../../libjpeg-turbo/jerror.h" +#endif//_FX_JPEG_TURBO_ + +/* + * Do we want to do special processing suitable for when JSAMPLE is a + * 16bit value? + */ + +#if defined(JPEG_LIB_MK1) +# define JPEG_LIB_MK1_OR_12BIT 1 +#elif BITS_IN_JSAMPLE == 12 +# define JPEG_LIB_MK1_OR_12BIT 1 +#endif + +/* + * We are using width_in_blocks which is supposed to be private to + * libjpeg. Unfortunately, the libjpeg delivered with Cygwin has + * renamed this member to width_in_data_units. Since the header has + * also renamed a define, use that unique define name in order to + * detect the problem header and adjust to suit. + */ +#if defined(D_MAX_DATA_UNITS_IN_MCU) +#define width_in_blocks width_in_data_units +#endif + +/* + * On some machines it may be worthwhile to use _setjmp or sigsetjmp + * in place of plain setjmp. These macros will make it easier. + */ +#define SETJMP(jbuf) setjmp(jbuf) +#define LONGJMP(jbuf,code) longjmp(jbuf,code) +#define JMP_BUF jmp_buf + +typedef struct jpeg_destination_mgr jpeg_destination_mgr; +typedef struct jpeg_source_mgr jpeg_source_mgr; +typedef struct jpeg_error_mgr jpeg_error_mgr; + +/* + * State block for each open TIFF file using + * libjpeg to do JPEG compression/decompression. + * + * libjpeg's visible state is either a jpeg_compress_struct + * or jpeg_decompress_struct depending on which way we + * are going. comm can be used to refer to the fields + * which are common to both. + * + * NB: cinfo is required to be the first member of JPEGState, + * so we can safely cast JPEGState* -> jpeg_xxx_struct* + * and vice versa! + */ +typedef struct { + union { + struct jpeg_compress_struct c; + struct jpeg_decompress_struct d; + struct jpeg_common_struct comm; + } cinfo; /* NB: must be first */ + int cinfo_initialized; + + jpeg_error_mgr err; /* libjpeg error manager */ + JMP_BUF exit_jmpbuf; /* for catching libjpeg failures */ + /* + * The following two members could be a union, but + * they're small enough that it's not worth the effort. + */ + jpeg_destination_mgr dest; /* data dest for compression */ + jpeg_source_mgr src; /* data source for decompression */ + /* private state */ + TIFF* tif; /* back link needed by some code */ + uint16 photometric; /* copy of PhotometricInterpretation */ + uint16 h_sampling; /* luminance sampling factors */ + uint16 v_sampling; + tmsize_t bytesperline; /* decompressed bytes per scanline */ + /* pointers to intermediate buffers when processing downsampled data */ + JSAMPARRAY ds_buffer[MAX_COMPONENTS]; + int scancount; /* number of "scanlines" accumulated */ + int samplesperclump; + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFPrintMethod printdir; /* super-class method */ + TIFFStripMethod defsparent; /* super-class method */ + TIFFTileMethod deftparent; /* super-class method */ + /* pseudo-tag fields */ + void* jpegtables; /* JPEGTables tag value, or NULL */ + uint32 jpegtables_length; /* number of bytes in same */ + int jpegquality; /* Compression quality level */ + int jpegcolormode; /* Auto RGB<=>YCbCr convert? */ + int jpegtablesmode; /* What to put in JPEGTables */ + + int ycbcrsampling_fetched; +} JPEGState; + +#define JState(tif) ((JPEGState*)(tif)->tif_data) + +static int JPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s); +static int JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s); +static int JPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s); +static int JPEGEncodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s); +static int JPEGInitializeLibJPEG(TIFF * tif, int decode ); +static int DecodeRowError(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s); + +#define FIELD_JPEGTABLES (FIELD_CODEC+0) + +static const TIFFField jpegFields[] = { + { TIFFTAG_JPEGTABLES, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_C32_UINT8, FIELD_JPEGTABLES, FALSE, TRUE, "JPEGTables", NULL }, + { TIFFTAG_JPEGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL }, + { TIFFTAG_JPEGCOLORMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL }, + { TIFFTAG_JPEGTABLESMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL } +}; + +/* + * libjpeg interface layer. + * + * We use setjmp/longjmp to return control to libtiff + * when a fatal error is encountered within the JPEG + * library. We also direct libjpeg error and warning + * messages through the appropriate libtiff handlers. + */ + +/* + * Error handling routines (these replace corresponding + * IJG routines from jerror.c). These are used for both + * compression and decompression. + */ +static void +TIFFjpeg_error_exit(j_common_ptr cinfo) +{ + JPEGState *sp = (JPEGState *) cinfo; /* NB: cinfo assumed first */ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message) (cinfo, buffer); + TIFFErrorExt(sp->tif->tif_clientdata, "JPEGLib", "%s", buffer); /* display the error message */ + jpeg_abort(cinfo); /* clean up libjpeg state */ + LONGJMP(sp->exit_jmpbuf, 1); /* return to libtiff caller */ +} + +/* + * This routine is invoked only for warning messages, + * since error_exit does its own thing and trace_level + * is never set > 0. + */ +static void +TIFFjpeg_output_message(j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message) (cinfo, buffer); + TIFFWarningExt(((JPEGState *) cinfo)->tif->tif_clientdata, "JPEGLib", "%s", buffer); +} + +/* + * Interface routines. This layer of routines exists + * primarily to limit side-effects from using setjmp. + * Also, normal/error returns are converted into return + * values per libtiff practice. + */ +#define CALLJPEG(sp, fail, op) (SETJMP((sp)->exit_jmpbuf) ? (fail) : (op)) +#define CALLVJPEG(sp, op) CALLJPEG(sp, 0, ((op),1)) + +static int +TIFFjpeg_create_compress(JPEGState* sp) +{ + /* initialize JPEG error handling */ + sp->cinfo.c.err = jpeg_std_error(&sp->err); + sp->err.error_exit = TIFFjpeg_error_exit; + sp->err.output_message = TIFFjpeg_output_message; + + return CALLVJPEG(sp, jpeg_create_compress(&sp->cinfo.c)); +} + +static int +TIFFjpeg_create_decompress(JPEGState* sp) +{ + /* initialize JPEG error handling */ + sp->cinfo.d.err = jpeg_std_error(&sp->err); + sp->err.error_exit = TIFFjpeg_error_exit; + sp->err.output_message = TIFFjpeg_output_message; + + return CALLVJPEG(sp, jpeg_create_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_set_defaults(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_set_defaults(&sp->cinfo.c)); +} + +static int +TIFFjpeg_set_colorspace(JPEGState* sp, J_COLOR_SPACE colorspace) +{ + return CALLVJPEG(sp, jpeg_set_colorspace(&sp->cinfo.c, colorspace)); +} + +static int +TIFFjpeg_set_quality(JPEGState* sp, int quality, boolean force_baseline) +{ + return CALLVJPEG(sp, + jpeg_set_quality(&sp->cinfo.c, quality, force_baseline)); +} + +static int +TIFFjpeg_suppress_tables(JPEGState* sp, boolean suppress) +{ + return CALLVJPEG(sp, jpeg_suppress_tables(&sp->cinfo.c, suppress)); +} + +static int +TIFFjpeg_start_compress(JPEGState* sp, boolean write_all_tables) +{ + return CALLVJPEG(sp, + jpeg_start_compress(&sp->cinfo.c, write_all_tables)); +} + +static int +TIFFjpeg_write_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int num_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_write_scanlines(&sp->cinfo.c, + scanlines, (JDIMENSION) num_lines)); +} + +static int +TIFFjpeg_write_raw_data(JPEGState* sp, JSAMPIMAGE data, int num_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_write_raw_data(&sp->cinfo.c, + data, (JDIMENSION) num_lines)); +} + +static int +TIFFjpeg_finish_compress(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_finish_compress(&sp->cinfo.c)); +} + +static int +TIFFjpeg_write_tables(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_write_tables(&sp->cinfo.c)); +} + +static int +TIFFjpeg_read_header(JPEGState* sp, boolean require_image) +{ + return CALLJPEG(sp, -1, jpeg_read_header(&sp->cinfo.d, require_image)); +} + +static int +TIFFjpeg_start_decompress(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_start_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_read_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int max_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d, + scanlines, (JDIMENSION) max_lines)); +} + +static int +TIFFjpeg_read_raw_data(JPEGState* sp, JSAMPIMAGE data, int max_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_read_raw_data(&sp->cinfo.d, + data, (JDIMENSION) max_lines)); +} + +static int +TIFFjpeg_finish_decompress(JPEGState* sp) +{ + return CALLJPEG(sp, -1, (int) jpeg_finish_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_abort(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_abort(&sp->cinfo.comm)); +} + +static int +TIFFjpeg_destroy(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_destroy(&sp->cinfo.comm)); +} + +static JSAMPARRAY +TIFFjpeg_alloc_sarray(JPEGState* sp, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +{ + return CALLJPEG(sp, (JSAMPARRAY) NULL, + (*sp->cinfo.comm.mem->alloc_sarray) + (&sp->cinfo.comm, pool_id, samplesperrow, numrows)); +} + +/* + * JPEG library destination data manager. + * These routines direct compressed data from libjpeg into the + * libtiff output buffer. + */ + +static void +std_init_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata; + sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize; +} + +static boolean +std_empty_output_buffer(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + /* the entire buffer has been filled */ + tif->tif_rawcc = tif->tif_rawdatasize; + +#ifdef IPPJ_HUFF + /* + * The Intel IPP performance library does not necessarily fill up + * the whole output buffer on each pass, so only dump out the parts + * that have been filled. + * http://trac.osgeo.org/gdal/wiki/JpegIPP + */ + if ( sp->dest.free_in_buffer >= 0 ) { + tif->tif_rawcc = tif->tif_rawdatasize - sp->dest.free_in_buffer; + } +#endif + + TIFFFlushData1(tif); + sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata; + sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize; + + return (TRUE); +} + +static void +std_term_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + tif->tif_rawcp = (uint8*) sp->dest.next_output_byte; + tif->tif_rawcc = + tif->tif_rawdatasize - (tmsize_t) sp->dest.free_in_buffer; + /* NB: libtiff does the final buffer flush */ +} + +static void +TIFFjpeg_data_dest(JPEGState* sp, TIFF* tif) +{ + (void) tif; + sp->cinfo.c.dest = &sp->dest; + sp->dest.init_destination = std_init_destination; + sp->dest.empty_output_buffer = std_empty_output_buffer; + sp->dest.term_destination = std_term_destination; +} + +/* + * Alternate destination manager for outputting to JPEGTables field. + */ + +static void +tables_init_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + /* while building, jpegtables_length is allocated buffer size */ + sp->dest.next_output_byte = (JOCTET*) sp->jpegtables; + sp->dest.free_in_buffer = (size_t) sp->jpegtables_length; +} + +static boolean +tables_empty_output_buffer(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + void* newbuf; + + /* the entire buffer has been filled; enlarge it by 1000 bytes */ + newbuf = _TIFFrealloc((void*) sp->jpegtables, + (tmsize_t) (sp->jpegtables_length + 1000)); + if (newbuf == NULL) + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 100); + sp->dest.next_output_byte = (JOCTET*) newbuf + sp->jpegtables_length; + sp->dest.free_in_buffer = (size_t) 1000; + sp->jpegtables = newbuf; + sp->jpegtables_length += 1000; + return (TRUE); +} + +static void +tables_term_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + /* set tables length to number of bytes actually emitted */ + sp->jpegtables_length -= (uint32) sp->dest.free_in_buffer; +} + +static int +TIFFjpeg_tables_dest(JPEGState* sp, TIFF* tif) +{ + (void) tif; + /* + * Allocate a working buffer for building tables. + * Initial size is 1000 bytes, which is usually adequate. + */ + if (sp->jpegtables) + _TIFFfree(sp->jpegtables); + sp->jpegtables_length = 1000; + sp->jpegtables = (void*) _TIFFmalloc((tmsize_t) sp->jpegtables_length); + if (sp->jpegtables == NULL) { + sp->jpegtables_length = 0; + TIFFErrorExt(sp->tif->tif_clientdata, "TIFFjpeg_tables_dest", "No space for JPEGTables"); + return (0); + } + sp->cinfo.c.dest = &sp->dest; + sp->dest.init_destination = tables_init_destination; + sp->dest.empty_output_buffer = tables_empty_output_buffer; + sp->dest.term_destination = tables_term_destination; + return (1); +} + +/* + * JPEG library source data manager. + * These routines supply compressed data to libjpeg. + */ + +static void +std_init_source(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + sp->src.next_input_byte = (const JOCTET*) tif->tif_rawdata; + sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc; +} + +static boolean +std_fill_input_buffer(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState* ) cinfo; + static const JOCTET dummy_EOI[2] = { 0xFF, JPEG_EOI }; + +#ifdef IPPJ_HUFF + /* + * The Intel IPP performance library does not necessarily read the whole + * input buffer in one pass, so it is possible to get here with data + * yet to read. + * + * We just return without doing anything, until the entire buffer has + * been read. + * http://trac.osgeo.org/gdal/wiki/JpegIPP + */ + if( sp->src.bytes_in_buffer > 0 ) { + return (TRUE); + } +#endif + + /* + * Normally the whole strip/tile is read and so we don't need to do + * a fill. In the case of CHUNKY_STRIP_READ_SUPPORT we might not have + * all the data, but the rawdata is refreshed between scanlines and + * we push this into the io machinery in JPEGDecode(). + * http://trac.osgeo.org/gdal/ticket/3894 + */ + + WARNMS(cinfo, JWRN_JPEG_EOF); + /* insert a fake EOI marker */ + sp->src.next_input_byte = dummy_EOI; + sp->src.bytes_in_buffer = 2; + return (TRUE); +} + +static void +std_skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + JPEGState* sp = (JPEGState*) cinfo; + + if (num_bytes > 0) { + if ((size_t)num_bytes > sp->src.bytes_in_buffer) { + /* oops, buffer overrun */ + (void) std_fill_input_buffer(cinfo); + } else { + sp->src.next_input_byte += (size_t) num_bytes; + sp->src.bytes_in_buffer -= (size_t) num_bytes; + } + } +} + +static void +std_term_source(j_decompress_ptr cinfo) +{ + /* No work necessary here */ + (void) cinfo; +} + +static void +TIFFjpeg_data_src(JPEGState* sp, TIFF* tif) +{ + (void) tif; + sp->cinfo.d.src = &sp->src; + sp->src.init_source = std_init_source; + sp->src.fill_input_buffer = std_fill_input_buffer; + sp->src.skip_input_data = std_skip_input_data; + sp->src.resync_to_restart = jpeg_resync_to_restart; + sp->src.term_source = std_term_source; + sp->src.bytes_in_buffer = 0; /* for safety */ + sp->src.next_input_byte = NULL; +} + +/* + * Alternate source manager for reading from JPEGTables. + * We can share all the code except for the init routine. + */ + +static void +tables_init_source(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + sp->src.next_input_byte = (const JOCTET*) sp->jpegtables; + sp->src.bytes_in_buffer = (size_t) sp->jpegtables_length; +} + +static void +TIFFjpeg_tables_src(JPEGState* sp, TIFF* tif) +{ + TIFFjpeg_data_src(sp, tif); + sp->src.init_source = tables_init_source; +} + +/* + * Allocate downsampled-data buffers needed for downsampled I/O. + * We use values computed in jpeg_start_compress or jpeg_start_decompress. + * We use libjpeg's allocator so that buffers will be released automatically + * when done with strip/tile. + * This is also a handy place to compute samplesperclump, bytesperline. + */ +static int +alloc_downsampled_buffers(TIFF* tif, jpeg_component_info* comp_info, + int num_components) +{ + JPEGState* sp = JState(tif); + int ci; + jpeg_component_info* compptr; + JSAMPARRAY buf; + int samples_per_clump = 0; + + for (ci = 0, compptr = comp_info; ci < num_components; + ci++, compptr++) { + samples_per_clump += compptr->h_samp_factor * + compptr->v_samp_factor; + buf = TIFFjpeg_alloc_sarray(sp, JPOOL_IMAGE, + compptr->width_in_blocks * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor*DCTSIZE)); + if (buf == NULL) + return (0); + sp->ds_buffer[ci] = buf; + } + sp->samplesperclump = samples_per_clump; + return (1); +} + + +/* + * JPEG Decoding. + */ + +#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING + +#define JPEG_MARKER_SOF0 0xC0 +#define JPEG_MARKER_SOF1 0xC1 +#define JPEG_MARKER_SOF3 0xC3 +#define JPEG_MARKER_DHT 0xC4 +#define JPEG_MARKER_SOI 0xD8 +#define JPEG_MARKER_SOS 0xDA +#define JPEG_MARKER_DQT 0xDB +#define JPEG_MARKER_DRI 0xDD +#define JPEG_MARKER_APP0 0xE0 +#define JPEG_MARKER_COM 0xFE +struct JPEGFixupTagsSubsamplingData +{ + TIFF* tif; + void* buffer; + uint32 buffersize; + uint8* buffercurrentbyte; + uint32 bufferbytesleft; + uint64 fileoffset; + uint64 filebytesleft; + uint8 filepositioned; +}; +static void JPEGFixupTagsSubsampling(TIFF* tif); +static int JPEGFixupTagsSubsamplingSec(struct JPEGFixupTagsSubsamplingData* data); +static int JPEGFixupTagsSubsamplingReadByte(struct JPEGFixupTagsSubsamplingData* data, uint8* result); +static int JPEGFixupTagsSubsamplingReadWord(struct JPEGFixupTagsSubsamplingData* data, uint16* result); +static void JPEGFixupTagsSubsamplingSkip(struct JPEGFixupTagsSubsamplingData* data, uint16 skiplength); + +#endif + +static int +JPEGFixupTags(TIFF* tif) +{ +#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING + if ((tif->tif_dir.td_photometric==PHOTOMETRIC_YCBCR)&& + (tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG)&& + (tif->tif_dir.td_samplesperpixel==3)) + JPEGFixupTagsSubsampling(tif); +#endif + + return(1); +} + +#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING + +static void +JPEGFixupTagsSubsampling(TIFF* tif) +{ + /* + * Some JPEG-in-TIFF produces do not emit the YCBCRSUBSAMPLING values in + * the TIFF tags, but still use non-default (2,2) values within the jpeg + * data stream itself. In order for TIFF applications to work properly + * - for instance to get the strip buffer size right - it is imperative + * that the subsampling be available before we start reading the image + * data normally. This function will attempt to analyze the first strip in + * order to get the sampling values from the jpeg data stream. + * + * Note that JPEGPreDeocode() will produce a fairly loud warning when the + * discovered sampling does not match the default sampling (2,2) or whatever + * was actually in the tiff tags. + * + * See the bug in bugzilla for details: + * + * http://bugzilla.remotesensing.org/show_bug.cgi?id=168 + * + * Frank Warmerdam, July 2002 + * Joris Van Damme, May 2007 + */ + static const char module[] = "JPEGFixupTagsSubsampling"; + struct JPEGFixupTagsSubsamplingData m; + + _TIFFFillStriles( tif ); + + if( tif->tif_dir.td_stripbytecount == NULL + || tif->tif_dir.td_stripbytecount[0] == 0 ) + { + /* Do not even try to check if the first strip/tile does not + yet exist, as occurs when GDAL has created a new NULL file + for instance. */ + return; + } + + m.tif=tif; + m.buffersize=2048; + m.buffer=_TIFFmalloc(m.buffersize); + if (m.buffer==NULL) + { + TIFFWarningExt(tif->tif_clientdata,module, + "Unable to allocate memory for auto-correcting of subsampling values; auto-correcting skipped"); + return; + } + m.buffercurrentbyte=NULL; + m.bufferbytesleft=0; + m.fileoffset=tif->tif_dir.td_stripoffset[0]; + m.filepositioned=0; + m.filebytesleft=tif->tif_dir.td_stripbytecount[0]; + if (!JPEGFixupTagsSubsamplingSec(&m)) + TIFFWarningExt(tif->tif_clientdata,module, + "Unable to auto-correct subsampling values, likely corrupt JPEG compressed data in first strip/tile; auto-correcting skipped"); + _TIFFfree(m.buffer); +} + +static int +JPEGFixupTagsSubsamplingSec(struct JPEGFixupTagsSubsamplingData* data) +{ + static const char module[] = "JPEGFixupTagsSubsamplingSec"; + uint8 m; + while (1) + { + while (1) + { + if (!JPEGFixupTagsSubsamplingReadByte(data,&m)) + return(0); + if (m==255) + break; + } + while (1) + { + if (!JPEGFixupTagsSubsamplingReadByte(data,&m)) + return(0); + if (m!=255) + break; + } + switch (m) + { + case JPEG_MARKER_SOI: + /* this type of marker has no data and should be skipped */ + break; + case JPEG_MARKER_COM: + case JPEG_MARKER_APP0: + case JPEG_MARKER_APP0+1: + case JPEG_MARKER_APP0+2: + case JPEG_MARKER_APP0+3: + case JPEG_MARKER_APP0+4: + case JPEG_MARKER_APP0+5: + case JPEG_MARKER_APP0+6: + case JPEG_MARKER_APP0+7: + case JPEG_MARKER_APP0+8: + case JPEG_MARKER_APP0+9: + case JPEG_MARKER_APP0+10: + case JPEG_MARKER_APP0+11: + case JPEG_MARKER_APP0+12: + case JPEG_MARKER_APP0+13: + case JPEG_MARKER_APP0+14: + case JPEG_MARKER_APP0+15: + case JPEG_MARKER_DQT: + case JPEG_MARKER_SOS: + case JPEG_MARKER_DHT: + case JPEG_MARKER_DRI: + /* this type of marker has data, but it has no use to us and should be skipped */ + { + uint16 n; + if (!JPEGFixupTagsSubsamplingReadWord(data,&n)) + return(0); + if (n<2) + return(0); + n-=2; + if (n>0) + JPEGFixupTagsSubsamplingSkip(data,n); + } + break; + case JPEG_MARKER_SOF0: + case JPEG_MARKER_SOF1: + /* this marker contains the subsampling factors we're scanning for */ + { + uint16 n; + uint16 o; + uint8 p; + uint8 ph,pv; + if (!JPEGFixupTagsSubsamplingReadWord(data,&n)) + return(0); + if (n!=8+data->tif->tif_dir.td_samplesperpixel*3) + return(0); + JPEGFixupTagsSubsamplingSkip(data,7); + if (!JPEGFixupTagsSubsamplingReadByte(data,&p)) + return(0); + ph=(p>>4); + pv=(p&15); + JPEGFixupTagsSubsamplingSkip(data,1); + for (o=1; otif->tif_dir.td_samplesperpixel; o++) + { + JPEGFixupTagsSubsamplingSkip(data,1); + if (!JPEGFixupTagsSubsamplingReadByte(data,&p)) + return(0); + if (p!=0x11) + { + TIFFWarningExt(data->tif->tif_clientdata,module, + "Subsampling values inside JPEG compressed data have no TIFF equivalent, auto-correction of TIFF subsampling values failed"); + return(1); + } + JPEGFixupTagsSubsamplingSkip(data,1); + } + if (((ph!=1)&&(ph!=2)&&(ph!=4))||((pv!=1)&&(pv!=2)&&(pv!=4))) + { + TIFFWarningExt(data->tif->tif_clientdata,module, + "Subsampling values inside JPEG compressed data have no TIFF equivalent, auto-correction of TIFF subsampling values failed"); + return(1); + } + if ((ph!=data->tif->tif_dir.td_ycbcrsubsampling[0])||(pv!=data->tif->tif_dir.td_ycbcrsubsampling[1])) + { + TIFFWarningExt(data->tif->tif_clientdata,module, + "Auto-corrected former TIFF subsampling values [%d,%d] to match subsampling values inside JPEG compressed data [%d,%d]", + (int)data->tif->tif_dir.td_ycbcrsubsampling[0], + (int)data->tif->tif_dir.td_ycbcrsubsampling[1], + (int)ph,(int)pv); + data->tif->tif_dir.td_ycbcrsubsampling[0]=ph; + data->tif->tif_dir.td_ycbcrsubsampling[1]=pv; + } + } + return(1); + default: + return(0); + } + } +} + +static int +JPEGFixupTagsSubsamplingReadByte(struct JPEGFixupTagsSubsamplingData* data, uint8* result) +{ + if (data->bufferbytesleft==0) + { + uint32 m; + if (data->filebytesleft==0) + return(0); + if (!data->filepositioned) + { + TIFFSeekFile(data->tif,data->fileoffset,SEEK_SET); + data->filepositioned=1; + } + m=data->buffersize; + if ((uint64)m>data->filebytesleft) + m=(uint32)data->filebytesleft; + assert(m<0x80000000UL); + if (TIFFReadFile(data->tif,data->buffer,(tmsize_t)m)!=(tmsize_t)m) + return(0); + data->buffercurrentbyte=data->buffer; + data->bufferbytesleft=m; + data->fileoffset+=m; + data->filebytesleft-=m; + } + *result=*data->buffercurrentbyte; + data->buffercurrentbyte++; + data->bufferbytesleft--; + return(1); +} + +static int +JPEGFixupTagsSubsamplingReadWord(struct JPEGFixupTagsSubsamplingData* data, uint16* result) +{ + uint8 ma; + uint8 mb; + if (!JPEGFixupTagsSubsamplingReadByte(data,&ma)) + return(0); + if (!JPEGFixupTagsSubsamplingReadByte(data,&mb)) + return(0); + *result=(ma<<8)|mb; + return(1); +} + +static void +JPEGFixupTagsSubsamplingSkip(struct JPEGFixupTagsSubsamplingData* data, uint16 skiplength) +{ + if ((uint32)skiplength<=data->bufferbytesleft) + { + data->buffercurrentbyte+=skiplength; + data->bufferbytesleft-=skiplength; + } + else + { + uint16 m; + m=skiplength-data->bufferbytesleft; + if (m<=data->filebytesleft) + { + data->bufferbytesleft=0; + data->fileoffset+=m; + data->filebytesleft-=m; + data->filepositioned=0; + } + else + { + data->bufferbytesleft=0; + data->filebytesleft=0; + } + } +} + +#endif + + +static int +JPEGSetupDecode(TIFF* tif) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + +#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFInitJPEG) + if( tif->tif_dir.td_bitspersample == 12 ) + return TIFFReInitJPEG_12( tif, COMPRESSION_JPEG, 0 ); +#endif + + JPEGInitializeLibJPEG( tif, TRUE ); + + assert(sp != NULL); + assert(sp->cinfo.comm.is_decompressor); + + /* Read JPEGTables if it is present */ + if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) { + TIFFjpeg_tables_src(sp, tif); + if(TIFFjpeg_read_header(sp,FALSE) != JPEG_HEADER_TABLES_ONLY) { + TIFFErrorExt(tif->tif_clientdata, "JPEGSetupDecode", "Bogus JPEGTables field"); + return (0); + } + } + + /* Grab parameters that are same for all strips/tiles */ + sp->photometric = td->td_photometric; + switch (sp->photometric) { + case PHOTOMETRIC_YCBCR: + sp->h_sampling = td->td_ycbcrsubsampling[0]; + sp->v_sampling = td->td_ycbcrsubsampling[1]; + break; + default: + /* TIFF 6.0 forbids subsampling of all other color spaces */ + sp->h_sampling = 1; + sp->v_sampling = 1; + break; + } + + /* Set up for reading normal data */ + TIFFjpeg_data_src(sp, tif); + tif->tif_postdecode = _TIFFNoPostDecode; /* override byte swapping */ + return (1); +} + +/* + * Set up for decoding a strip or tile. + */ +static int +JPEGPreDecode(TIFF* tif, uint16 s) +{ + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGPreDecode"; + uint32 segment_width, segment_height; + int downsampled_output; + int ci; + + assert(sp != NULL); + + if (sp->cinfo.comm.is_decompressor == 0) + { + tif->tif_setupdecode( tif ); + } + + assert(sp->cinfo.comm.is_decompressor); + /* + * Reset decoder state from any previous strip/tile, + * in case application didn't read the whole strip. + */ + if (!TIFFjpeg_abort(sp)) + return (0); + /* + * Read the header for this strip/tile. + */ + + if (TIFFjpeg_read_header(sp, TRUE) != JPEG_HEADER_OK) + return (0); + + tif->tif_rawcp = (uint8*) sp->src.next_input_byte; + tif->tif_rawcc = sp->src.bytes_in_buffer; + + /* + * Check image parameters and set decompression parameters. + */ + segment_width = td->td_imagewidth; + segment_height = td->td_imagelength - tif->tif_row; + if (isTiled(tif)) { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + sp->bytesperline = TIFFTileRowSize(tif); + } else { + if (segment_height > td->td_rowsperstrip) + segment_height = td->td_rowsperstrip; + sp->bytesperline = TIFFScanlineSize(tif); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) { + /* + * For PC 2, scale down the expected strip/tile size + * to match a downsampled component + */ + segment_width = TIFFhowmany_32(segment_width, sp->h_sampling); + segment_height = TIFFhowmany_32(segment_height, sp->v_sampling); + } + if (sp->cinfo.d.image_width < segment_width || + sp->cinfo.d.image_height < segment_height) { + TIFFWarningExt(tif->tif_clientdata, module, + "Improper JPEG strip/tile size, " + "expected %dx%d, got %dx%d", + segment_width, segment_height, + sp->cinfo.d.image_width, + sp->cinfo.d.image_height); + } + if (sp->cinfo.d.image_width > segment_width || + sp->cinfo.d.image_height > segment_height) { + /* + * This case could be dangerous, if the strip or tile size has + * been reported as less than the amount of data jpeg will + * return, some potential security issues arise. Catch this + * case and error out. + */ + TIFFErrorExt(tif->tif_clientdata, module, + "JPEG strip/tile size exceeds expected dimensions," + " expected %dx%d, got %dx%d", + segment_width, segment_height, + sp->cinfo.d.image_width, sp->cinfo.d.image_height); + return (0); + } + if (sp->cinfo.d.num_components != + (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1)) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG component count"); + return (0); + } +#ifdef JPEG_LIB_MK1 + if (12 != td->td_bitspersample && 8 != td->td_bitspersample) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG data precision"); + return (0); + } + sp->cinfo.d.data_precision = td->td_bitspersample; + sp->cinfo.d.bits_in_jsample = td->td_bitspersample; +#else + if (sp->cinfo.d.data_precision != td->td_bitspersample) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG data precision"); + return (0); + } +#endif + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + /* Component 0 should have expected sampling factors */ + if (sp->cinfo.d.comp_info[0].h_samp_factor != sp->h_sampling || + sp->cinfo.d.comp_info[0].v_samp_factor != sp->v_sampling) { + TIFFErrorExt(tif->tif_clientdata, module, + "Improper JPEG sampling factors %d,%d\n" + "Apparently should be %d,%d.", + sp->cinfo.d.comp_info[0].h_samp_factor, + sp->cinfo.d.comp_info[0].v_samp_factor, + sp->h_sampling, sp->v_sampling); + return (0); + } + /* Rest should have sampling factors 1,1 */ + for (ci = 1; ci < sp->cinfo.d.num_components; ci++) { + if (sp->cinfo.d.comp_info[ci].h_samp_factor != 1 || + sp->cinfo.d.comp_info[ci].v_samp_factor != 1) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors"); + return (0); + } + } + } else { + /* PC 2's single component should have sampling factors 1,1 */ + if (sp->cinfo.d.comp_info[0].h_samp_factor != 1 || + sp->cinfo.d.comp_info[0].v_samp_factor != 1) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors"); + return (0); + } + } + downsampled_output = FALSE; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + sp->photometric == PHOTOMETRIC_YCBCR && + sp->jpegcolormode == JPEGCOLORMODE_RGB) { + /* Convert YCbCr to RGB */ + sp->cinfo.d.jpeg_color_space = JCS_YCbCr; + sp->cinfo.d.out_color_space = JCS_RGB; + } else { + /* Suppress colorspace handling */ + sp->cinfo.d.jpeg_color_space = JCS_UNKNOWN; + sp->cinfo.d.out_color_space = JCS_UNKNOWN; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + (sp->h_sampling != 1 || sp->v_sampling != 1)) + downsampled_output = TRUE; + /* XXX what about up-sampling? */ + } + if (downsampled_output) { + /* Need to use raw-data interface to libjpeg */ + sp->cinfo.d.raw_data_out = TRUE; +#if JPEG_LIB_VERSION >= 70 + sp->cinfo.d.do_fancy_upsampling = FALSE; +#endif /* JPEG_LIB_VERSION >= 70 */ + tif->tif_decoderow = DecodeRowError; + tif->tif_decodestrip = JPEGDecodeRaw; + tif->tif_decodetile = JPEGDecodeRaw; + } else { + /* Use normal interface to libjpeg */ + sp->cinfo.d.raw_data_out = FALSE; + tif->tif_decoderow = JPEGDecode; + tif->tif_decodestrip = JPEGDecode; + tif->tif_decodetile = JPEGDecode; + } + /* Start JPEG decompressor */ + if (!TIFFjpeg_start_decompress(sp)) + return (0); + /* Allocate downsampled-data buffers if needed */ + if (downsampled_output) { + if (!alloc_downsampled_buffers(tif, sp->cinfo.d.comp_info, + sp->cinfo.d.num_components)) + return (0); + sp->scancount = DCTSIZE; /* mark buffer empty */ + } + return (1); +} + +/* + * Decode a chunk of pixels. + * "Standard" case: returned data is not downsampled. + */ +/*ARGSUSED*/ static int +JPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) +{ + JPEGState *sp = JState(tif); + tmsize_t nrows; + (void) s; + + /* + ** Update available information, buffer may have been refilled + ** between decode requests + */ + sp->src.next_input_byte = (const JOCTET*) tif->tif_rawcp; + sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc; + + if( sp->bytesperline == 0 ) + return 0; + + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline not read"); + + if( nrows > (tmsize_t) sp->cinfo.d.image_height ) + nrows = sp->cinfo.d.image_height; + + /* data is expected to be read in multiples of a scanline */ + if (nrows) + { + JSAMPROW line_work_buf = NULL; + + /* + * For 6B, only use temporary buffer for 12 bit imagery. + * For Mk1 always use it. + */ +#if !defined(JPEG_LIB_MK1) + if( sp->cinfo.d.data_precision == 12 ) +#endif + { + line_work_buf = (JSAMPROW) + _TIFFmalloc(sizeof(short) * sp->cinfo.d.output_width + * sp->cinfo.d.num_components ); + } + + do { + if( line_work_buf != NULL ) + { + /* + * In the MK1 case, we aways read into a 16bit buffer, and then + * pack down to 12bit or 8bit. In 6B case we only read into 16 + * bit buffer for 12bit data, which we need to repack. + */ + if (TIFFjpeg_read_scanlines(sp, &line_work_buf, 1) != 1) + return (0); + + if( sp->cinfo.d.data_precision == 12 ) + { + int value_pairs = (sp->cinfo.d.output_width + * sp->cinfo.d.num_components) / 2; + int iPair; + + for( iPair = 0; iPair < value_pairs; iPair++ ) + { + unsigned char *out_ptr = + ((unsigned char *) buf) + iPair * 3; + JSAMPLE *in_ptr = line_work_buf + iPair * 2; + + out_ptr[0] = (in_ptr[0] & 0xff0) >> 4; + out_ptr[1] = ((in_ptr[0] & 0xf) << 4) + | ((in_ptr[1] & 0xf00) >> 8); + out_ptr[2] = ((in_ptr[1] & 0xff) >> 0); + } + } + else if( sp->cinfo.d.data_precision == 8 ) + { + int value_count = (sp->cinfo.d.output_width + * sp->cinfo.d.num_components); + int iValue; + + for( iValue = 0; iValue < value_count; iValue++ ) + { + ((unsigned char *) buf)[iValue] = + line_work_buf[iValue] & 0xff; + } + } + } + else + { + /* + * In the libjpeg6b 8bit case. We read directly into the + * TIFF buffer. + */ + JSAMPROW bufptr = (JSAMPROW)buf; + + if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1) + return (0); + } + + ++tif->tif_row; + buf += sp->bytesperline; + cc -= sp->bytesperline; + } while (--nrows > 0); + + if( line_work_buf != NULL ) + _TIFFfree( line_work_buf ); + } + + /* Update information on consumed data */ + tif->tif_rawcp = (uint8*) sp->src.next_input_byte; + tif->tif_rawcc = sp->src.bytes_in_buffer; + + /* Close down the decompressor if we've finished the strip or tile. */ + return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height + || TIFFjpeg_finish_decompress(sp); +} + +/*ARGSUSED*/ static int +DecodeRowError(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) + +{ + (void) buf; + (void) cc; + (void) s; + + TIFFErrorExt(tif->tif_clientdata, "TIFFReadScanline", + "scanline oriented access is not supported for downsampled JPEG compressed images, consider enabling TIFF_JPEGCOLORMODE as JPEGCOLORMODE_RGB." ); + return 0; +} + +/* + * Decode a chunk of pixels. + * Returned data is downsampled per sampling factors. + */ +/*ARGSUSED*/ static int +JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) +{ + JPEGState *sp = JState(tif); + tmsize_t nrows; + (void) s; + + /* data is expected to be read in multiples of a scanline */ + if ( (nrows = sp->cinfo.d.image_height) ) { + + /* Cb,Cr both have sampling factors 1, so this is correct */ + JDIMENSION clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width; + int samples_per_clump = sp->samplesperclump; + +#if defined(JPEG_LIB_MK1_OR_12BIT) + unsigned short* tmpbuf = _TIFFmalloc(sizeof(unsigned short) * + sp->cinfo.d.output_width * + sp->cinfo.d.num_components); + if(tmpbuf==NULL) { + TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw", + "Out of memory"); + return 0; + } +#endif + + do { + jpeg_component_info *compptr; + int ci, clumpoffset; + + if( cc < sp->bytesperline ) { + TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw", + "application buffer not large enough for all data."); + return 0; + } + + /* Reload downsampled-data buffer if needed */ + if (sp->scancount >= DCTSIZE) { + int n = sp->cinfo.d.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_read_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + sp->scancount = 0; + } + /* + * Fastest way to unseparate data is to make one pass + * over the scanline for each row of each component. + */ + clumpoffset = 0; /* first sample in clump */ + for (ci = 0, compptr = sp->cinfo.d.comp_info; + ci < sp->cinfo.d.num_components; + ci++, compptr++) { + int hsamp = compptr->h_samp_factor; + int vsamp = compptr->v_samp_factor; + int ypos; + + for (ypos = 0; ypos < vsamp; ypos++) { + JSAMPLE *inptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; + JDIMENSION nclump; +#if defined(JPEG_LIB_MK1_OR_12BIT) + JSAMPLE *outptr = (JSAMPLE*)tmpbuf + clumpoffset; +#else + JSAMPLE *outptr = (JSAMPLE*)buf + clumpoffset; + if (cc < (tmsize_t) (clumpoffset + samples_per_clump*(clumps_per_line-1) + hsamp)) { + TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw", + "application buffer not large enough for all data, possible subsampling issue"); + return 0; + } +#endif + + if (hsamp == 1) { + /* fast path for at least Cb and Cr */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + outptr[0] = *inptr++; + outptr += samples_per_clump; + } + } else { + int xpos; + + /* general case */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + for (xpos = 0; xpos < hsamp; xpos++) + outptr[xpos] = *inptr++; + outptr += samples_per_clump; + } + } + clumpoffset += hsamp; + } + } + +#if defined(JPEG_LIB_MK1_OR_12BIT) + { + if (sp->cinfo.d.data_precision == 8) + { + int i=0; + int len = sp->cinfo.d.output_width * sp->cinfo.d.num_components; + for (i=0; icinfo.d.output_width + * sp->cinfo.d.num_components) / 2; + int iPair; + for( iPair = 0; iPair < value_pairs; iPair++ ) + { + unsigned char *out_ptr = ((unsigned char *) buf) + iPair * 3; + JSAMPLE *in_ptr = (JSAMPLE *) (tmpbuf + iPair * 2); + out_ptr[0] = (in_ptr[0] & 0xff0) >> 4; + out_ptr[1] = ((in_ptr[0] & 0xf) << 4) + | ((in_ptr[1] & 0xf00) >> 8); + out_ptr[2] = ((in_ptr[1] & 0xff) >> 0); + } + } + } +#endif + + sp->scancount ++; + tif->tif_row += sp->v_sampling; + + buf += sp->bytesperline; + cc -= sp->bytesperline; + + nrows -= sp->v_sampling; + } while (nrows > 0); + +#if defined(JPEG_LIB_MK1_OR_12BIT) + _TIFFfree(tmpbuf); +#endif + + } + + /* Close down the decompressor if done. */ + return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height + || TIFFjpeg_finish_decompress(sp); +} + + +/* + * JPEG Encoding. + */ + +static void +unsuppress_quant_table (JPEGState* sp, int tblno) +{ + JQUANT_TBL* qtbl; + + if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL) + qtbl->sent_table = FALSE; +} + +static void +unsuppress_huff_table (JPEGState* sp, int tblno) +{ + JHUFF_TBL* htbl; + + if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = FALSE; + if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = FALSE; +} + +static int +prepare_JPEGTables(TIFF* tif) +{ + JPEGState* sp = JState(tif); + + /* Initialize quant tables for current quality setting */ + if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) + return (0); + /* Mark only the tables we want for output */ + /* NB: chrominance tables are currently used only with YCbCr */ + if (!TIFFjpeg_suppress_tables(sp, TRUE)) + return (0); + if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) { + unsuppress_quant_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_quant_table(sp, 1); + } + if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) { + unsuppress_huff_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_huff_table(sp, 1); + } + /* Direct libjpeg output into jpegtables */ + if (!TIFFjpeg_tables_dest(sp, tif)) + return (0); + /* Emit tables-only datastream */ + if (!TIFFjpeg_write_tables(sp)) + return (0); + + return (1); +} + +static int +JPEGSetupEncode(TIFF* tif) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGSetupEncode"; + +#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFInitJPEG) + if( tif->tif_dir.td_bitspersample == 12 ) + return TIFFReInitJPEG_12( tif, COMPRESSION_JPEG, 1 ); +#endif + + JPEGInitializeLibJPEG( tif, FALSE ); + + assert(sp != NULL); + assert(!sp->cinfo.comm.is_decompressor); + + /* + * Initialize all JPEG parameters to default values. + * Note that jpeg_set_defaults needs legal values for + * in_color_space and input_components. + */ + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + sp->cinfo.c.input_components = 1; + if (!TIFFjpeg_set_defaults(sp)) + return (0); + /* Set per-file parameters */ + sp->photometric = td->td_photometric; + switch (sp->photometric) { + case PHOTOMETRIC_YCBCR: + sp->h_sampling = td->td_ycbcrsubsampling[0]; + sp->v_sampling = td->td_ycbcrsubsampling[1]; + /* + * A ReferenceBlackWhite field *must* be present since the + * default value is inappropriate for YCbCr. Fill in the + * proper value if application didn't set it. + */ + { + float *ref; + if (!TIFFGetField(tif, TIFFTAG_REFERENCEBLACKWHITE, + &ref)) { + float refbw[6]; + long top = 1L << td->td_bitspersample; + refbw[0] = 0; + refbw[1] = (float)(top-1L); + refbw[2] = (float)(top>>1); + refbw[3] = refbw[1]; + refbw[4] = refbw[2]; + refbw[5] = refbw[1]; + TIFFSetField(tif, TIFFTAG_REFERENCEBLACKWHITE, + refbw); + } + } + break; + case PHOTOMETRIC_PALETTE: /* disallowed by Tech Note */ + case PHOTOMETRIC_MASK: + TIFFErrorExt(tif->tif_clientdata, module, + "PhotometricInterpretation %d not allowed for JPEG", + (int) sp->photometric); + return (0); + default: + /* TIFF 6.0 forbids subsampling of all other color spaces */ + sp->h_sampling = 1; + sp->v_sampling = 1; + break; + } + + /* Verify miscellaneous parameters */ + + /* + * This would need work if libtiff ever supports different + * depths for different components, or if libjpeg ever supports + * run-time selection of depth. Neither is imminent. + */ +#ifdef JPEG_LIB_MK1 + /* BITS_IN_JSAMPLE now permits 8 and 12 --- dgilbert */ + if (td->td_bitspersample != 8 && td->td_bitspersample != 12) +#else + if (td->td_bitspersample != BITS_IN_JSAMPLE ) +#endif + { + TIFFErrorExt(tif->tif_clientdata, module, "BitsPerSample %d not allowed for JPEG", + (int) td->td_bitspersample); + return (0); + } + sp->cinfo.c.data_precision = td->td_bitspersample; +#ifdef JPEG_LIB_MK1 + sp->cinfo.c.bits_in_jsample = td->td_bitspersample; +#endif + if (isTiled(tif)) { + if ((td->td_tilelength % (sp->v_sampling * DCTSIZE)) != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "JPEG tile height must be multiple of %d", + sp->v_sampling * DCTSIZE); + return (0); + } + if ((td->td_tilewidth % (sp->h_sampling * DCTSIZE)) != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "JPEG tile width must be multiple of %d", + sp->h_sampling * DCTSIZE); + return (0); + } + } else { + if (td->td_rowsperstrip < td->td_imagelength && + (td->td_rowsperstrip % (sp->v_sampling * DCTSIZE)) != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "RowsPerStrip must be multiple of %d for JPEG", + sp->v_sampling * DCTSIZE); + return (0); + } + } + + /* Create a JPEGTables field if appropriate */ + if (sp->jpegtablesmode & (JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF)) { + if( sp->jpegtables == NULL + || memcmp(sp->jpegtables,"\0\0\0\0\0\0\0\0\0",8) == 0 ) + { + if (!prepare_JPEGTables(tif)) + return (0); + /* Mark the field present */ + /* Can't use TIFFSetField since BEENWRITING is already set! */ + tif->tif_flags |= TIFF_DIRTYDIRECT; + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); + } + } else { + /* We do not support application-supplied JPEGTables, */ + /* so mark the field not present */ + TIFFClrFieldBit(tif, FIELD_JPEGTABLES); + } + + /* Direct libjpeg output to libtiff's output buffer */ + TIFFjpeg_data_dest(sp, tif); + + return (1); +} + +/* + * Set encoding state at the start of a strip or tile. + */ +static int +JPEGPreEncode(TIFF* tif, uint16 s) +{ + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGPreEncode"; + uint32 segment_width, segment_height; + int downsampled_input; + + assert(sp != NULL); + + if (sp->cinfo.comm.is_decompressor == 1) + { + tif->tif_setupencode( tif ); + } + + assert(!sp->cinfo.comm.is_decompressor); + /* + * Set encoding parameters for this strip/tile. + */ + if (isTiled(tif)) { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + sp->bytesperline = TIFFTileRowSize(tif); + } else { + segment_width = td->td_imagewidth; + segment_height = td->td_imagelength - tif->tif_row; + if (segment_height > td->td_rowsperstrip) + segment_height = td->td_rowsperstrip; + sp->bytesperline = TIFFScanlineSize(tif); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) { + /* for PC 2, scale down the strip/tile size + * to match a downsampled component + */ + segment_width = TIFFhowmany_32(segment_width, sp->h_sampling); + segment_height = TIFFhowmany_32(segment_height, sp->v_sampling); + } + if (segment_width > 65535 || segment_height > 65535) { + TIFFErrorExt(tif->tif_clientdata, module, "Strip/tile too large for JPEG"); + return (0); + } + sp->cinfo.c.image_width = segment_width; + sp->cinfo.c.image_height = segment_height; + downsampled_input = FALSE; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + sp->cinfo.c.input_components = td->td_samplesperpixel; + if (sp->photometric == PHOTOMETRIC_YCBCR) { + if (sp->jpegcolormode == JPEGCOLORMODE_RGB) { + sp->cinfo.c.in_color_space = JCS_RGB; + } else { + sp->cinfo.c.in_color_space = JCS_YCbCr; + if (sp->h_sampling != 1 || sp->v_sampling != 1) + downsampled_input = TRUE; + } + if (!TIFFjpeg_set_colorspace(sp, JCS_YCbCr)) + return (0); + /* + * Set Y sampling factors; + * we assume jpeg_set_colorspace() set the rest to 1 + */ + sp->cinfo.c.comp_info[0].h_samp_factor = sp->h_sampling; + sp->cinfo.c.comp_info[0].v_samp_factor = sp->v_sampling; + } else { + if ((td->td_photometric == PHOTOMETRIC_MINISWHITE || td->td_photometric == PHOTOMETRIC_MINISBLACK) && td->td_samplesperpixel == 1) + sp->cinfo.c.in_color_space = JCS_GRAYSCALE; + else if (td->td_photometric == PHOTOMETRIC_RGB && td->td_samplesperpixel == 3) + sp->cinfo.c.in_color_space = JCS_RGB; + else if (td->td_photometric == PHOTOMETRIC_SEPARATED && td->td_samplesperpixel == 4) + sp->cinfo.c.in_color_space = JCS_CMYK; + else + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + if (!TIFFjpeg_set_colorspace(sp, sp->cinfo.c.in_color_space)) + return (0); + /* jpeg_set_colorspace set all sampling factors to 1 */ + } + } else { + sp->cinfo.c.input_components = 1; + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) + return (0); + sp->cinfo.c.comp_info[0].component_id = s; + /* jpeg_set_colorspace() set sampling factors to 1 */ + if (sp->photometric == PHOTOMETRIC_YCBCR && s > 0) { + sp->cinfo.c.comp_info[0].quant_tbl_no = 1; + sp->cinfo.c.comp_info[0].dc_tbl_no = 1; + sp->cinfo.c.comp_info[0].ac_tbl_no = 1; + } + } + /* ensure libjpeg won't write any extraneous markers */ + sp->cinfo.c.write_JFIF_header = FALSE; + sp->cinfo.c.write_Adobe_marker = FALSE; + /* set up table handling correctly */ + if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) + return (0); + if (! (sp->jpegtablesmode & JPEGTABLESMODE_QUANT)) { + unsuppress_quant_table(sp, 0); + unsuppress_quant_table(sp, 1); + } + if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) + sp->cinfo.c.optimize_coding = FALSE; + else + sp->cinfo.c.optimize_coding = TRUE; + if (downsampled_input) { + /* Need to use raw-data interface to libjpeg */ + sp->cinfo.c.raw_data_in = TRUE; + tif->tif_encoderow = JPEGEncodeRaw; + tif->tif_encodestrip = JPEGEncodeRaw; + tif->tif_encodetile = JPEGEncodeRaw; + } else { + /* Use normal interface to libjpeg */ + sp->cinfo.c.raw_data_in = FALSE; + tif->tif_encoderow = JPEGEncode; + tif->tif_encodestrip = JPEGEncode; + tif->tif_encodetile = JPEGEncode; + } + /* Start JPEG compressor */ + if (!TIFFjpeg_start_compress(sp, FALSE)) + return (0); + /* Allocate downsampled-data buffers if needed */ + if (downsampled_input) { + if (!alloc_downsampled_buffers(tif, sp->cinfo.c.comp_info, + sp->cinfo.c.num_components)) + return (0); + } + sp->scancount = 0; + + return (1); +} + +/* + * Encode a chunk of pixels. + * "Standard" case: incoming data is not downsampled. + */ +static int +JPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) +{ + JPEGState *sp = JState(tif); + tmsize_t nrows; + JSAMPROW bufptr[1]; + short *line16 = NULL; + int line16_count = 0; + + (void) s; + assert(sp != NULL); + /* data is expected to be supplied in multiples of a scanline */ + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "fractional scanline discarded"); + + /* The last strip will be limited to image size */ + if( !isTiled(tif) && tif->tif_row+nrows > tif->tif_dir.td_imagelength ) + nrows = tif->tif_dir.td_imagelength - tif->tif_row; + + if( sp->cinfo.c.data_precision == 12 ) + { + line16_count = (int)((sp->bytesperline * 2) / 3); + line16 = (short *) _TIFFmalloc(sizeof(short) * line16_count); + // FIXME: undiagnosed malloc failure + } + + while (nrows-- > 0) { + + if( sp->cinfo.c.data_precision == 12 ) + { + + int value_pairs = line16_count / 2; + int iPair; + + bufptr[0] = (JSAMPROW) line16; + + for( iPair = 0; iPair < value_pairs; iPair++ ) + { + unsigned char *in_ptr = + ((unsigned char *) buf) + iPair * 3; + JSAMPLE *out_ptr = (JSAMPLE *) (line16 + iPair * 2); + + out_ptr[0] = (in_ptr[0] << 4) | ((in_ptr[1] & 0xf0) >> 4); + out_ptr[1] = ((in_ptr[1] & 0x0f) << 8) | in_ptr[2]; + } + } + else + { + bufptr[0] = (JSAMPROW) buf; + } + if (TIFFjpeg_write_scanlines(sp, bufptr, 1) != 1) + return (0); + if (nrows > 0) + tif->tif_row++; + buf += sp->bytesperline; + } + + if( sp->cinfo.c.data_precision == 12 ) + { + _TIFFfree( line16 ); + } + + return (1); +} + +/* + * Encode a chunk of pixels. + * Incoming data is expected to be downsampled per sampling factors. + */ +static int +JPEGEncodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) +{ + JPEGState *sp = JState(tif); + JSAMPLE* inptr; + JSAMPLE* outptr; + tmsize_t nrows; + JDIMENSION clumps_per_line, nclump; + int clumpoffset, ci, xpos, ypos; + jpeg_component_info* compptr; + int samples_per_clump = sp->samplesperclump; + tmsize_t bytesperclumpline; + + (void) s; + assert(sp != NULL); + /* data is expected to be supplied in multiples of a clumpline */ + /* a clumpline is equivalent to v_sampling desubsampled scanlines */ + /* TODO: the following calculation of bytesperclumpline, should substitute calculation of sp->bytesperline, except that it is per v_sampling lines */ + bytesperclumpline = (((sp->cinfo.c.image_width+sp->h_sampling-1)/sp->h_sampling) + *(sp->h_sampling*sp->v_sampling+2)*sp->cinfo.c.data_precision+7) + /8; + + nrows = ( cc / bytesperclumpline ) * sp->v_sampling; + if (cc % bytesperclumpline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline discarded"); + + /* Cb,Cr both have sampling factors 1, so this is correct */ + clumps_per_line = sp->cinfo.c.comp_info[1].downsampled_width; + + while (nrows > 0) { + /* + * Fastest way to separate the data is to make one pass + * over the scanline for each row of each component. + */ + clumpoffset = 0; /* first sample in clump */ + for (ci = 0, compptr = sp->cinfo.c.comp_info; + ci < sp->cinfo.c.num_components; + ci++, compptr++) { + int hsamp = compptr->h_samp_factor; + int vsamp = compptr->v_samp_factor; + int padding = (int) (compptr->width_in_blocks * DCTSIZE - + clumps_per_line * hsamp); + for (ypos = 0; ypos < vsamp; ypos++) { + inptr = ((JSAMPLE*) buf) + clumpoffset; + outptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; + if (hsamp == 1) { + /* fast path for at least Cb and Cr */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + *outptr++ = inptr[0]; + inptr += samples_per_clump; + } + } else { + /* general case */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + for (xpos = 0; xpos < hsamp; xpos++) + *outptr++ = inptr[xpos]; + inptr += samples_per_clump; + } + } + /* pad each scanline as needed */ + for (xpos = 0; xpos < padding; xpos++) { + *outptr = outptr[-1]; + outptr++; + } + clumpoffset += hsamp; + } + } + sp->scancount++; + if (sp->scancount >= DCTSIZE) { + int n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + sp->scancount = 0; + } + tif->tif_row += sp->v_sampling; + buf += bytesperclumpline; + nrows -= sp->v_sampling; + } + return (1); +} + +/* + * Finish up at the end of a strip or tile. + */ +static int +JPEGPostEncode(TIFF* tif) +{ + JPEGState *sp = JState(tif); + + if (sp->scancount > 0) { + /* + * Need to emit a partial bufferload of downsampled data. + * Pad the data vertically. + */ + int ci, ypos, n; + jpeg_component_info* compptr; + + for (ci = 0, compptr = sp->cinfo.c.comp_info; + ci < sp->cinfo.c.num_components; + ci++, compptr++) { + int vsamp = compptr->v_samp_factor; + tmsize_t row_width = compptr->width_in_blocks * DCTSIZE + * sizeof(JSAMPLE); + for (ypos = sp->scancount * vsamp; + ypos < DCTSIZE * vsamp; ypos++) { + _TIFFmemcpy((void*)sp->ds_buffer[ci][ypos], + (void*)sp->ds_buffer[ci][ypos-1], + row_width); + + } + } + n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + } + + return (TIFFjpeg_finish_compress(JState(tif))); +} + +static void +JPEGCleanup(TIFF* tif) +{ + JPEGState *sp = JState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + tif->tif_tagmethods.printdir = sp->printdir; + + if( sp != NULL ) { + if( sp->cinfo_initialized ) + TIFFjpeg_destroy(sp); /* release libjpeg resources */ + if (sp->jpegtables) /* tag value */ + _TIFFfree(sp->jpegtables); + } + _TIFFfree(tif->tif_data); /* release local state */ + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static void +JPEGResetUpsampled( TIFF* tif ) +{ + JPEGState* sp = JState(tif); + TIFFDirectory* td = &tif->tif_dir; + + /* + * Mark whether returned data is up-sampled or not so TIFFStripSize + * and TIFFTileSize return values that reflect the true amount of + * data. + */ + tif->tif_flags &= ~TIFF_UPSAMPLED; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + if (td->td_photometric == PHOTOMETRIC_YCBCR && + sp->jpegcolormode == JPEGCOLORMODE_RGB) { + tif->tif_flags |= TIFF_UPSAMPLED; + } else { +#ifdef notdef + if (td->td_ycbcrsubsampling[0] != 1 || + td->td_ycbcrsubsampling[1] != 1) + ; /* XXX what about up-sampling? */ +#endif + } + } + + /* + * Must recalculate cached tile size in case sampling state changed. + * Should we really be doing this now if image size isn't set? + */ + if( tif->tif_tilesize > 0 ) + tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t)(-1); + if( tif->tif_scanlinesize > 0 ) + tif->tif_scanlinesize = TIFFScanlineSize(tif); +} + +static int +JPEGVSetField(TIFF* tif, uint32 tag, va_list ap) +{ + JPEGState* sp = JState(tif); + const TIFFField* fip; + uint32 v32; + + assert(sp != NULL); + + switch (tag) { + case TIFFTAG_JPEGTABLES: + v32 = (uint32) va_arg(ap, uint32); + if (v32 == 0) { + /* XXX */ + return (0); + } + _TIFFsetByteArray(&sp->jpegtables, va_arg(ap, void*), + (long) v32); + sp->jpegtables_length = v32; + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); + break; + case TIFFTAG_JPEGQUALITY: + sp->jpegquality = (int) va_arg(ap, int); + return (1); /* pseudo tag */ + case TIFFTAG_JPEGCOLORMODE: + sp->jpegcolormode = (int) va_arg(ap, int); + JPEGResetUpsampled( tif ); + return (1); /* pseudo tag */ + case TIFFTAG_PHOTOMETRIC: + { + int ret_value = (*sp->vsetparent)(tif, tag, ap); + JPEGResetUpsampled( tif ); + return ret_value; + } + case TIFFTAG_JPEGTABLESMODE: + sp->jpegtablesmode = (int) va_arg(ap, int); + return (1); /* pseudo tag */ + case TIFFTAG_YCBCRSUBSAMPLING: + /* mark the fact that we have a real ycbcrsubsampling! */ + sp->ycbcrsampling_fetched = 1; + /* should we be recomputing upsampling info here? */ + return (*sp->vsetparent)(tif, tag, ap); + default: + return (*sp->vsetparent)(tif, tag, ap); + } + + if ((fip = TIFFFieldWithTag(tif, tag))) { + TIFFSetFieldBit(tif, fip->field_bit); + } else { + return (0); + } + + tif->tif_flags |= TIFF_DIRTYDIRECT; + return (1); +} + +static int +JPEGVGetField(TIFF* tif, uint32 tag, va_list ap) +{ + JPEGState* sp = JState(tif); + + assert(sp != NULL); + + switch (tag) { + case TIFFTAG_JPEGTABLES: + *va_arg(ap, uint32*) = sp->jpegtables_length; + *va_arg(ap, void**) = sp->jpegtables; + break; + case TIFFTAG_JPEGQUALITY: + *va_arg(ap, int*) = sp->jpegquality; + break; + case TIFFTAG_JPEGCOLORMODE: + *va_arg(ap, int*) = sp->jpegcolormode; + break; + case TIFFTAG_JPEGTABLESMODE: + *va_arg(ap, int*) = sp->jpegtablesmode; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static void +JPEGPrintDir(TIFF* tif, FILE* fd, long flags) +{ + JPEGState* sp = JState(tif); + + assert(sp != NULL); + (void) flags; + + if( sp != NULL ) { + if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) + fprintf(fd, " JPEG Tables: (%lu bytes)\n", + (unsigned long) sp->jpegtables_length); + if (sp->printdir) + (*sp->printdir)(tif, fd, flags); + } +} + +static uint32 +JPEGDefaultStripSize(TIFF* tif, uint32 s) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + s = (*sp->defsparent)(tif, s); + if (s < td->td_imagelength) + s = TIFFroundup_32(s, td->td_ycbcrsubsampling[1] * DCTSIZE); + return (s); +} + +static void +JPEGDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + (*sp->deftparent)(tif, tw, th); + *tw = TIFFroundup_32(*tw, td->td_ycbcrsubsampling[0] * DCTSIZE); + *th = TIFFroundup_32(*th, td->td_ycbcrsubsampling[1] * DCTSIZE); +} + +/* + * The JPEG library initialized used to be done in TIFFInitJPEG(), but + * now that we allow a TIFF file to be opened in update mode it is necessary + * to have some way of deciding whether compression or decompression is + * desired other than looking at tif->tif_mode. We accomplish this by + * examining {TILE/STRIP}BYTECOUNTS to see if there is a non-zero entry. + * If so, we assume decompression is desired. + * + * This is tricky, because TIFFInitJPEG() is called while the directory is + * being read, and generally speaking the BYTECOUNTS tag won't have been read + * at that point. So we try to defer jpeg library initialization till we + * do have that tag ... basically any access that might require the compressor + * or decompressor that occurs after the reading of the directory. + * + * In an ideal world compressors or decompressors would be setup + * at the point where a single tile or strip was accessed (for read or write) + * so that stuff like update of missing tiles, or replacement of tiles could + * be done. However, we aren't trying to crack that nut just yet ... + * + * NFW, Feb 3rd, 2003. + */ + +static int JPEGInitializeLibJPEG( TIFF * tif, int decompress ) +{ + JPEGState* sp = JState(tif); + + if(sp->cinfo_initialized) + { + if( !decompress && sp->cinfo.comm.is_decompressor ) + TIFFjpeg_destroy( sp ); + else if( decompress && !sp->cinfo.comm.is_decompressor ) + TIFFjpeg_destroy( sp ); + else + return 1; + + sp->cinfo_initialized = 0; + } + + /* + * Initialize libjpeg. + */ + if ( decompress ) { + if (!TIFFjpeg_create_decompress(sp)) + return (0); + } else { + if (!TIFFjpeg_create_compress(sp)) + return (0); + } + + sp->cinfo_initialized = TRUE; + + return 1; +} + +int +TIFFInitJPEG(TIFF* tif, int scheme) +{ + JPEGState* sp; + + assert(scheme == COMPRESSION_JPEG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, jpegFields, TIFFArrayCount(jpegFields))) { + TIFFErrorExt(tif->tif_clientdata, + "TIFFInitJPEG", + "Merging JPEG codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8*) _TIFFmalloc(sizeof (JPEGState)); + + if (tif->tif_data == NULL) { + TIFFErrorExt(tif->tif_clientdata, + "TIFFInitJPEG", "No space for JPEG state block"); + return 0; + } + _TIFFmemset(tif->tif_data, 0, sizeof(JPEGState)); + + sp = JState(tif); + sp->tif = tif; /* back link */ + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = JPEGVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = JPEGVSetField; /* hook for codec tags */ + sp->printdir = tif->tif_tagmethods.printdir; + tif->tif_tagmethods.printdir = JPEGPrintDir; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->jpegtables = NULL; + sp->jpegtables_length = 0; + sp->jpegquality = 75; /* Default IJG quality */ + sp->jpegcolormode = JPEGCOLORMODE_RAW; + sp->jpegtablesmode = JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF; + sp->ycbcrsampling_fetched = 0; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = JPEGFixupTags; + tif->tif_setupdecode = JPEGSetupDecode; + tif->tif_predecode = JPEGPreDecode; + tif->tif_decoderow = JPEGDecode; + tif->tif_decodestrip = JPEGDecode; + tif->tif_decodetile = JPEGDecode; + tif->tif_setupencode = JPEGSetupEncode; + tif->tif_preencode = JPEGPreEncode; + tif->tif_postencode = JPEGPostEncode; + tif->tif_encoderow = JPEGEncode; + tif->tif_encodestrip = JPEGEncode; + tif->tif_encodetile = JPEGEncode; + tif->tif_cleanup = JPEGCleanup; + sp->defsparent = tif->tif_defstripsize; + tif->tif_defstripsize = JPEGDefaultStripSize; + sp->deftparent = tif->tif_deftilesize; + tif->tif_deftilesize = JPEGDefaultTileSize; + tif->tif_flags |= TIFF_NOBITREV; /* no bit reversal, please */ + + sp->cinfo_initialized = FALSE; + + /* + ** Create a JPEGTables field if no directory has yet been created. + ** We do this just to ensure that sufficient space is reserved for + ** the JPEGTables field. It will be properly created the right + ** size later. + */ + if( tif->tif_diroff == 0 ) + { +#define SIZE_OF_JPEGTABLES 2000 +/* +The following line assumes incorrectly that all JPEG-in-TIFF files will have +a JPEGTABLES tag generated and causes null-filled JPEGTABLES tags to be written +when the JPEG data is placed with TIFFWriteRawStrip. The field bit should be +set, anyway, later when actual JPEGTABLES header is generated, so removing it +here hopefully is harmless. + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); +*/ + sp->jpegtables_length = SIZE_OF_JPEGTABLES; + sp->jpegtables = (void *) _TIFFmalloc(sp->jpegtables_length); + // FIXME: NULL-deref after malloc failure + _TIFFmemset(sp->jpegtables, 0, SIZE_OF_JPEGTABLES); +#undef SIZE_OF_JPEGTABLES + } + + return 1; +} +#endif /* JPEG_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_luv.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_luv.c new file mode 100644 index 0000000000..0c2298989b --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_luv.c @@ -0,0 +1,1687 @@ +/* $Id: tif_luv.c,v 1.35 2011-04-02 20:54:09 bfriesen Exp $ */ + +/* + * Copyright (c) 1997 Greg Ward Larson + * Copyright (c) 1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler, Greg Larson and Silicon Graphics may not be used in any + * advertising or publicity relating to the software without the specific, + * prior written permission of Sam Leffler, Greg Larson and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER, GREG LARSON OR SILICON GRAPHICS BE LIABLE + * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#ifdef LOGLUV_SUPPORT + +/* + * TIFF Library. + * LogLuv compression support for high dynamic range images. + * + * Contributed by Greg Larson. + * + * LogLuv image support uses the TIFF library to store 16 or 10-bit + * log luminance values with 8 bits each of u and v or a 14-bit index. + * + * The codec can take as input and produce as output 32-bit IEEE float values + * as well as 16-bit integer values. A 16-bit luminance is interpreted + * as a sign bit followed by a 15-bit integer that is converted + * to and from a linear magnitude using the transformation: + * + * L = 2^( (Le+.5)/256 - 64 ) # real from 15-bit + * + * Le = floor( 256*(log2(L) + 64) ) # 15-bit from real + * + * The actual conversion to world luminance units in candelas per sq. meter + * requires an additional multiplier, which is stored in the TIFFTAG_STONITS. + * This value is usually set such that a reasonable exposure comes from + * clamping decoded luminances above 1 to 1 in the displayed image. + * + * The 16-bit values for u and v may be converted to real values by dividing + * each by 32768. (This allows for negative values, which aren't useful as + * far as we know, but are left in case of future improvements in human + * color vision.) + * + * Conversion from (u,v), which is actually the CIE (u',v') system for + * you color scientists, is accomplished by the following transformation: + * + * u = 4*x / (-2*x + 12*y + 3) + * v = 9*y / (-2*x + 12*y + 3) + * + * x = 9*u / (6*u - 16*v + 12) + * y = 4*v / (6*u - 16*v + 12) + * + * This process is greatly simplified by passing 32-bit IEEE floats + * for each of three CIE XYZ coordinates. The codec then takes care + * of conversion to and from LogLuv, though the application is still + * responsible for interpreting the TIFFTAG_STONITS calibration factor. + * + * By definition, a CIE XYZ vector of [1 1 1] corresponds to a neutral white + * point of (x,y)=(1/3,1/3). However, most color systems assume some other + * white point, such as D65, and an absolute color conversion to XYZ then + * to another color space with a different white point may introduce an + * unwanted color cast to the image. It is often desirable, therefore, to + * perform a white point conversion that maps the input white to [1 1 1] + * in XYZ, then record the original white point using the TIFFTAG_WHITEPOINT + * tag value. A decoder that demands absolute color calibration may use + * this white point tag to get back the original colors, but usually it + * will be ignored and the new white point will be used instead that + * matches the output color space. + * + * Pixel information is compressed into one of two basic encodings, depending + * on the setting of the compression tag, which is one of COMPRESSION_SGILOG + * or COMPRESSION_SGILOG24. For COMPRESSION_SGILOG, greyscale data is + * stored as: + * + * 1 15 + * |-+---------------| + * + * COMPRESSION_SGILOG color data is stored as: + * + * 1 15 8 8 + * |-+---------------|--------+--------| + * S Le ue ve + * + * For the 24-bit COMPRESSION_SGILOG24 color format, the data is stored as: + * + * 10 14 + * |----------|--------------| + * Le' Ce + * + * There is no sign bit in the 24-bit case, and the (u,v) chromaticity is + * encoded as an index for optimal color resolution. The 10 log bits are + * defined by the following conversions: + * + * L = 2^((Le'+.5)/64 - 12) # real from 10-bit + * + * Le' = floor( 64*(log2(L) + 12) ) # 10-bit from real + * + * The 10 bits of the smaller format may be converted into the 15 bits of + * the larger format by multiplying by 4 and adding 13314. Obviously, + * a smaller range of magnitudes is covered (about 5 orders of magnitude + * instead of 38), and the lack of a sign bit means that negative luminances + * are not allowed. (Well, they aren't allowed in the real world, either, + * but they are useful for certain types of image processing.) + * + * The desired user format is controlled by the setting the internal + * pseudo tag TIFFTAG_SGILOGDATAFMT to one of: + * SGILOGDATAFMT_FLOAT = IEEE 32-bit float XYZ values + * SGILOGDATAFMT_16BIT = 16-bit integer encodings of logL, u and v + * Raw data i/o is also possible using: + * SGILOGDATAFMT_RAW = 32-bit unsigned integer with encoded pixel + * In addition, the following decoding is provided for ease of display: + * SGILOGDATAFMT_8BIT = 8-bit default RGB gamma-corrected values + * + * For grayscale images, we provide the following data formats: + * SGILOGDATAFMT_FLOAT = IEEE 32-bit float Y values + * SGILOGDATAFMT_16BIT = 16-bit integer w/ encoded luminance + * SGILOGDATAFMT_8BIT = 8-bit gray monitor values + * + * Note that the COMPRESSION_SGILOG applies a simple run-length encoding + * scheme by separating the logL, u and v bytes for each row and applying + * a PackBits type of compression. Since the 24-bit encoding is not + * adaptive, the 32-bit color format takes less space in many cases. + * + * Further control is provided over the conversion from higher-resolution + * formats to final encoded values through the pseudo tag + * TIFFTAG_SGILOGENCODE: + * SGILOGENCODE_NODITHER = do not dither encoded values + * SGILOGENCODE_RANDITHER = apply random dithering during encoding + * + * The default value of this tag is SGILOGENCODE_NODITHER for + * COMPRESSION_SGILOG to maximize run-length encoding and + * SGILOGENCODE_RANDITHER for COMPRESSION_SGILOG24 to turn + * quantization errors into noise. + */ + +#include +#include +#include + +/* + * State block for each open TIFF + * file using LogLuv compression/decompression. + */ +typedef struct logLuvState LogLuvState; + +struct logLuvState { + int user_datafmt; /* user data format */ + int encode_meth; /* encoding method */ + int pixel_size; /* bytes per pixel */ + + uint8* tbuf; /* translation buffer */ + tmsize_t tbuflen; /* buffer length */ + void (*tfunc)(LogLuvState*, uint8*, tmsize_t); + + TIFFVSetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +}; + +#define DecoderState(tif) ((LogLuvState*) (tif)->tif_data) +#define EncoderState(tif) ((LogLuvState*) (tif)->tif_data) + +#define SGILOGDATAFMT_UNKNOWN -1 + +#define MINRUN 4 /* minimum run length */ + +/* + * Decode a string of 16-bit gray pixels. + */ +static int +LogL16Decode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s) +{ + static const char module[] = "LogL16Decode"; + LogLuvState* sp = DecoderState(tif); + int shft; + tmsize_t i; + tmsize_t npixels; + unsigned char* bp; + int16* tp; + int16 b; + tmsize_t cc; + int rc; + + assert(s == 0); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_16BIT) + tp = (int16*) op; + else { + assert(sp->tbuflen >= npixels); + tp = (int16*) sp->tbuf; + } + _TIFFmemset((void*) tp, 0, npixels*sizeof (tp[0])); + + bp = (unsigned char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + /* get each byte string */ + for (shft = 2*8; (shft -= 8) >= 0; ) { + for (i = 0; i < npixels && cc > 0; ) + if (*bp >= 128) { /* run */ + rc = *bp++ + (2-128); /* TODO: potential input buffer overrun when decoding corrupt or truncated data */ + b = (int16)(*bp++ << shft); + cc -= 2; + while (rc-- && i < npixels) + tp[i++] |= b; + } else { /* non-run */ + rc = *bp++; /* nul is noop */ + while (--cc && rc-- && i < npixels) + tp[i++] |= (int16)*bp++ << shft; + } + if (i != npixels) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at row %lu (short %I64d pixels)", + (unsigned long) tif->tif_row, + (unsigned __int64) (npixels - i)); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at row %lu (short %llu pixels)", + (unsigned long) tif->tif_row, + (unsigned long long) (npixels - i)); +#endif + tif->tif_rawcp = (uint8*) bp; + tif->tif_rawcc = cc; + return (0); + } + } + (*sp->tfunc)(sp, op, npixels); + tif->tif_rawcp = (uint8*) bp; + tif->tif_rawcc = cc; + return (1); +} + +/* + * Decode a string of 24-bit pixels. + */ +static int +LogLuvDecode24(TIFF* tif, uint8* op, tmsize_t occ, uint16 s) +{ + static const char module[] = "LogLuvDecode24"; + LogLuvState* sp = DecoderState(tif); + tmsize_t cc; + tmsize_t i; + tmsize_t npixels; + unsigned char* bp; + uint32* tp; + + assert(s == 0); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32 *)op; + else { + assert(sp->tbuflen >= npixels); + tp = (uint32 *) sp->tbuf; + } + /* copy to array of uint32 */ + bp = (unsigned char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + for (i = 0; i < npixels && cc > 0; i++) { + tp[i] = bp[0] << 16 | bp[1] << 8 | bp[2]; + bp += 3; + cc -= 3; + } + tif->tif_rawcp = (uint8*) bp; + tif->tif_rawcc = cc; + if (i != npixels) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at row %lu (short %I64d pixels)", + (unsigned long) tif->tif_row, + (unsigned __int64) (npixels - i)); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at row %lu (short %llu pixels)", + (unsigned long) tif->tif_row, + (unsigned long long) (npixels - i)); +#endif + return (0); + } + (*sp->tfunc)(sp, op, npixels); + return (1); +} + +/* + * Decode a string of 32-bit pixels. + */ +static int +LogLuvDecode32(TIFF* tif, uint8* op, tmsize_t occ, uint16 s) +{ + static const char module[] = "LogLuvDecode32"; + LogLuvState* sp; + int shft; + tmsize_t i; + tmsize_t npixels; + unsigned char* bp; + uint32* tp; + uint32 b; + tmsize_t cc; + int rc; + + assert(s == 0); + sp = DecoderState(tif); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32*) op; + else { + assert(sp->tbuflen >= npixels); + tp = (uint32*) sp->tbuf; + } + _TIFFmemset((void*) tp, 0, npixels*sizeof (tp[0])); + + bp = (unsigned char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + /* get each byte string */ + for (shft = 4*8; (shft -= 8) >= 0; ) { + for (i = 0; i < npixels && cc > 0; ) + if (*bp >= 128) { /* run */ + rc = *bp++ + (2-128); + b = (uint32)*bp++ << shft; + cc -= 2; /* TODO: potential input buffer overrun when decoding corrupt or truncated data */ + while (rc-- && i < npixels) + tp[i++] |= b; + } else { /* non-run */ + rc = *bp++; /* nul is noop */ + while (--cc && rc-- && i < npixels) + tp[i++] |= (uint32)*bp++ << shft; + } + if (i != npixels) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at row %lu (short %I64d pixels)", + (unsigned long) tif->tif_row, + (unsigned __int64) (npixels - i)); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at row %lu (short %llu pixels)", + (unsigned long) tif->tif_row, + (unsigned long long) (npixels - i)); +#endif + tif->tif_rawcp = (uint8*) bp; + tif->tif_rawcc = cc; + return (0); + } + } + (*sp->tfunc)(sp, op, npixels); + tif->tif_rawcp = (uint8*) bp; + tif->tif_rawcc = cc; + return (1); +} + +/* + * Decode a strip of pixels. We break it into rows to + * maintain synchrony with the encode algorithm, which + * is row by row. + */ +static int +LogLuvDecodeStrip(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + tmsize_t rowlen = TIFFScanlineSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Decode a tile of pixels. We break it into rows to + * maintain synchrony with the encode algorithm, which + * is row by row. + */ +static int +LogLuvDecodeTile(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + tmsize_t rowlen = TIFFTileRowSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Encode a row of 16-bit pixels. + */ +static int +LogL16Encode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + LogLuvState* sp = EncoderState(tif); + int shft; + tmsize_t i; + tmsize_t j; + tmsize_t npixels; + uint8* op; + int16* tp; + int16 b; + tmsize_t occ; + int rc=0, mask; + tmsize_t beg; + + assert(s == 0); + assert(sp != NULL); + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_16BIT) + tp = (int16*) bp; + else { + tp = (int16*) sp->tbuf; + assert(sp->tbuflen >= npixels); + (*sp->tfunc)(sp, bp, npixels); + } + /* compress each byte string */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (shft = 2*8; (shft -= 8) >= 0; ) + for (i = 0; i < npixels; i += rc) { + if (occ < 4) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + mask = 0xff << shft; /* find next run */ + for (beg = i; beg < npixels; beg += rc) { + b = (int16) (tp[beg] & mask); + rc = 1; + while (rc < 127+2 && beg+rc < npixels && + (tp[beg+rc] & mask) == b) + rc++; + if (rc >= MINRUN) + break; /* long enough */ + } + if (beg-i > 1 && beg-i < MINRUN) { + b = (int16) (tp[i] & mask);/*check short run */ + j = i+1; + while ((tp[j++] & mask) == b) + if (j == beg) { + *op++ = (uint8)(128-2+j-i); + *op++ = (uint8)(b >> shft); + occ -= 2; + i = beg; + break; + } + } + while (i < beg) { /* write out non-run */ + if ((j = beg-i) > 127) j = 127; + if (occ < j+3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = (uint8) j; occ--; + while (j--) { + *op++ = (uint8) (tp[i++] >> shft & 0xff); + occ--; + } + } + if (rc >= MINRUN) { /* write out run */ + *op++ = (uint8) (128-2+rc); + *op++ = (uint8) (tp[beg] >> shft & 0xff); + occ -= 2; + } else + rc = 0; + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (1); +} + +/* + * Encode a row of 24-bit pixels. + */ +static int +LogLuvEncode24(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + LogLuvState* sp = EncoderState(tif); + tmsize_t i; + tmsize_t npixels; + tmsize_t occ; + uint8* op; + uint32* tp; + + assert(s == 0); + assert(sp != NULL); + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32*) bp; + else { + tp = (uint32*) sp->tbuf; + assert(sp->tbuflen >= npixels); + (*sp->tfunc)(sp, bp, npixels); + } + /* write out encoded pixels */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (i = npixels; i--; ) { + if (occ < 3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = (uint8)(*tp >> 16); + *op++ = (uint8)(*tp >> 8 & 0xff); + *op++ = (uint8)(*tp++ & 0xff); + occ -= 3; + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (1); +} + +/* + * Encode a row of 32-bit pixels. + */ +static int +LogLuvEncode32(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + LogLuvState* sp = EncoderState(tif); + int shft; + tmsize_t i; + tmsize_t j; + tmsize_t npixels; + uint8* op; + uint32* tp; + uint32 b; + tmsize_t occ; + int rc=0, mask; + tmsize_t beg; + + assert(s == 0); + assert(sp != NULL); + + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32*) bp; + else { + tp = (uint32*) sp->tbuf; + assert(sp->tbuflen >= npixels); + (*sp->tfunc)(sp, bp, npixels); + } + /* compress each byte string */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (shft = 4*8; (shft -= 8) >= 0; ) + for (i = 0; i < npixels; i += rc) { + if (occ < 4) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + mask = 0xff << shft; /* find next run */ + for (beg = i; beg < npixels; beg += rc) { + b = tp[beg] & mask; + rc = 1; + while (rc < 127+2 && beg+rc < npixels && + (tp[beg+rc] & mask) == b) + rc++; + if (rc >= MINRUN) + break; /* long enough */ + } + if (beg-i > 1 && beg-i < MINRUN) { + b = tp[i] & mask; /* check short run */ + j = i+1; + while ((tp[j++] & mask) == b) + if (j == beg) { + *op++ = (uint8)(128-2+j-i); + *op++ = (uint8)(b >> shft); + occ -= 2; + i = beg; + break; + } + } + while (i < beg) { /* write out non-run */ + if ((j = beg-i) > 127) j = 127; + if (occ < j+3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = (uint8) j; occ--; + while (j--) { + *op++ = (uint8)(tp[i++] >> shft & 0xff); + occ--; + } + } + if (rc >= MINRUN) { /* write out run */ + *op++ = (uint8) (128-2+rc); + *op++ = (uint8)(tp[beg] >> shft & 0xff); + occ -= 2; + } else + rc = 0; + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (1); +} + +/* + * Encode a strip of pixels. We break it into rows to + * avoid encoding runs across row boundaries. + */ +static int +LogLuvEncodeStrip(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + tmsize_t rowlen = TIFFScanlineSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Encode a tile of pixels. We break it into rows to + * avoid encoding runs across row boundaries. + */ +static int +LogLuvEncodeTile(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + tmsize_t rowlen = TIFFTileRowSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Encode/Decode functions for converting to and from user formats. + */ + +#include "uvcode.h" + +#ifndef UVSCALE +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 +#define UVSCALE 410. +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef log2 +#define log2(x) ((1./M_LN2)*log(x)) +#endif +#define exp2(x) exp(M_LN2*(x)) + +#define itrunc(x,m) ((m)==SGILOGENCODE_NODITHER ? \ + (int)(x) : \ + (int)((x) + rand()*(1./RAND_MAX) - .5)) + +#if !LOGLUV_PUBLIC +static +#endif +double +LogL16toY(int p16) /* compute luminance from 16-bit LogL */ +{ + int Le = p16 & 0x7fff; + double Y; + + if (!Le) + return (0.); + Y = exp(M_LN2/256.*(Le+.5) - M_LN2*64.); + return (!(p16 & 0x8000) ? Y : -Y); +} + +#if !LOGLUV_PUBLIC +static +#endif +int +LogL16fromY(double Y, int em) /* get 16-bit LogL from Y */ +{ + if (Y >= 1.8371976e19) + return (0x7fff); + if (Y <= -1.8371976e19) + return (0xffff); + if (Y > 5.4136769e-20) + return itrunc(256.*(log2(Y) + 64.), em); + if (Y < -5.4136769e-20) + return (~0x7fff | itrunc(256.*(log2(-Y) + 64.), em)); + return (0); +} + +static void +L16toY(LogLuvState* sp, uint8* op, tmsize_t n) +{ + int16* l16 = (int16*) sp->tbuf; + float* yp = (float*) op; + + while (n-- > 0) + *yp++ = (float)LogL16toY(*l16++); +} + +static void +L16toGry(LogLuvState* sp, uint8* op, tmsize_t n) +{ + int16* l16 = (int16*) sp->tbuf; + uint8* gp = (uint8*) op; + + while (n-- > 0) { + double Y = LogL16toY(*l16++); + *gp++ = (uint8) ((Y <= 0.) ? 0 : (Y >= 1.) ? 255 : (int)(256.*sqrt(Y))); + } +} + +static void +L16fromY(LogLuvState* sp, uint8* op, tmsize_t n) +{ + int16* l16 = (int16*) sp->tbuf; + float* yp = (float*) op; + + while (n-- > 0) + *l16++ = (int16) (LogL16fromY(*yp++, sp->encode_meth)); +} + +#if !LOGLUV_PUBLIC +static +#endif +void +XYZtoRGB24(float xyz[3], uint8 rgb[3]) +{ + double r, g, b; + /* assume CCIR-709 primaries */ + r = 2.690*xyz[0] + -1.276*xyz[1] + -0.414*xyz[2]; + g = -1.022*xyz[0] + 1.978*xyz[1] + 0.044*xyz[2]; + b = 0.061*xyz[0] + -0.224*xyz[1] + 1.163*xyz[2]; + /* assume 2.0 gamma for speed */ + /* could use integer sqrt approx., but this is probably faster */ + rgb[0] = (uint8)((r<=0.) ? 0 : (r >= 1.) ? 255 : (int)(256.*sqrt(r))); + rgb[1] = (uint8)((g<=0.) ? 0 : (g >= 1.) ? 255 : (int)(256.*sqrt(g))); + rgb[2] = (uint8)((b<=0.) ? 0 : (b >= 1.) ? 255 : (int)(256.*sqrt(b))); +} + +#if !LOGLUV_PUBLIC +static +#endif +double +LogL10toY(int p10) /* compute luminance from 10-bit LogL */ +{ + if (p10 == 0) + return (0.); + return (exp(M_LN2/64.*(p10+.5) - M_LN2*12.)); +} + +#if !LOGLUV_PUBLIC +static +#endif +int +LogL10fromY(double Y, int em) /* get 10-bit LogL from Y */ +{ + if (Y >= 15.742) + return (0x3ff); + else if (Y <= .00024283) + return (0); + else + return itrunc(64.*(log2(Y) + 12.), em); +} + +#define NANGLES 100 +#define uv2ang(u, v) ( (NANGLES*.499999999/M_PI) \ + * atan2((v)-V_NEU,(u)-U_NEU) + .5*NANGLES ) + +static int +oog_encode(double u, double v) /* encode out-of-gamut chroma */ +{ + static int oog_table[NANGLES]; + static int initialized = 0; + register int i; + + if (!initialized) { /* set up perimeter table */ + double eps[NANGLES], ua, va, ang, epsa; + int ui, vi, ustep; + for (i = NANGLES; i--; ) + eps[i] = 2.; + for (vi = UV_NVS; vi--; ) { + va = UV_VSTART + (vi+.5)*UV_SQSIZ; + ustep = uv_row[vi].nus-1; + if (vi == UV_NVS-1 || vi == 0 || ustep <= 0) + ustep = 1; + for (ui = uv_row[vi].nus-1; ui >= 0; ui -= ustep) { + ua = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ; + ang = uv2ang(ua, va); + i = (int) ang; + epsa = fabs(ang - (i+.5)); + if (epsa < eps[i]) { + oog_table[i] = uv_row[vi].ncum + ui; + eps[i] = epsa; + } + } + } + for (i = NANGLES; i--; ) /* fill any holes */ + if (eps[i] > 1.5) { + int i1, i2; + for (i1 = 1; i1 < NANGLES/2; i1++) + if (eps[(i+i1)%NANGLES] < 1.5) + break; + for (i2 = 1; i2 < NANGLES/2; i2++) + if (eps[(i+NANGLES-i2)%NANGLES] < 1.5) + break; + if (i1 < i2) + oog_table[i] = + oog_table[(i+i1)%NANGLES]; + else + oog_table[i] = + oog_table[(i+NANGLES-i2)%NANGLES]; + } + initialized = 1; + } + i = (int) uv2ang(u, v); /* look up hue angle */ + return (oog_table[i]); +} + +#undef uv2ang +#undef NANGLES + +#if !LOGLUV_PUBLIC +static +#endif +int +uv_encode(double u, double v, int em) /* encode (u',v') coordinates */ +{ + register int vi, ui; + + if (v < UV_VSTART) + return oog_encode(u, v); + vi = itrunc((v - UV_VSTART)*(1./UV_SQSIZ), em); + if (vi >= UV_NVS) + return oog_encode(u, v); + if (u < uv_row[vi].ustart) + return oog_encode(u, v); + ui = itrunc((u - uv_row[vi].ustart)*(1./UV_SQSIZ), em); + if (ui >= uv_row[vi].nus) + return oog_encode(u, v); + + return (uv_row[vi].ncum + ui); +} + +#if !LOGLUV_PUBLIC +static +#endif +int +uv_decode(double *up, double *vp, int c) /* decode (u',v') index */ +{ + int upper, lower; + register int ui, vi; + + if (c < 0 || c >= UV_NDIVS) + return (-1); + lower = 0; /* binary search */ + upper = UV_NVS; + while (upper - lower > 1) { + vi = (lower + upper) >> 1; + ui = c - uv_row[vi].ncum; + if (ui > 0) + lower = vi; + else if (ui < 0) + upper = vi; + else { + lower = vi; + break; + } + } + vi = lower; + ui = c - uv_row[vi].ncum; + *up = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ; + *vp = UV_VSTART + (vi+.5)*UV_SQSIZ; + return (0); +} + +#if !LOGLUV_PUBLIC +static +#endif +void +LogLuv24toXYZ(uint32 p, float XYZ[3]) +{ + int Ce; + double L, u, v, s, x, y; + /* decode luminance */ + L = LogL10toY(p>>14 & 0x3ff); + if (L <= 0.) { + XYZ[0] = XYZ[1] = XYZ[2] = 0.; + return; + } + /* decode color */ + Ce = p & 0x3fff; + if (uv_decode(&u, &v, Ce) < 0) { + u = U_NEU; v = V_NEU; + } + s = 1./(6.*u - 16.*v + 12.); + x = 9.*u * s; + y = 4.*v * s; + /* convert to XYZ */ + XYZ[0] = (float)(x/y * L); + XYZ[1] = (float)L; + XYZ[2] = (float)((1.-x-y)/y * L); +} + +#if !LOGLUV_PUBLIC +static +#endif +uint32 +LogLuv24fromXYZ(float XYZ[3], int em) +{ + int Le, Ce; + double u, v, s; + /* encode luminance */ + Le = LogL10fromY(XYZ[1], em); + /* encode color */ + s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2]; + if (!Le || s <= 0.) { + u = U_NEU; + v = V_NEU; + } else { + u = 4.*XYZ[0] / s; + v = 9.*XYZ[1] / s; + } + Ce = uv_encode(u, v, em); + if (Ce < 0) /* never happens */ + Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER); + /* combine encodings */ + return (Le << 14 | Ce); +} + +static void +Luv24toXYZ(LogLuvState* sp, uint8* op, tmsize_t n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + LogLuv24toXYZ(*luv, xyz); + xyz += 3; + luv++; + } +} + +static void +Luv24toLuv48(LogLuvState* sp, uint8* op, tmsize_t n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + while (n-- > 0) { + double u, v; + + *luv3++ = (int16)((*luv >> 12 & 0xffd) + 13314); + if (uv_decode(&u, &v, *luv&0x3fff) < 0) { + u = U_NEU; + v = V_NEU; + } + *luv3++ = (int16)(u * (1L<<15)); + *luv3++ = (int16)(v * (1L<<15)); + luv++; + } +} + +static void +Luv24toRGB(LogLuvState* sp, uint8* op, tmsize_t n) +{ + uint32* luv = (uint32*) sp->tbuf; + uint8* rgb = (uint8*) op; + + while (n-- > 0) { + float xyz[3]; + + LogLuv24toXYZ(*luv++, xyz); + XYZtoRGB24(xyz, rgb); + rgb += 3; + } +} + +static void +Luv24fromXYZ(LogLuvState* sp, uint8* op, tmsize_t n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + *luv++ = LogLuv24fromXYZ(xyz, sp->encode_meth); + xyz += 3; + } +} + +static void +Luv24fromLuv48(LogLuvState* sp, uint8* op, tmsize_t n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + while (n-- > 0) { + int Le, Ce; + + if (luv3[0] <= 0) + Le = 0; + else if (luv3[0] >= (1<<12)+3314) + Le = (1<<10) - 1; + else if (sp->encode_meth == SGILOGENCODE_NODITHER) + Le = (luv3[0]-3314) >> 2; + else + Le = itrunc(.25*(luv3[0]-3314.), sp->encode_meth); + + Ce = uv_encode((luv3[1]+.5)/(1<<15), (luv3[2]+.5)/(1<<15), + sp->encode_meth); + if (Ce < 0) /* never happens */ + Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER); + *luv++ = (uint32)Le << 14 | Ce; + luv3 += 3; + } +} + +#if !LOGLUV_PUBLIC +static +#endif +void +LogLuv32toXYZ(uint32 p, float XYZ[3]) +{ + double L, u, v, s, x, y; + /* decode luminance */ + L = LogL16toY((int)p >> 16); + if (L <= 0.) { + XYZ[0] = XYZ[1] = XYZ[2] = 0.; + return; + } + /* decode color */ + u = 1./UVSCALE * ((p>>8 & 0xff) + .5); + v = 1./UVSCALE * ((p & 0xff) + .5); + s = 1./(6.*u - 16.*v + 12.); + x = 9.*u * s; + y = 4.*v * s; + /* convert to XYZ */ + XYZ[0] = (float)(x/y * L); + XYZ[1] = (float)L; + XYZ[2] = (float)((1.-x-y)/y * L); +} + +#if !LOGLUV_PUBLIC +static +#endif +uint32 +LogLuv32fromXYZ(float XYZ[3], int em) +{ + unsigned int Le, ue, ve; + double u, v, s; + /* encode luminance */ + Le = (unsigned int)LogL16fromY(XYZ[1], em); + /* encode color */ + s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2]; + if (!Le || s <= 0.) { + u = U_NEU; + v = V_NEU; + } else { + u = 4.*XYZ[0] / s; + v = 9.*XYZ[1] / s; + } + if (u <= 0.) ue = 0; + else ue = itrunc(UVSCALE*u, em); + if (ue > 255) ue = 255; + if (v <= 0.) ve = 0; + else ve = itrunc(UVSCALE*v, em); + if (ve > 255) ve = 255; + /* combine encodings */ + return (Le << 16 | ue << 8 | ve); +} + +static void +Luv32toXYZ(LogLuvState* sp, uint8* op, tmsize_t n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + LogLuv32toXYZ(*luv++, xyz); + xyz += 3; + } +} + +static void +Luv32toLuv48(LogLuvState* sp, uint8* op, tmsize_t n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + while (n-- > 0) { + double u, v; + + *luv3++ = (int16)(*luv >> 16); + u = 1./UVSCALE * ((*luv>>8 & 0xff) + .5); + v = 1./UVSCALE * ((*luv & 0xff) + .5); + *luv3++ = (int16)(u * (1L<<15)); + *luv3++ = (int16)(v * (1L<<15)); + luv++; + } +} + +static void +Luv32toRGB(LogLuvState* sp, uint8* op, tmsize_t n) +{ + uint32* luv = (uint32*) sp->tbuf; + uint8* rgb = (uint8*) op; + + while (n-- > 0) { + float xyz[3]; + + LogLuv32toXYZ(*luv++, xyz); + XYZtoRGB24(xyz, rgb); + rgb += 3; + } +} + +static void +Luv32fromXYZ(LogLuvState* sp, uint8* op, tmsize_t n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + *luv++ = LogLuv32fromXYZ(xyz, sp->encode_meth); + xyz += 3; + } +} + +static void +Luv32fromLuv48(LogLuvState* sp, uint8* op, tmsize_t n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + if (sp->encode_meth == SGILOGENCODE_NODITHER) { + while (n-- > 0) { + *luv++ = (uint32)luv3[0] << 16 | + (luv3[1]*(uint32)(UVSCALE+.5) >> 7 & 0xff00) | + (luv3[2]*(uint32)(UVSCALE+.5) >> 15 & 0xff); + luv3 += 3; + } + return; + } + while (n-- > 0) { + *luv++ = (uint32)luv3[0] << 16 | + (itrunc(luv3[1]*(UVSCALE/(1<<15)), sp->encode_meth) << 8 & 0xff00) | + (itrunc(luv3[2]*(UVSCALE/(1<<15)), sp->encode_meth) & 0xff); + luv3 += 3; + } +} + +static void +_logLuvNop(LogLuvState* sp, uint8* op, tmsize_t n) +{ + (void) sp; (void) op; (void) n; +} + +static int +LogL16GuessDataFmt(TIFFDirectory *td) +{ +#define PACK(s,b,f) (((b)<<6)|((s)<<3)|(f)) + switch (PACK(td->td_samplesperpixel, td->td_bitspersample, td->td_sampleformat)) { + case PACK(1, 32, SAMPLEFORMAT_IEEEFP): + return (SGILOGDATAFMT_FLOAT); + case PACK(1, 16, SAMPLEFORMAT_VOID): + case PACK(1, 16, SAMPLEFORMAT_INT): + case PACK(1, 16, SAMPLEFORMAT_UINT): + return (SGILOGDATAFMT_16BIT); + case PACK(1, 8, SAMPLEFORMAT_VOID): + case PACK(1, 8, SAMPLEFORMAT_UINT): + return (SGILOGDATAFMT_8BIT); + } +#undef PACK + return (SGILOGDATAFMT_UNKNOWN); +} + +static tmsize_t +multiply_ms(tmsize_t m1, tmsize_t m2) +{ + tmsize_t bytes = m1 * m2; + + if (m1 && bytes / m1 != m2) + bytes = 0; + + return bytes; +} + +static int +LogL16InitState(TIFF* tif) +{ + static const char module[] = "LogL16InitState"; + TIFFDirectory *td = &tif->tif_dir; + LogLuvState* sp = DecoderState(tif); + + assert(sp != NULL); + assert(td->td_photometric == PHOTOMETRIC_LOGL); + + /* for some reason, we can't do this in TIFFInitLogL16 */ + if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN) + sp->user_datafmt = LogL16GuessDataFmt(td); + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->pixel_size = sizeof (float); + break; + case SGILOGDATAFMT_16BIT: + sp->pixel_size = sizeof (int16); + break; + case SGILOGDATAFMT_8BIT: + sp->pixel_size = sizeof (uint8); + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "No support for converting user data format to LogL"); + return (0); + } + if( isTiled(tif) ) + sp->tbuflen = multiply_ms(td->td_tilewidth, td->td_tilelength); + else + sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_rowsperstrip); + if (multiply_ms(sp->tbuflen, sizeof (int16)) == 0 || + (sp->tbuf = (uint8*) _TIFFmalloc(sp->tbuflen * sizeof (int16))) == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, "No space for SGILog translation buffer"); + return (0); + } + return (1); +} + +static int +LogLuvGuessDataFmt(TIFFDirectory *td) +{ + int guess; + + /* + * If the user didn't tell us their datafmt, + * take our best guess from the bitspersample. + */ +#define PACK(a,b) (((a)<<3)|(b)) + switch (PACK(td->td_bitspersample, td->td_sampleformat)) { + case PACK(32, SAMPLEFORMAT_IEEEFP): + guess = SGILOGDATAFMT_FLOAT; + break; + case PACK(32, SAMPLEFORMAT_VOID): + case PACK(32, SAMPLEFORMAT_UINT): + case PACK(32, SAMPLEFORMAT_INT): + guess = SGILOGDATAFMT_RAW; + break; + case PACK(16, SAMPLEFORMAT_VOID): + case PACK(16, SAMPLEFORMAT_INT): + case PACK(16, SAMPLEFORMAT_UINT): + guess = SGILOGDATAFMT_16BIT; + break; + case PACK( 8, SAMPLEFORMAT_VOID): + case PACK( 8, SAMPLEFORMAT_UINT): + guess = SGILOGDATAFMT_8BIT; + break; + default: + guess = SGILOGDATAFMT_UNKNOWN; + break; +#undef PACK + } + /* + * Double-check samples per pixel. + */ + switch (td->td_samplesperpixel) { + case 1: + if (guess != SGILOGDATAFMT_RAW) + guess = SGILOGDATAFMT_UNKNOWN; + break; + case 3: + if (guess == SGILOGDATAFMT_RAW) + guess = SGILOGDATAFMT_UNKNOWN; + break; + default: + guess = SGILOGDATAFMT_UNKNOWN; + break; + } + return (guess); +} + +static int +LogLuvInitState(TIFF* tif) +{ + static const char module[] = "LogLuvInitState"; + TIFFDirectory* td = &tif->tif_dir; + LogLuvState* sp = DecoderState(tif); + + assert(sp != NULL); + assert(td->td_photometric == PHOTOMETRIC_LOGLUV); + + /* for some reason, we can't do this in TIFFInitLogLuv */ + if (td->td_planarconfig != PLANARCONFIG_CONTIG) { + TIFFErrorExt(tif->tif_clientdata, module, + "SGILog compression cannot handle non-contiguous data"); + return (0); + } + if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN) + sp->user_datafmt = LogLuvGuessDataFmt(td); + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->pixel_size = 3*sizeof (float); + break; + case SGILOGDATAFMT_16BIT: + sp->pixel_size = 3*sizeof (int16); + break; + case SGILOGDATAFMT_RAW: + sp->pixel_size = sizeof (uint32); + break; + case SGILOGDATAFMT_8BIT: + sp->pixel_size = 3*sizeof (uint8); + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "No support for converting user data format to LogLuv"); + return (0); + } + if( isTiled(tif) ) + sp->tbuflen = multiply_ms(td->td_tilewidth, td->td_tilelength); + else + sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_rowsperstrip); + if (multiply_ms(sp->tbuflen, sizeof (uint32)) == 0 || + (sp->tbuf = (uint8*) _TIFFmalloc(sp->tbuflen * sizeof (uint32))) == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, "No space for SGILog translation buffer"); + return (0); + } + return (1); +} + +static int +LogLuvFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +static int +LogLuvSetupDecode(TIFF* tif) +{ + static const char module[] = "LogLuvSetupDecode"; + LogLuvState* sp = DecoderState(tif); + TIFFDirectory* td = &tif->tif_dir; + + tif->tif_postdecode = _TIFFNoPostDecode; + switch (td->td_photometric) { + case PHOTOMETRIC_LOGLUV: + if (!LogLuvInitState(tif)) + break; + if (td->td_compression == COMPRESSION_SGILOG24) { + tif->tif_decoderow = LogLuvDecode24; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv24toXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv24toLuv48; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = Luv24toRGB; + break; + } + } else { + tif->tif_decoderow = LogLuvDecode32; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv32toXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv32toLuv48; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = Luv32toRGB; + break; + } + } + return (1); + case PHOTOMETRIC_LOGL: + if (!LogL16InitState(tif)) + break; + tif->tif_decoderow = LogL16Decode; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = L16toY; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = L16toGry; + break; + } + return (1); + default: + TIFFErrorExt(tif->tif_clientdata, module, + "Inappropriate photometric interpretation %d for SGILog compression; %s", + td->td_photometric, "must be either LogLUV or LogL"); + break; + } + return (0); +} + +static int +LogLuvSetupEncode(TIFF* tif) +{ + static const char module[] = "LogLuvSetupEncode"; + LogLuvState* sp = EncoderState(tif); + TIFFDirectory* td = &tif->tif_dir; + + switch (td->td_photometric) { + case PHOTOMETRIC_LOGLUV: + if (!LogLuvInitState(tif)) + break; + if (td->td_compression == COMPRESSION_SGILOG24) { + tif->tif_encoderow = LogLuvEncode24; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv24fromXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv24fromLuv48; + break; + case SGILOGDATAFMT_RAW: + break; + default: + goto notsupported; + } + } else { + tif->tif_encoderow = LogLuvEncode32; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv32fromXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv32fromLuv48; + break; + case SGILOGDATAFMT_RAW: + break; + default: + goto notsupported; + } + } + break; + case PHOTOMETRIC_LOGL: + if (!LogL16InitState(tif)) + break; + tif->tif_encoderow = LogL16Encode; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = L16fromY; + break; + case SGILOGDATAFMT_16BIT: + break; + default: + goto notsupported; + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "Inappropriate photometric interpretation %d for SGILog compression; %s", + td->td_photometric, "must be either LogLUV or LogL"); + break; + } + return (1); +notsupported: + TIFFErrorExt(tif->tif_clientdata, module, + "SGILog compression supported only for %s, or raw data", + td->td_photometric == PHOTOMETRIC_LOGL ? "Y, L" : "XYZ, Luv"); + return (0); +} + +static void +LogLuvClose(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + + /* + * For consistency, we always want to write out the same + * bitspersample and sampleformat for our TIFF file, + * regardless of the data format being used by the application. + * Since this routine is called after tags have been set but + * before they have been recorded in the file, we reset them here. + */ + td->td_samplesperpixel = + (td->td_photometric == PHOTOMETRIC_LOGL) ? 1 : 3; + td->td_bitspersample = 16; + td->td_sampleformat = SAMPLEFORMAT_INT; +} + +static void +LogLuvCleanup(TIFF* tif) +{ + LogLuvState* sp = (LogLuvState *)tif->tif_data; + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->tbuf) + _TIFFfree(sp->tbuf); + _TIFFfree(sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int +LogLuvVSetField(TIFF* tif, uint32 tag, va_list ap) +{ + static const char module[] = "LogLuvVSetField"; + LogLuvState* sp = DecoderState(tif); + int bps, fmt; + + switch (tag) { + case TIFFTAG_SGILOGDATAFMT: + sp->user_datafmt = (int) va_arg(ap, int); + /* + * Tweak the TIFF header so that the rest of libtiff knows what + * size of data will be passed between app and library, and + * assume that the app knows what it is doing and is not + * confused by these header manipulations... + */ + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + bps = 32, fmt = SAMPLEFORMAT_IEEEFP; + break; + case SGILOGDATAFMT_16BIT: + bps = 16, fmt = SAMPLEFORMAT_INT; + break; + case SGILOGDATAFMT_RAW: + bps = 32, fmt = SAMPLEFORMAT_UINT; + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + break; + case SGILOGDATAFMT_8BIT: + bps = 8, fmt = SAMPLEFORMAT_UINT; + break; + default: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Unknown data format %d for LogLuv compression", + sp->user_datafmt); + return (0); + } + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, fmt); + /* + * Must recalculate sizes should bits/sample change. + */ + tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t) -1; + tif->tif_scanlinesize = TIFFScanlineSize(tif); + return (1); + case TIFFTAG_SGILOGENCODE: + sp->encode_meth = (int) va_arg(ap, int); + if (sp->encode_meth != SGILOGENCODE_NODITHER && + sp->encode_meth != SGILOGENCODE_RANDITHER) { + TIFFErrorExt(tif->tif_clientdata, module, + "Unknown encoding %d for LogLuv compression", + sp->encode_meth); + return (0); + } + return (1); + default: + return (*sp->vsetparent)(tif, tag, ap); + } +} + +static int +LogLuvVGetField(TIFF* tif, uint32 tag, va_list ap) +{ + LogLuvState *sp = (LogLuvState *)tif->tif_data; + + switch (tag) { + case TIFFTAG_SGILOGDATAFMT: + *va_arg(ap, int*) = sp->user_datafmt; + return (1); + default: + return (*sp->vgetparent)(tif, tag, ap); + } +} + +static const TIFFField LogLuvFields[] = { + { TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogDataFmt", NULL}, + { TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogEncode", NULL} +}; + +int +TIFFInitSGILog(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitSGILog"; + LogLuvState* sp; + + assert(scheme == COMPRESSION_SGILOG24 || scheme == COMPRESSION_SGILOG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, LogLuvFields, + TIFFArrayCount(LogLuvFields))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging SGILog codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8*) _TIFFmalloc(sizeof (LogLuvState)); + if (tif->tif_data == NULL) + goto bad; + sp = (LogLuvState*) tif->tif_data; + _TIFFmemset((void*)sp, 0, sizeof (*sp)); + sp->user_datafmt = SGILOGDATAFMT_UNKNOWN; + sp->encode_meth = (scheme == COMPRESSION_SGILOG24) ? + SGILOGENCODE_RANDITHER : SGILOGENCODE_NODITHER; + sp->tfunc = _logLuvNop; + + /* + * Install codec methods. + * NB: tif_decoderow & tif_encoderow are filled + * in at setup time. + */ + tif->tif_fixuptags = LogLuvFixupTags; + tif->tif_setupdecode = LogLuvSetupDecode; + tif->tif_decodestrip = LogLuvDecodeStrip; + tif->tif_decodetile = LogLuvDecodeTile; + tif->tif_setupencode = LogLuvSetupEncode; + tif->tif_encodestrip = LogLuvEncodeStrip; + tif->tif_encodetile = LogLuvEncodeTile; + tif->tif_close = LogLuvClose; + tif->tif_cleanup = LogLuvCleanup; + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = LogLuvVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = LogLuvVSetField; /* hook for codec tags */ + + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "%s: No space for LogLuv state block", tif->tif_name); + return (0); +} +#endif /* LOGLUV_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_lzw.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_lzw.c new file mode 100644 index 0000000000..5c9ab0bf74 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_lzw.c @@ -0,0 +1,1169 @@ +/* $Id: tif_lzw.c,v 1.45 2011-04-02 20:54:09 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#ifdef LZW_SUPPORT +/* + * TIFF Library. + * Rev 5.0 Lempel-Ziv & Welch Compression Support + * + * This code is derived from the compress program whose code is + * derived from software contributed to Berkeley by James A. Woods, + * derived from original work by Spencer Thomas and Joseph Orost. + * + * The original Berkeley copyright notice appears below in its entirety. + */ +#include "tif_predict.h" + +#include + +/* + * NB: The 5.0 spec describes a different algorithm than Aldus + * implements. Specifically, Aldus does code length transitions + * one code earlier than should be done (for real LZW). + * Earlier versions of this library implemented the correct + * LZW algorithm, but emitted codes in a bit order opposite + * to the TIFF spec. Thus, to maintain compatibility w/ Aldus + * we interpret MSB-LSB ordered codes to be images written w/ + * old versions of this library, but otherwise adhere to the + * Aldus "off by one" algorithm. + * + * Future revisions to the TIFF spec are expected to "clarify this issue". + */ +#define LZW_COMPAT /* include backwards compatibility code */ +/* + * Each strip of data is supposed to be terminated by a CODE_EOI. + * If the following #define is included, the decoder will also + * check for end-of-strip w/o seeing this code. This makes the + * library more robust, but also slower. + */ +#define LZW_CHECKEOS /* include checks for strips w/o EOI code */ + +#define MAXCODE(n) ((1L<<(n))-1) +/* + * The TIFF spec specifies that encoded bit + * strings range from 9 to 12 bits. + */ +#define BITS_MIN 9 /* start with 9 bits */ +#define BITS_MAX 12 /* max of 12 bit strings */ +/* predefined codes */ +#define CODE_CLEAR 256 /* code to clear string table */ +#define CODE_EOI 257 /* end-of-information code */ +#define CODE_FIRST 258 /* first free code entry */ +#define CODE_MAX MAXCODE(BITS_MAX) +#define HSIZE 9001L /* 91% occupancy */ +#define HSHIFT (13-8) +#ifdef LZW_COMPAT +/* NB: +1024 is for compatibility with old files */ +#define CSIZE (MAXCODE(BITS_MAX)+1024L) +#else +#define CSIZE (MAXCODE(BITS_MAX)+1L) +#endif + +/* + * State block for each open TIFF file using LZW + * compression/decompression. Note that the predictor + * state block must be first in this data structure. + */ +typedef struct { + TIFFPredictorState predict; /* predictor super class */ + + unsigned short nbits; /* # of bits/code */ + unsigned short maxcode; /* maximum code for lzw_nbits */ + unsigned short free_ent; /* next free entry in hash table */ + long nextdata; /* next bits of i/o */ + long nextbits; /* # of valid bits in lzw_nextdata */ + + int rw_mode; /* preserve rw_mode from init */ +} LZWBaseState; + +#define lzw_nbits base.nbits +#define lzw_maxcode base.maxcode +#define lzw_free_ent base.free_ent +#define lzw_nextdata base.nextdata +#define lzw_nextbits base.nextbits + +/* + * Encoding-specific state. + */ +typedef uint16 hcode_t; /* codes fit in 16 bits */ +typedef struct { + long hash; + hcode_t code; +} hash_t; + +/* + * Decoding-specific state. + */ +typedef struct code_ent { + struct code_ent *next; + unsigned short length; /* string len, including this token */ + unsigned char value; /* data value */ + unsigned char firstchar; /* first token of string */ +} code_t; + +typedef int (*decodeFunc)(TIFF*, uint8*, tmsize_t, uint16); + +typedef struct { + LZWBaseState base; + + /* Decoding specific data */ + long dec_nbitsmask; /* lzw_nbits 1 bits, right adjusted */ + long dec_restart; /* restart count */ +#ifdef LZW_CHECKEOS + uint64 dec_bitsleft; /* available bits in raw data */ +#endif + decodeFunc dec_decode; /* regular or backwards compatible */ + code_t* dec_codep; /* current recognized code */ + code_t* dec_oldcodep; /* previously recognized code */ + code_t* dec_free_entp; /* next free entry */ + code_t* dec_maxcodep; /* max available entry */ + code_t* dec_codetab; /* kept separate for small machines */ + + /* Encoding specific data */ + int enc_oldcode; /* last code encountered */ + long enc_checkpoint; /* point at which to clear table */ +#define CHECK_GAP 10000 /* enc_ratio check interval */ + long enc_ratio; /* current compression ratio */ + long enc_incount; /* (input) data bytes encoded */ + long enc_outcount; /* encoded (output) bytes */ + uint8* enc_rawlimit; /* bound on tif_rawdata buffer */ + hash_t* enc_hashtab; /* kept separate for small machines */ +} LZWCodecState; + +#define LZWState(tif) ((LZWBaseState*) (tif)->tif_data) +#define DecoderState(tif) ((LZWCodecState*) LZWState(tif)) +#define EncoderState(tif) ((LZWCodecState*) LZWState(tif)) + +static int LZWDecode(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s); +#ifdef LZW_COMPAT +static int LZWDecodeCompat(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s); +#endif +static void cl_hash(LZWCodecState*); + +/* + * LZW Decoder. + */ + +#ifdef LZW_CHECKEOS +/* + * This check shouldn't be necessary because each + * strip is suppose to be terminated with CODE_EOI. + */ +#define NextCode(_tif, _sp, _bp, _code, _get) { \ + if ((_sp)->dec_bitsleft < (uint64)nbits) { \ + TIFFWarningExt(_tif->tif_clientdata, module, \ + "LZWDecode: Strip %d not terminated with EOI code", \ + _tif->tif_curstrip); \ + _code = CODE_EOI; \ + } else { \ + _get(_sp,_bp,_code); \ + (_sp)->dec_bitsleft -= nbits; \ + } \ +} +#else +#define NextCode(tif, sp, bp, code, get) get(sp, bp, code) +#endif + +static int +LZWFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +static int +LZWSetupDecode(TIFF* tif) +{ + static const char module[] = "LZWSetupDecode"; + LZWCodecState* sp = DecoderState(tif); + int code; + + if( sp == NULL ) + { + /* + * Allocate state block so tag methods have storage to record + * values. + */ + tif->tif_data = (uint8*) _TIFFmalloc(sizeof(LZWCodecState)); + if (tif->tif_data == NULL) + { + TIFFErrorExt(tif->tif_clientdata, module, "No space for LZW state block"); + return (0); + } + + DecoderState(tif)->dec_codetab = NULL; + DecoderState(tif)->dec_decode = NULL; + + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + + sp = DecoderState(tif); + } + + assert(sp != NULL); + + if (sp->dec_codetab == NULL) { + sp->dec_codetab = (code_t*)_TIFFmalloc(CSIZE*sizeof (code_t)); + if (sp->dec_codetab == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for LZW code table"); + return (0); + } + /* + * Pre-load the table. + */ + code = 255; + do { + sp->dec_codetab[code].value = code; + sp->dec_codetab[code].firstchar = code; + sp->dec_codetab[code].length = 1; + sp->dec_codetab[code].next = NULL; + } while (code--); + /* + * Zero-out the unused entries + */ + _TIFFmemset(&sp->dec_codetab[CODE_CLEAR], 0, + (CODE_FIRST - CODE_CLEAR) * sizeof (code_t)); + } + return (1); +} + +/* + * Setup state for decoding a strip. + */ +static int +LZWPreDecode(TIFF* tif, uint16 s) +{ + static const char module[] = "LZWPreDecode"; + LZWCodecState *sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + if( sp->dec_codetab == NULL ) + { + tif->tif_setupdecode( tif ); + } + + /* + * Check for old bit-reversed codes. + */ + if (tif->tif_rawdata[0] == 0 && (tif->tif_rawdata[1] & 0x1)) { +#ifdef LZW_COMPAT + if (!sp->dec_decode) { + TIFFWarningExt(tif->tif_clientdata, module, + "Old-style LZW codes, convert file"); + /* + * Override default decoding methods with + * ones that deal with the old coding. + * Otherwise the predictor versions set + * above will call the compatibility routines + * through the dec_decode method. + */ + tif->tif_decoderow = LZWDecodeCompat; + tif->tif_decodestrip = LZWDecodeCompat; + tif->tif_decodetile = LZWDecodeCompat; + /* + * If doing horizontal differencing, must + * re-setup the predictor logic since we + * switched the basic decoder methods... + */ + (*tif->tif_setupdecode)(tif); + sp->dec_decode = LZWDecodeCompat; + } + sp->lzw_maxcode = MAXCODE(BITS_MIN); +#else /* !LZW_COMPAT */ + if (!sp->dec_decode) { + TIFFErrorExt(tif->tif_clientdata, module, + "Old-style LZW codes not supported"); + sp->dec_decode = LZWDecode; + } + return (0); +#endif/* !LZW_COMPAT */ + } else { + sp->lzw_maxcode = MAXCODE(BITS_MIN)-1; + sp->dec_decode = LZWDecode; + } + sp->lzw_nbits = BITS_MIN; + sp->lzw_nextbits = 0; + sp->lzw_nextdata = 0; + + sp->dec_restart = 0; + sp->dec_nbitsmask = MAXCODE(BITS_MIN); +#ifdef LZW_CHECKEOS + sp->dec_bitsleft = ((uint64)tif->tif_rawcc) << 3; +#endif + sp->dec_free_entp = sp->dec_codetab + CODE_FIRST; + /* + * Zero entries that are not yet filled in. We do + * this to guard against bogus input data that causes + * us to index into undefined entries. If you can + * come up with a way to safely bounds-check input codes + * while decoding then you can remove this operation. + */ + _TIFFmemset(sp->dec_free_entp, 0, (CSIZE-CODE_FIRST)*sizeof (code_t)); + sp->dec_oldcodep = &sp->dec_codetab[-1]; + sp->dec_maxcodep = &sp->dec_codetab[sp->dec_nbitsmask-1]; + return (1); +} + +/* + * Decode a "hunk of data". + */ +#define GetNextCode(sp, bp, code) { \ + nextdata = (nextdata<<8) | *(bp)++; \ + nextbits += 8; \ + if (nextbits < nbits) { \ + nextdata = (nextdata<<8) | *(bp)++; \ + nextbits += 8; \ + } \ + code = (hcode_t)((nextdata >> (nextbits-nbits)) & nbitsmask); \ + nextbits -= nbits; \ +} + +static void +codeLoop(TIFF* tif, const char* module) +{ + TIFFErrorExt(tif->tif_clientdata, module, + "Bogus encoding, loop in the code table; scanline %d", + tif->tif_row); +} + +static int +LZWDecode(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s) +{ + static const char module[] = "LZWDecode"; + LZWCodecState *sp = DecoderState(tif); + char *op = (char*) op0; + long occ = (long) occ0; + char *tp; + unsigned char *bp; + hcode_t code; + int len; + long nbits, nextbits, nextdata, nbitsmask; + code_t *codep, *free_entp, *maxcodep, *oldcodep; + + (void) s; + assert(sp != NULL); + assert(sp->dec_codetab != NULL); + + /* + Fail if value does not fit in long. + */ + if ((tmsize_t) occ != occ0) + return (0); + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) { + long residue; + + codep = sp->dec_codep; + residue = codep->length - sp->dec_restart; + if (residue > occ) { + /* + * Residue from previous decode is sufficient + * to satisfy decode request. Skip to the + * start of the decoded string, place decoded + * values in the output buffer, and return. + */ + sp->dec_restart += occ; + do { + codep = codep->next; + } while (--residue > occ && codep); + if (codep) { + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ && codep); + } + return (1); + } + /* + * Residue satisfies only part of the decode request. + */ + op += residue, occ -= residue; + tp = op; + do { + int t; + --tp; + t = codep->value; + codep = codep->next; + *tp = t; + } while (--residue && codep); + sp->dec_restart = 0; + } + + bp = (unsigned char *)tif->tif_rawcp; + nbits = sp->lzw_nbits; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + nbitsmask = sp->dec_nbitsmask; + oldcodep = sp->dec_oldcodep; + free_entp = sp->dec_free_entp; + maxcodep = sp->dec_maxcodep; + + while (occ > 0) { + NextCode(tif, sp, bp, code, GetNextCode); + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + free_entp = sp->dec_codetab + CODE_FIRST; + _TIFFmemset(free_entp, 0, + (CSIZE - CODE_FIRST) * sizeof (code_t)); + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask-1; + NextCode(tif, sp, bp, code, GetNextCode); + if (code == CODE_EOI) + break; + if (code >= CODE_CLEAR) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecode: Corrupted LZW table at scanline %d", + tif->tif_row); + return (0); + } + *op++ = (char)code, occ--; + oldcodep = sp->dec_codetab + code; + continue; + } + codep = sp->dec_codetab + code; + + /* + * Add the new entry to the code table. + */ + if (free_entp < &sp->dec_codetab[0] || + free_entp >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, module, + "Corrupted LZW table at scanline %d", + tif->tif_row); + return (0); + } + + free_entp->next = oldcodep; + if (free_entp->next < &sp->dec_codetab[0] || + free_entp->next >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, module, + "Corrupted LZW table at scanline %d", + tif->tif_row); + return (0); + } + free_entp->firstchar = free_entp->next->firstchar; + free_entp->length = free_entp->next->length+1; + free_entp->value = (codep < free_entp) ? + codep->firstchar : free_entp->firstchar; + if (++free_entp > maxcodep) { + if (++nbits > BITS_MAX) /* should not happen */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = sp->dec_codetab + nbitsmask-1; + } + oldcodep = codep; + if (code >= 256) { + /* + * Code maps to a string, copy string + * value to output (written in reverse). + */ + if(codep->length == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Wrong length of decoded string: " + "data probably corrupted at scanline %d", + tif->tif_row); + return (0); + } + if (codep->length > occ) { + /* + * String is too long for decode buffer, + * locate portion that will fit, copy to + * the decode buffer, and setup restart + * logic for the next decoding call. + */ + sp->dec_codep = codep; + do { + codep = codep->next; + } while (codep && codep->length > occ); + if (codep) { + sp->dec_restart = (long)occ; + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ && codep); + if (codep) + codeLoop(tif, module); + } + break; + } + len = codep->length; + tp = op + len; + do { + int t; + --tp; + t = codep->value; + codep = codep->next; + *tp = t; + } while (codep && tp > op); + if (codep) { + codeLoop(tif, module); + break; + } + assert(occ >= len); + op += len, occ -= len; + } else + *op++ = (char)code, occ--; + } + + tif->tif_rawcp = (uint8*) bp; + sp->lzw_nbits = (unsigned short) nbits; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->dec_nbitsmask = nbitsmask; + sp->dec_oldcodep = oldcodep; + sp->dec_free_entp = free_entp; + sp->dec_maxcodep = maxcodep; + + if (occ > 0) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at scanline %d (short %I64d bytes)", + tif->tif_row, (unsigned __int64) occ); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at scanline %d (short %llu bytes)", + tif->tif_row, (unsigned long long) occ); +#endif + return (0); + } + return (1); +} + +#ifdef LZW_COMPAT +/* + * Decode a "hunk of data" for old images. + */ +#define GetNextCodeCompat(sp, bp, code) { \ + nextdata |= (unsigned long) *(bp)++ << nextbits; \ + nextbits += 8; \ + if (nextbits < nbits) { \ + nextdata |= (unsigned long) *(bp)++ << nextbits;\ + nextbits += 8; \ + } \ + code = (hcode_t)(nextdata & nbitsmask); \ + nextdata >>= nbits; \ + nextbits -= nbits; \ +} + +static int +LZWDecodeCompat(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s) +{ + static const char module[] = "LZWDecodeCompat"; + LZWCodecState *sp = DecoderState(tif); + char *op = (char*) op0; + long occ = (long) occ0; + char *tp; + unsigned char *bp; + int code, nbits; + long nextbits, nextdata, nbitsmask; + code_t *codep, *free_entp, *maxcodep, *oldcodep; + + (void) s; + assert(sp != NULL); + + /* + Fail if value does not fit in long. + */ + if ((tmsize_t) occ != occ0) + return (0); + + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) { + long residue; + + codep = sp->dec_codep; + residue = codep->length - sp->dec_restart; + if (residue > occ) { + /* + * Residue from previous decode is sufficient + * to satisfy decode request. Skip to the + * start of the decoded string, place decoded + * values in the output buffer, and return. + */ + sp->dec_restart += occ; + do { + codep = codep->next; + } while (--residue > occ); + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ); + return (1); + } + /* + * Residue satisfies only part of the decode request. + */ + op += residue, occ -= residue; + tp = op; + do { + *--tp = codep->value; + codep = codep->next; + } while (--residue); + sp->dec_restart = 0; + } + + bp = (unsigned char *)tif->tif_rawcp; + nbits = sp->lzw_nbits; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + nbitsmask = sp->dec_nbitsmask; + oldcodep = sp->dec_oldcodep; + free_entp = sp->dec_free_entp; + maxcodep = sp->dec_maxcodep; + + while (occ > 0) { + NextCode(tif, sp, bp, code, GetNextCodeCompat); + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + free_entp = sp->dec_codetab + CODE_FIRST; + _TIFFmemset(free_entp, 0, + (CSIZE - CODE_FIRST) * sizeof (code_t)); + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask; + NextCode(tif, sp, bp, code, GetNextCodeCompat); + if (code == CODE_EOI) + break; + if (code >= CODE_CLEAR) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecode: Corrupted LZW table at scanline %d", + tif->tif_row); + return (0); + } + *op++ = code, occ--; + oldcodep = sp->dec_codetab + code; + continue; + } + codep = sp->dec_codetab + code; + + /* + * Add the new entry to the code table. + */ + if (free_entp < &sp->dec_codetab[0] || + free_entp >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, module, + "Corrupted LZW table at scanline %d", tif->tif_row); + return (0); + } + + free_entp->next = oldcodep; + if (free_entp->next < &sp->dec_codetab[0] || + free_entp->next >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, module, + "Corrupted LZW table at scanline %d", tif->tif_row); + return (0); + } + free_entp->firstchar = free_entp->next->firstchar; + free_entp->length = free_entp->next->length+1; + free_entp->value = (codep < free_entp) ? + codep->firstchar : free_entp->firstchar; + if (++free_entp > maxcodep) { + if (++nbits > BITS_MAX) /* should not happen */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = sp->dec_codetab + nbitsmask; + } + oldcodep = codep; + if (code >= 256) { + /* + * Code maps to a string, copy string + * value to output (written in reverse). + */ + if(codep->length == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Wrong length of decoded " + "string: data probably corrupted at scanline %d", + tif->tif_row); + return (0); + } + if (codep->length > occ) { + /* + * String is too long for decode buffer, + * locate portion that will fit, copy to + * the decode buffer, and setup restart + * logic for the next decoding call. + */ + sp->dec_codep = codep; + do { + codep = codep->next; + } while (codep->length > occ); + sp->dec_restart = occ; + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ); + break; + } + assert(occ >= codep->length); + op += codep->length, occ -= codep->length; + tp = op; + do { + *--tp = codep->value; + } while( (codep = codep->next) != NULL ); + } else + *op++ = code, occ--; + } + + tif->tif_rawcp = (uint8*) bp; + sp->lzw_nbits = nbits; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->dec_nbitsmask = nbitsmask; + sp->dec_oldcodep = oldcodep; + sp->dec_free_entp = free_entp; + sp->dec_maxcodep = maxcodep; + + if (occ > 0) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at scanline %d (short %I64d bytes)", + tif->tif_row, (unsigned __int64) occ); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at scanline %d (short %llu bytes)", + tif->tif_row, (unsigned long long) occ); +#endif + return (0); + } + return (1); +} +#endif /* LZW_COMPAT */ + +/* + * LZW Encoding. + */ + +static int +LZWSetupEncode(TIFF* tif) +{ + static const char module[] = "LZWSetupEncode"; + LZWCodecState* sp = EncoderState(tif); + + assert(sp != NULL); + sp->enc_hashtab = (hash_t*) _TIFFmalloc(HSIZE*sizeof (hash_t)); + if (sp->enc_hashtab == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for LZW hash table"); + return (0); + } + return (1); +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +LZWPreEncode(TIFF* tif, uint16 s) +{ + LZWCodecState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + + if( sp->enc_hashtab == NULL ) + { + tif->tif_setupencode( tif ); + } + + sp->lzw_nbits = BITS_MIN; + sp->lzw_maxcode = MAXCODE(BITS_MIN); + sp->lzw_free_ent = CODE_FIRST; + sp->lzw_nextbits = 0; + sp->lzw_nextdata = 0; + sp->enc_checkpoint = CHECK_GAP; + sp->enc_ratio = 0; + sp->enc_incount = 0; + sp->enc_outcount = 0; + /* + * The 4 here insures there is space for 2 max-sized + * codes in LZWEncode and LZWPostDecode. + */ + sp->enc_rawlimit = tif->tif_rawdata + tif->tif_rawdatasize-1 - 4; + cl_hash(sp); /* clear hash table */ + sp->enc_oldcode = (hcode_t) -1; /* generates CODE_CLEAR in LZWEncode */ + return (1); +} + +#define CALCRATIO(sp, rat) { \ + if (incount > 0x007fffff) { /* NB: shift will overflow */\ + rat = outcount >> 8; \ + rat = (rat == 0 ? 0x7fffffff : incount/rat); \ + } else \ + rat = (incount<<8) / outcount; \ +} +#define PutNextCode(op, c) { \ + nextdata = (nextdata << nbits) | c; \ + nextbits += nbits; \ + *op++ = (unsigned char)(nextdata >> (nextbits-8)); \ + nextbits -= 8; \ + if (nextbits >= 8) { \ + *op++ = (unsigned char)(nextdata >> (nextbits-8)); \ + nextbits -= 8; \ + } \ + outcount += nbits; \ +} + +/* + * Encode a chunk of pixels. + * + * Uses an open addressing double hashing (no chaining) on the + * prefix code/next character combination. We do a variant of + * Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's + * relatively-prime secondary probe. Here, the modular division + * first probe is gives way to a faster exclusive-or manipulation. + * Also do block compression with an adaptive reset, whereby the + * code table is cleared when the compression ratio decreases, + * but after the table fills. The variable-length output codes + * are re-sized at this point, and a CODE_CLEAR is generated + * for the decoder. + */ +static int +LZWEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + register LZWCodecState *sp = EncoderState(tif); + register long fcode; + register hash_t *hp; + register int h, c; + hcode_t ent; + long disp; + long incount, outcount, checkpoint; + long nextdata, nextbits; + int free_ent, maxcode, nbits; + uint8* op; + uint8* limit; + + (void) s; + if (sp == NULL) + return (0); + + assert(sp->enc_hashtab != NULL); + + /* + * Load local state. + */ + incount = sp->enc_incount; + outcount = sp->enc_outcount; + checkpoint = sp->enc_checkpoint; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + free_ent = sp->lzw_free_ent; + maxcode = sp->lzw_maxcode; + nbits = sp->lzw_nbits; + op = tif->tif_rawcp; + limit = sp->enc_rawlimit; + ent = sp->enc_oldcode; + + if (ent == (hcode_t) -1 && cc > 0) { + /* + * NB: This is safe because it can only happen + * at the start of a strip where we know there + * is space in the data buffer. + */ + PutNextCode(op, CODE_CLEAR); + ent = *bp++; cc--; incount++; + } + while (cc > 0) { + c = *bp++; cc--; incount++; + fcode = ((long)c << BITS_MAX) + ent; + h = (c << HSHIFT) ^ ent; /* xor hashing */ +#ifdef _WINDOWS + /* + * Check hash index for an overflow. + */ + if (h >= HSIZE) + h -= HSIZE; +#endif + hp = &sp->enc_hashtab[h]; + if (hp->hash == fcode) { + ent = hp->code; + continue; + } + if (hp->hash >= 0) { + /* + * Primary hash failed, check secondary hash. + */ + disp = HSIZE - h; + if (h == 0) + disp = 1; + do { + /* + * Avoid pointer arithmetic 'cuz of + * wraparound problems with segments. + */ + if ((h -= disp) < 0) + h += HSIZE; + hp = &sp->enc_hashtab[h]; + if (hp->hash == fcode) { + ent = hp->code; + goto hit; + } + } while (hp->hash >= 0); + } + /* + * New entry, emit code and add to table. + */ + /* + * Verify there is space in the buffer for the code + * and any potential Clear code that might be emitted + * below. The value of limit is setup so that there + * are at least 4 bytes free--room for 2 codes. + */ + if (op > limit) { + tif->tif_rawcc = (tmsize_t)(op - tif->tif_rawdata); + TIFFFlushData1(tif); + op = tif->tif_rawdata; + } + PutNextCode(op, ent); + ent = c; + hp->code = free_ent++; + hp->hash = fcode; + if (free_ent == CODE_MAX-1) { + /* table is full, emit clear code and reset */ + cl_hash(sp); + sp->enc_ratio = 0; + incount = 0; + outcount = 0; + free_ent = CODE_FIRST; + PutNextCode(op, CODE_CLEAR); + nbits = BITS_MIN; + maxcode = MAXCODE(BITS_MIN); + } else { + /* + * If the next entry is going to be too big for + * the code size, then increase it, if possible. + */ + if (free_ent > maxcode) { + nbits++; + assert(nbits <= BITS_MAX); + maxcode = (int) MAXCODE(nbits); + } else if (incount >= checkpoint) { + long rat; + /* + * Check compression ratio and, if things seem + * to be slipping, clear the hash table and + * reset state. The compression ratio is a + * 24+8-bit fractional number. + */ + checkpoint = incount+CHECK_GAP; + CALCRATIO(sp, rat); + if (rat <= sp->enc_ratio) { + cl_hash(sp); + sp->enc_ratio = 0; + incount = 0; + outcount = 0; + free_ent = CODE_FIRST; + PutNextCode(op, CODE_CLEAR); + nbits = BITS_MIN; + maxcode = MAXCODE(BITS_MIN); + } else + sp->enc_ratio = rat; + } + } + hit: + ; + } + + /* + * Restore global state. + */ + sp->enc_incount = incount; + sp->enc_outcount = outcount; + sp->enc_checkpoint = checkpoint; + sp->enc_oldcode = ent; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->lzw_free_ent = free_ent; + sp->lzw_maxcode = maxcode; + sp->lzw_nbits = nbits; + tif->tif_rawcp = op; + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ +static int +LZWPostEncode(TIFF* tif) +{ + register LZWCodecState *sp = EncoderState(tif); + uint8* op = tif->tif_rawcp; + long nextbits = sp->lzw_nextbits; + long nextdata = sp->lzw_nextdata; + long outcount = sp->enc_outcount; + int nbits = sp->lzw_nbits; + + if (op > sp->enc_rawlimit) { + tif->tif_rawcc = (tmsize_t)(op - tif->tif_rawdata); + TIFFFlushData1(tif); + op = tif->tif_rawdata; + } + if (sp->enc_oldcode != (hcode_t) -1) { + PutNextCode(op, sp->enc_oldcode); + sp->enc_oldcode = (hcode_t) -1; + } + PutNextCode(op, CODE_EOI); + if (nextbits > 0) + *op++ = (unsigned char)(nextdata << (8-nextbits)); + tif->tif_rawcc = (tmsize_t)(op - tif->tif_rawdata); + return (1); +} + +/* + * Reset encoding hash table. + */ +static void +cl_hash(LZWCodecState* sp) +{ + register hash_t *hp = &sp->enc_hashtab[HSIZE-1]; + register long i = HSIZE-8; + + do { + i -= 8; + hp[-7].hash = -1; + hp[-6].hash = -1; + hp[-5].hash = -1; + hp[-4].hash = -1; + hp[-3].hash = -1; + hp[-2].hash = -1; + hp[-1].hash = -1; + hp[ 0].hash = -1; + hp -= 8; + } while (i >= 0); + for (i += 8; i > 0; i--, hp--) + hp->hash = -1; +} + +static void +LZWCleanup(TIFF* tif) +{ + (void)TIFFPredictorCleanup(tif); + + assert(tif->tif_data != 0); + + if (DecoderState(tif)->dec_codetab) + _TIFFfree(DecoderState(tif)->dec_codetab); + + if (EncoderState(tif)->enc_hashtab) + _TIFFfree(EncoderState(tif)->enc_hashtab); + + _TIFFfree(tif->tif_data); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +int +TIFFInitLZW(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitLZW"; + assert(scheme == COMPRESSION_LZW); + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8*) _TIFFmalloc(sizeof (LZWCodecState)); + if (tif->tif_data == NULL) + goto bad; + DecoderState(tif)->dec_codetab = NULL; + DecoderState(tif)->dec_decode = NULL; + EncoderState(tif)->enc_hashtab = NULL; + LZWState(tif)->rw_mode = tif->tif_mode; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = LZWFixupTags; + tif->tif_setupdecode = LZWSetupDecode; + tif->tif_predecode = LZWPreDecode; + tif->tif_decoderow = LZWDecode; + tif->tif_decodestrip = LZWDecode; + tif->tif_decodetile = LZWDecode; + tif->tif_setupencode = LZWSetupEncode; + tif->tif_preencode = LZWPreEncode; + tif->tif_postencode = LZWPostEncode; + tif->tif_encoderow = LZWEncode; + tif->tif_encodestrip = LZWEncode; + tif->tif_encodetile = LZWEncode; + tif->tif_cleanup = LZWCleanup; + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "No space for LZW state block"); + return (0); +} + +/* + * Copyright (c) 1985, 1986 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods, derived from original work by Spencer Thomas + * and Joseph Orost. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#endif /* LZW_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_next.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_next.c new file mode 100644 index 0000000000..8c4fec456f --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_next.c @@ -0,0 +1,162 @@ +/* $Id: tif_next.c,v 1.13 2010-03-10 18:56:48 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#ifdef NEXT_SUPPORT +/* + * TIFF Library. + * + * NeXT 2-bit Grey Scale Compression Algorithm Support + */ + +#define SETPIXEL(op, v) { \ + switch (npixels++ & 3) { \ + case 0: op[0] = (unsigned char) ((v) << 6); break; \ + case 1: op[0] |= (v) << 4; break; \ + case 2: op[0] |= (v) << 2; break; \ + case 3: *op++ |= (v); break; \ + } \ +} + +#define LITERALROW 0x00 +#define LITERALSPAN 0x40 +#define WHITE ((1<<2)-1) + +static int +NeXTDecode(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s) +{ + static const char module[] = "NeXTDecode"; + unsigned char *bp, *op; + tmsize_t cc; + uint8* row; + tmsize_t scanline, n; + + (void) s; + /* + * Each scanline is assumed to start off as all + * white (we assume a PhotometricInterpretation + * of ``min-is-black''). + */ + for (op = (unsigned char*) buf, cc = occ; cc-- > 0;) + *op++ = 0xff; + + bp = (unsigned char *)tif->tif_rawcp; + cc = tif->tif_rawcc; + scanline = tif->tif_scanlinesize; + if (occ % scanline) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (0); + } + for (row = buf; occ > 0; occ -= scanline, row += scanline) { + n = *bp++, cc--; + switch (n) { + case LITERALROW: + /* + * The entire scanline is given as literal values. + */ + if (cc < scanline) + goto bad; + _TIFFmemcpy(row, bp, scanline); + bp += scanline; + cc -= scanline; + break; + case LITERALSPAN: { + tmsize_t off; + /* + * The scanline has a literal span that begins at some + * offset. + */ + off = (bp[0] * 256) + bp[1]; + n = (bp[2] * 256) + bp[3]; + if (cc < 4+n || off+n > scanline) + goto bad; + _TIFFmemcpy(row+off, bp+4, n); + bp += 4+n; + cc -= 4+n; + break; + } + default: { + uint32 npixels = 0, grey; + uint32 imagewidth = tif->tif_dir.td_imagewidth; + + /* + * The scanline is composed of a sequence of constant + * color ``runs''. We shift into ``run mode'' and + * interpret bytes as codes of the form + * until we've filled the scanline. + */ + op = row; + for (;;) { + grey = (uint32)((n>>6) & 0x3); + n &= 0x3f; + /* + * Ensure the run does not exceed the scanline + * bounds, potentially resulting in a security + * issue. + */ + while (n-- > 0 && npixels < imagewidth) + SETPIXEL(op, grey); + if (npixels >= imagewidth) + break; + if (cc == 0) + goto bad; + n = *bp++, cc--; + } + break; + } + } + } + tif->tif_rawcp = (uint8*) bp; + tif->tif_rawcc = cc; + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, "Not enough data for scanline %ld", + (long) tif->tif_row); + return (0); +} + +int +TIFFInitNeXT(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_decoderow = NeXTDecode; + tif->tif_decodestrip = NeXTDecode; + tif->tif_decodetile = NeXTDecode; + return (1); +} +#endif /* NEXT_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_ojpeg.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_ojpeg.c new file mode 100644 index 0000000000..bed4f9be7e --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_ojpeg.c @@ -0,0 +1,2506 @@ +/* $Id: tif_ojpeg.c,v 1.56 2012-05-24 03:15:18 fwarmerdam Exp $ */ + +/* WARNING: The type of JPEG encapsulation defined by the TIFF Version 6.0 + specification is now totally obsolete and deprecated for new applications and + images. This file was was created solely in order to read unconverted images + still present on some users' computer systems. It will never be extended + to write such files. Writing new-style JPEG compressed TIFFs is implemented + in tif_jpeg.c. + + The code is carefully crafted to robustly read all gathered JPEG-in-TIFF + testfiles, and anticipate as much as possible all other... But still, it may + fail on some. If you encounter problems, please report them on the TIFF + mailing list and/or to Joris Van Damme . + + Please read the file called "TIFF Technical Note #2" if you need to be + convinced this compression scheme is bad and breaks TIFF. That document + is linked to from the LibTiff site + and from AWare Systems' TIFF section + . It is also absorbed + in Adobe's specification supplements, marked "draft" up to this day, but + supported by the TIFF community. + + This file interfaces with Release 6B of the JPEG Library written by the + Independent JPEG Group. Previous versions of this file required a hack inside + the LibJpeg library. This version no longer requires that. Remember to + remove the hack if you update from the old version. + + Copyright (c) Joris Van Damme + Copyright (c) AWare Systems + + The licence agreement for this file is the same as the rest of the LibTiff + library. + + IN NO EVENT SHALL JORIS VAN DAMME OR AWARE SYSTEMS BE LIABLE FOR + ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + OF THIS SOFTWARE. + + Joris Van Damme and/or AWare Systems may be available for custom + developement. If you like what you see, and need anything similar or related, + contact . +*/ + +/* What is what, and what is not? + + This decoder starts with an input stream, that is essentially the JpegInterchangeFormat + stream, if any, followed by the strile data, if any. This stream is read in + OJPEGReadByte and related functions. + + It analyzes the start of this stream, until it encounters non-marker data, i.e. + compressed image data. Some of the header markers it sees have no actual content, + like the SOI marker, and APP/COM markers that really shouldn't even be there. Some + other markers do have content, and the valuable bits and pieces of information + in these markers are saved, checking all to verify that the stream is more or + less within expected bounds. This happens inside the OJPEGReadHeaderInfoSecStreamXxx + functions. + + Some OJPEG imagery contains no valid JPEG header markers. This situation is picked + up on if we've seen no SOF marker when we're at the start of the compressed image + data. In this case, the tables are read from JpegXxxTables tags, and the other + bits and pieces of information is initialized to its most basic value. This is + implemented in the OJPEGReadHeaderInfoSecTablesXxx functions. + + When this is complete, a good and valid JPEG header can be assembled, and this is + passed through to LibJpeg. When that's done, the remainder of the input stream, i.e. + the compressed image data, can be passed through unchanged. This is done in + OJPEGWriteStream functions. + + LibTiff rightly expects to know the subsampling values before decompression. Just like + in new-style JPEG-in-TIFF, though, or even more so, actually, the YCbCrsubsampling + tag is notoriously unreliable. To correct these tag values with the ones inside + the JPEG stream, the first part of the input stream is pre-scanned in + OJPEGSubsamplingCorrect, making no note of any other data, reporting no warnings + or errors, up to the point where either these values are read, or it's clear they + aren't there. This means that some of the data is read twice, but we feel speed + in correcting these values is important enough to warrant this sacrifice. Allthough + there is currently no define or other configuration mechanism to disable this behaviour, + the actual header scanning is build to robustly respond with error report if it + should encounter an uncorrected mismatch of subsampling values. See + OJPEGReadHeaderInfoSecStreamSof. + + The restart interval and restart markers are the most tricky part... The restart + interval can be specified in a tag. It can also be set inside the input JPEG stream. + It can be used inside the input JPEG stream. If reading from strile data, we've + consistenly discovered the need to insert restart markers in between the different + striles, as is also probably the most likely interpretation of the original TIFF 6.0 + specification. With all this setting of interval, and actual use of markers that is not + predictable at the time of valid JPEG header assembly, the restart thing may turn + out the Achilles heel of this implementation. Fortunately, most OJPEG writer vendors + succeed in reading back what they write, which may be the reason why we've been able + to discover ways that seem to work. + + Some special provision is made for planarconfig separate OJPEG files. These seem + to consistently contain header info, a SOS marker, a plane, SOS marker, plane, SOS, + and plane. This may or may not be a valid JPEG configuration, we don't know and don't + care. We want LibTiff to be able to access the planes individually, without huge + buffering inside LibJpeg, anyway. So we compose headers to feed to LibJpeg, in this + case, that allow us to pass a single plane such that LibJpeg sees a valid + single-channel JPEG stream. Locating subsequent SOS markers, and thus subsequent + planes, is done inside OJPEGReadSecondarySos. + + The benefit of the scheme is... that it works, basically. We know of no other that + does. It works without checking software tag, or otherwise going about things in an + OJPEG flavor specific manner. Instead, it is a single scheme, that covers the cases + with and without JpegInterchangeFormat, with and without striles, with part of + the header in JpegInterchangeFormat and remainder in first strile, etc. It is forgiving + and robust, may likely work with OJPEG flavors we've not seen yet, and makes most out + of the data. + + Another nice side-effect is that a complete JPEG single valid stream is build if + planarconfig is not separate (vast majority). We may one day use that to build + converters to JPEG, and/or to new-style JPEG compression inside TIFF. + + A dissadvantage is the lack of random access to the individual striles. This is the + reason for much of the complicated restart-and-position stuff inside OJPEGPreDecode. + Applications would do well accessing all striles in order, as this will result in + a single sequential scan of the input stream, and no restarting of LibJpeg decoding + session. +*/ + +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) + +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN + +#include "tiffiop.h" +#ifdef OJPEG_SUPPORT + +/* Configuration defines here are: + * JPEG_ENCAP_EXTERNAL: The normal way to call libjpeg, uses longjump. In some environments, + * like eg LibTiffDelphi, this is not possible. For this reason, the actual calls to + * libjpeg, with longjump stuff, are encapsulated in dedicated functions. When + * JPEG_ENCAP_EXTERNAL is defined, these encapsulating functions are declared external + * to this unit, and can be defined elsewhere to use stuff other then longjump. + * The default mode, without JPEG_ENCAP_EXTERNAL, implements the call encapsulators + * here, internally, with normal longjump. + * SETJMP, LONGJMP, JMP_BUF: On some machines/environments a longjump equivalent is + * conviniently available, but still it may be worthwhile to use _setjmp or sigsetjmp + * in place of plain setjmp. These macros will make it easier. It is useless + * to fiddle with these if you define JPEG_ENCAP_EXTERNAL. + * OJPEG_BUFFER: Define the size of the desired buffer here. Should be small enough so as to guarantee + * instant processing, optimal streaming and optimal use of processor cache, but also big + * enough so as to not result in significant call overhead. It should be at least a few + * bytes to accomodate some structures (this is verified in asserts), but it would not be + * sensible to make it this small anyway, and it should be at most 64K since it is indexed + * with uint16. We recommend 2K. + * EGYPTIANWALK: You could also define EGYPTIANWALK here, but it is not used anywhere and has + * absolutely no effect. That is why most people insist the EGYPTIANWALK is a bit silly. + */ + +/* define LIBJPEG_ENCAP_EXTERNAL */ +#define SETJMP(jbuf) setjmp(jbuf) +#define LONGJMP(jbuf,code) longjmp(jbuf,code) +#define JMP_BUF jmp_buf +#define OJPEG_BUFFER 2048 +/* define EGYPTIANWALK */ + +#define JPEG_MARKER_SOF0 0xC0 +#define JPEG_MARKER_SOF1 0xC1 +#define JPEG_MARKER_SOF3 0xC3 +#define JPEG_MARKER_DHT 0xC4 +#define JPEG_MARKER_RST0 0XD0 +#define JPEG_MARKER_SOI 0xD8 +#define JPEG_MARKER_EOI 0xD9 +#define JPEG_MARKER_SOS 0xDA +#define JPEG_MARKER_DQT 0xDB +#define JPEG_MARKER_DRI 0xDD +#define JPEG_MARKER_APP0 0xE0 +#define JPEG_MARKER_COM 0xFE + +#define FIELD_OJPEG_JPEGINTERCHANGEFORMAT (FIELD_CODEC+0) +#define FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH (FIELD_CODEC+1) +#define FIELD_OJPEG_JPEGQTABLES (FIELD_CODEC+2) +#define FIELD_OJPEG_JPEGDCTABLES (FIELD_CODEC+3) +#define FIELD_OJPEG_JPEGACTABLES (FIELD_CODEC+4) +#define FIELD_OJPEG_JPEGPROC (FIELD_CODEC+5) +#define FIELD_OJPEG_JPEGRESTARTINTERVAL (FIELD_CODEC+6) + +static const TIFFField ojpegFields[] = { + {TIFFTAG_JPEGIFOFFSET,1,1,TIFF_LONG8,0,TIFF_SETGET_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGINTERCHANGEFORMAT,TRUE,FALSE,"JpegInterchangeFormat",NULL}, + {TIFFTAG_JPEGIFBYTECOUNT,1,1,TIFF_LONG8,0,TIFF_SETGET_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH,TRUE,FALSE,"JpegInterchangeFormatLength",NULL}, + {TIFFTAG_JPEGQTABLES,TIFF_VARIABLE2,TIFF_VARIABLE2,TIFF_LONG8,0,TIFF_SETGET_C32_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGQTABLES,FALSE,TRUE,"JpegQTables",NULL}, + {TIFFTAG_JPEGDCTABLES,TIFF_VARIABLE2,TIFF_VARIABLE2,TIFF_LONG8,0,TIFF_SETGET_C32_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGDCTABLES,FALSE,TRUE,"JpegDcTables",NULL}, + {TIFFTAG_JPEGACTABLES,TIFF_VARIABLE2,TIFF_VARIABLE2,TIFF_LONG8,0,TIFF_SETGET_C32_UINT64,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGACTABLES,FALSE,TRUE,"JpegAcTables",NULL}, + {TIFFTAG_JPEGPROC,1,1,TIFF_SHORT,0,TIFF_SETGET_UINT16,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGPROC,FALSE,FALSE,"JpegProc",NULL}, + {TIFFTAG_JPEGRESTARTINTERVAL,1,1,TIFF_SHORT,0,TIFF_SETGET_UINT16,TIFF_SETGET_UNDEFINED,FIELD_OJPEG_JPEGRESTARTINTERVAL,FALSE,FALSE,"JpegRestartInterval",NULL}, +}; + +#ifndef LIBJPEG_ENCAP_EXTERNAL +#include +#endif + +/* We undefine FAR to avoid conflict with JPEG definition */ + +#ifdef FAR +#undef FAR +#endif + +/* + Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is + not defined. Unfortunately, the MinGW and Borland compilers include + a typedef for INT32, which causes a conflict. MSVC does not include + a conficting typedef given the headers which are included. +*/ +#if defined(__BORLANDC__) || defined(__MINGW32__) +# define XMD_H 1 +#endif + +/* Define "boolean" as unsigned char, not int, per Windows custom. */ +#if defined(__WIN32__) && !defined(__MINGW32__) +# ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ + typedef unsigned char boolean; +# endif +# define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +#endif + +#ifndef _FX_JPEG_TURBO_ + #include "../../libjpeg/jpeglib.h" + #include "../../libjpeg/jerror.h" +#else + #include "../../libjpeg-turbo/jpeglib.h" + #include "../../libjpeg-turbo/jerror.h" +#endif//_FX_JPEG_TURBO_ + +typedef struct jpeg_error_mgr jpeg_error_mgr; +typedef struct jpeg_common_struct jpeg_common_struct; +typedef struct jpeg_decompress_struct jpeg_decompress_struct; +typedef struct jpeg_source_mgr jpeg_source_mgr; + +typedef enum { + osibsNotSetYet, + osibsJpegInterchangeFormat, + osibsStrile, + osibsEof +} OJPEGStateInBufferSource; + +typedef enum { + ososSoi, + ososQTable0,ososQTable1,ososQTable2,ososQTable3, + ososDcTable0,ososDcTable1,ososDcTable2,ososDcTable3, + ososAcTable0,ososAcTable1,ososAcTable2,ososAcTable3, + ososDri, + ososSof, + ososSos, + ososCompressed, + ososRst, + ososEoi +} OJPEGStateOutState; + +typedef struct { + TIFF* tif; + #ifndef LIBJPEG_ENCAP_EXTERNAL + JMP_BUF exit_jmpbuf; + #endif + TIFFVGetMethod vgetparent; + TIFFVSetMethod vsetparent; + TIFFPrintMethod printdir; + uint64 file_size; + uint32 image_width; + uint32 image_length; + uint32 strile_width; + uint32 strile_length; + uint32 strile_length_total; + uint8 samples_per_pixel; + uint8 plane_sample_offset; + uint8 samples_per_pixel_per_plane; + uint64 jpeg_interchange_format; + uint64 jpeg_interchange_format_length; + uint8 jpeg_proc; + uint8 subsamplingcorrect; + uint8 subsamplingcorrect_done; + uint8 subsampling_tag; + uint8 subsampling_hor; + uint8 subsampling_ver; + uint8 subsampling_force_desubsampling_inside_decompression; + uint8 qtable_offset_count; + uint8 dctable_offset_count; + uint8 actable_offset_count; + uint64 qtable_offset[3]; + uint64 dctable_offset[3]; + uint64 actable_offset[3]; + uint8* qtable[4]; + uint8* dctable[4]; + uint8* actable[4]; + uint16 restart_interval; + uint8 restart_index; + uint8 sof_log; + uint8 sof_marker_id; + uint32 sof_x; + uint32 sof_y; + uint8 sof_c[3]; + uint8 sof_hv[3]; + uint8 sof_tq[3]; + uint8 sos_cs[3]; + uint8 sos_tda[3]; + struct { + uint8 log; + OJPEGStateInBufferSource in_buffer_source; + uint32 in_buffer_next_strile; + uint64 in_buffer_file_pos; + uint64 in_buffer_file_togo; + } sos_end[3]; + uint8 readheader_done; + uint8 writeheader_done; + uint16 write_cursample; + uint32 write_curstrile; + uint8 libjpeg_session_active; + uint8 libjpeg_jpeg_query_style; + jpeg_error_mgr libjpeg_jpeg_error_mgr; + jpeg_decompress_struct libjpeg_jpeg_decompress_struct; + jpeg_source_mgr libjpeg_jpeg_source_mgr; + uint8 subsampling_convert_log; + uint32 subsampling_convert_ylinelen; + uint32 subsampling_convert_ylines; + uint32 subsampling_convert_clinelen; + uint32 subsampling_convert_clines; + uint32 subsampling_convert_ybuflen; + uint32 subsampling_convert_cbuflen; + uint32 subsampling_convert_ycbcrbuflen; + uint8* subsampling_convert_ycbcrbuf; + uint8* subsampling_convert_ybuf; + uint8* subsampling_convert_cbbuf; + uint8* subsampling_convert_crbuf; + uint32 subsampling_convert_ycbcrimagelen; + uint8** subsampling_convert_ycbcrimage; + uint32 subsampling_convert_clinelenout; + uint32 subsampling_convert_state; + uint32 bytes_per_line; /* if the codec outputs subsampled data, a 'line' in bytes_per_line */ + uint32 lines_per_strile; /* and lines_per_strile means subsampling_ver desubsampled rows */ + OJPEGStateInBufferSource in_buffer_source; + uint32 in_buffer_next_strile; + uint32 in_buffer_strile_count; + uint64 in_buffer_file_pos; + uint8 in_buffer_file_pos_log; + uint64 in_buffer_file_togo; + uint16 in_buffer_togo; + uint8* in_buffer_cur; + uint8 in_buffer[OJPEG_BUFFER]; + OJPEGStateOutState out_state; + uint8 out_buffer[OJPEG_BUFFER]; + uint8* skip_buffer; +} OJPEGState; + +static int OJPEGVGetField(TIFF* tif, uint32 tag, va_list ap); +static int OJPEGVSetField(TIFF* tif, uint32 tag, va_list ap); +static void OJPEGPrintDir(TIFF* tif, FILE* fd, long flags); + +static int OJPEGFixupTags(TIFF* tif); +static int OJPEGSetupDecode(TIFF* tif); +static int OJPEGPreDecode(TIFF* tif, uint16 s); +static int OJPEGPreDecodeSkipRaw(TIFF* tif); +static int OJPEGPreDecodeSkipScanlines(TIFF* tif); +static int OJPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s); +static int OJPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc); +static int OJPEGDecodeScanlines(TIFF* tif, uint8* buf, tmsize_t cc); +static void OJPEGPostDecode(TIFF* tif, uint8* buf, tmsize_t cc); +static int OJPEGSetupEncode(TIFF* tif); +static int OJPEGPreEncode(TIFF* tif, uint16 s); +static int OJPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s); +static int OJPEGPostEncode(TIFF* tif); +static void OJPEGCleanup(TIFF* tif); + +static void OJPEGSubsamplingCorrect(TIFF* tif); +static int OJPEGReadHeaderInfo(TIFF* tif); +static int OJPEGReadSecondarySos(TIFF* tif, uint16 s); +static int OJPEGWriteHeaderInfo(TIFF* tif); +static void OJPEGLibjpegSessionAbort(TIFF* tif); + +static int OJPEGReadHeaderInfoSec(TIFF* tif); +static int OJPEGReadHeaderInfoSecStreamDri(TIFF* tif); +static int OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif); +static int OJPEGReadHeaderInfoSecStreamDht(TIFF* tif); +static int OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id); +static int OJPEGReadHeaderInfoSecStreamSos(TIFF* tif); +static int OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif); +static int OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif); +static int OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif); + +static int OJPEGReadBufferFill(OJPEGState* sp); +static int OJPEGReadByte(OJPEGState* sp, uint8* byte); +static int OJPEGReadBytePeek(OJPEGState* sp, uint8* byte); +static void OJPEGReadByteAdvance(OJPEGState* sp); +static int OJPEGReadWord(OJPEGState* sp, uint16* word); +static int OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem); +static void OJPEGReadSkip(OJPEGState* sp, uint16 len); + +static int OJPEGWriteStream(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); +static void OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); +static void OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); +static void OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len); +static int OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len); +static void OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len); + +#ifdef LIBJPEG_ENCAP_EXTERNAL +extern int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); +extern int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image); +extern int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); +extern int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines); +extern int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines); +extern void jpeg_encap_unwind(TIFF* tif); +#else +static int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* j); +static int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image); +static int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); +static int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines); +static int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines); +static void jpeg_encap_unwind(TIFF* tif); +#endif + +static void OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo); +static void OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo); +static void OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo); +static boolean OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo); +static void OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes); +static boolean OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired); +static void OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo); + +int +TIFFInitOJPEG(TIFF* tif, int scheme) +{ + static const char module[]="TIFFInitOJPEG"; + OJPEGState* sp; + + assert(scheme==COMPRESSION_OJPEG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, ojpegFields, TIFFArrayCount(ojpegFields))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging Old JPEG codec-specific tags failed"); + return 0; + } + + /* state block */ + sp = (OJPEGState*)_TIFFmalloc(sizeof(OJPEGState)); // // add (OJPEGState*) cast + if (sp == NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"No space for OJPEG state block"); + return(0); + } + _TIFFmemset(sp,0,sizeof(OJPEGState)); + sp->tif=tif; + sp->jpeg_proc=1; + sp->subsampling_hor=2; + sp->subsampling_ver=2; + TIFFSetField(tif,TIFFTAG_YCBCRSUBSAMPLING,2,2); + /* tif codec methods */ + tif->tif_fixuptags=OJPEGFixupTags; + tif->tif_setupdecode=OJPEGSetupDecode; + tif->tif_predecode=OJPEGPreDecode; + tif->tif_postdecode=OJPEGPostDecode; + tif->tif_decoderow=OJPEGDecode; + tif->tif_decodestrip=OJPEGDecode; + tif->tif_decodetile=OJPEGDecode; + tif->tif_setupencode=OJPEGSetupEncode; + tif->tif_preencode=OJPEGPreEncode; + tif->tif_postencode=OJPEGPostEncode; + tif->tif_encoderow=OJPEGEncode; + tif->tif_encodestrip=OJPEGEncode; + tif->tif_encodetile=OJPEGEncode; + tif->tif_cleanup=OJPEGCleanup; + tif->tif_data=(uint8*)sp; + /* tif tag methods */ + sp->vgetparent=tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield=OJPEGVGetField; + sp->vsetparent=tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield=OJPEGVSetField; + sp->printdir=tif->tif_tagmethods.printdir; + tif->tif_tagmethods.printdir=OJPEGPrintDir; + /* Some OJPEG files don't have strip or tile offsets or bytecounts tags. + Some others do, but have totally meaningless or corrupt values + in these tags. In these cases, the JpegInterchangeFormat stream is + reliable. In any case, this decoder reads the compressed data itself, + from the most reliable locations, and we need to notify encapsulating + LibTiff not to read raw strips or tiles for us. */ + tif->tif_flags|=TIFF_NOREADRAW; + return(1); +} + +static int +OJPEGVGetField(TIFF* tif, uint32 tag, va_list ap) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + switch(tag) + { + case TIFFTAG_JPEGIFOFFSET: + *va_arg(ap,uint64*)=(uint64)sp->jpeg_interchange_format; + break; + case TIFFTAG_JPEGIFBYTECOUNT: + *va_arg(ap,uint64*)=(uint64)sp->jpeg_interchange_format_length; + break; + case TIFFTAG_YCBCRSUBSAMPLING: + if (sp->subsamplingcorrect_done==0) + OJPEGSubsamplingCorrect(tif); + *va_arg(ap,uint16*)=(uint16)sp->subsampling_hor; + *va_arg(ap,uint16*)=(uint16)sp->subsampling_ver; + break; + case TIFFTAG_JPEGQTABLES: + *va_arg(ap,uint32*)=(uint32)sp->qtable_offset_count; + *va_arg(ap,void**)=(void*)sp->qtable_offset; + break; + case TIFFTAG_JPEGDCTABLES: + *va_arg(ap,uint32*)=(uint32)sp->dctable_offset_count; + *va_arg(ap,void**)=(void*)sp->dctable_offset; + break; + case TIFFTAG_JPEGACTABLES: + *va_arg(ap,uint32*)=(uint32)sp->actable_offset_count; + *va_arg(ap,void**)=(void*)sp->actable_offset; + break; + case TIFFTAG_JPEGPROC: + *va_arg(ap,uint16*)=(uint16)sp->jpeg_proc; + break; + case TIFFTAG_JPEGRESTARTINTERVAL: + *va_arg(ap,uint16*)=sp->restart_interval; + break; + default: + return (*sp->vgetparent)(tif,tag,ap); + } + return (1); +} + +static int +OJPEGVSetField(TIFF* tif, uint32 tag, va_list ap) +{ + static const char module[]="OJPEGVSetField"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint32 ma; + uint64* mb; + uint32 n; + switch(tag) + { + case TIFFTAG_JPEGIFOFFSET: + sp->jpeg_interchange_format=(uint64)va_arg(ap,uint64); + break; + case TIFFTAG_JPEGIFBYTECOUNT: + sp->jpeg_interchange_format_length=(uint64)va_arg(ap,uint64); + break; + case TIFFTAG_YCBCRSUBSAMPLING: + sp->subsampling_tag=1; + sp->subsampling_hor=(uint8)va_arg(ap,uint16_vap); + sp->subsampling_ver=(uint8)va_arg(ap,uint16_vap); + tif->tif_dir.td_ycbcrsubsampling[0]=sp->subsampling_hor; + tif->tif_dir.td_ycbcrsubsampling[1]=sp->subsampling_ver; + break; + case TIFFTAG_JPEGQTABLES: + ma=(uint32)va_arg(ap,uint32); + if (ma!=0) + { + if (ma>3) + { + TIFFErrorExt(tif->tif_clientdata,module,"JpegQTables tag has incorrect count"); + return(0); + } + sp->qtable_offset_count=(uint8)ma; + mb=(uint64*)va_arg(ap,uint64*); + for (n=0; nqtable_offset[n]=mb[n]; + } + break; + case TIFFTAG_JPEGDCTABLES: + ma=(uint32)va_arg(ap,uint32); + if (ma!=0) + { + if (ma>3) + { + TIFFErrorExt(tif->tif_clientdata,module,"JpegDcTables tag has incorrect count"); + return(0); + } + sp->dctable_offset_count=(uint8)ma; + mb=(uint64*)va_arg(ap,uint64*); + for (n=0; ndctable_offset[n]=mb[n]; + } + break; + case TIFFTAG_JPEGACTABLES: + ma=(uint32)va_arg(ap,uint32); + if (ma!=0) + { + if (ma>3) + { + TIFFErrorExt(tif->tif_clientdata,module,"JpegAcTables tag has incorrect count"); + return(0); + } + sp->actable_offset_count=(uint8)ma; + mb=(uint64*)va_arg(ap,uint64*); + for (n=0; nactable_offset[n]=mb[n]; + } + break; + case TIFFTAG_JPEGPROC: + sp->jpeg_proc=(uint8)va_arg(ap,uint16_vap); + break; + case TIFFTAG_JPEGRESTARTINTERVAL: + sp->restart_interval=(uint16)va_arg(ap,uint16_vap); + break; + default: + return (*sp->vsetparent)(tif,tag,ap); + } + TIFFSetFieldBit(tif,TIFFFieldWithTag(tif,tag)->field_bit); + tif->tif_flags|=TIFF_DIRTYDIRECT; + return(1); +} + +static void +OJPEGPrintDir(TIFF* tif, FILE* fd, long flags) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + (void)flags; + assert(sp!=NULL); + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMAT)) + fprintf(fd," JpegInterchangeFormat: " TIFF_UINT64_FORMAT "\n",(TIFF_UINT64_T)sp->jpeg_interchange_format); + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH)) + fprintf(fd," JpegInterchangeFormatLength: " TIFF_UINT64_FORMAT "\n",(TIFF_UINT64_T)sp->jpeg_interchange_format_length); + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGQTABLES)) + { + fprintf(fd," JpegQTables:"); + for (m=0; mqtable_offset_count; m++) + fprintf(fd," " TIFF_UINT64_FORMAT,(TIFF_UINT64_T)sp->qtable_offset[m]); + fprintf(fd,"\n"); + } + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGDCTABLES)) + { + fprintf(fd," JpegDcTables:"); + for (m=0; mdctable_offset_count; m++) + fprintf(fd," " TIFF_UINT64_FORMAT,(TIFF_UINT64_T)sp->dctable_offset[m]); + fprintf(fd,"\n"); + } + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGACTABLES)) + { + fprintf(fd," JpegAcTables:"); + for (m=0; mactable_offset_count; m++) + fprintf(fd," " TIFF_UINT64_FORMAT,(TIFF_UINT64_T)sp->actable_offset[m]); + fprintf(fd,"\n"); + } + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGPROC)) + fprintf(fd," JpegProc: %u\n",(unsigned int)sp->jpeg_proc); + if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGRESTARTINTERVAL)) + fprintf(fd," JpegRestartInterval: %u\n",(unsigned int)sp->restart_interval); + if (sp->printdir) + (*sp->printdir)(tif, fd, flags); +} + +static int +OJPEGFixupTags(TIFF* tif) +{ + (void) tif; + return(1); +} + +static int +OJPEGSetupDecode(TIFF* tif) +{ + static const char module[]="OJPEGSetupDecode"; + TIFFWarningExt(tif->tif_clientdata,module,"Depreciated and troublesome old-style JPEG compression mode, please convert to new-style JPEG compression and notify vendor of writing software"); + return(1); +} + +static int +OJPEGPreDecode(TIFF* tif, uint16 s) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint32 m; + if (sp->subsamplingcorrect_done==0) + OJPEGSubsamplingCorrect(tif); + if (sp->readheader_done==0) + { + if (OJPEGReadHeaderInfo(tif)==0) + return(0); + } + if (sp->sos_end[s].log==0) + { + if (OJPEGReadSecondarySos(tif,s)==0) + return(0); + } + if isTiled(tif) + m=tif->tif_curtile; + else + m=tif->tif_curstrip; + if ((sp->writeheader_done!=0) && ((sp->write_cursample!=s) || (sp->write_curstrile>m))) + { + if (sp->libjpeg_session_active!=0) + OJPEGLibjpegSessionAbort(tif); + sp->writeheader_done=0; + } + if (sp->writeheader_done==0) + { + sp->plane_sample_offset=(uint8)s; + sp->write_cursample=s; + sp->write_curstrile=s*tif->tif_dir.td_stripsperimage; + if ((sp->in_buffer_file_pos_log==0) || + (sp->in_buffer_file_pos-sp->in_buffer_togo!=sp->sos_end[s].in_buffer_file_pos)) + { + sp->in_buffer_source=sp->sos_end[s].in_buffer_source; + sp->in_buffer_next_strile=sp->sos_end[s].in_buffer_next_strile; + sp->in_buffer_file_pos=sp->sos_end[s].in_buffer_file_pos; + sp->in_buffer_file_pos_log=0; + sp->in_buffer_file_togo=sp->sos_end[s].in_buffer_file_togo; + sp->in_buffer_togo=0; + sp->in_buffer_cur=0; + } + if (OJPEGWriteHeaderInfo(tif)==0) + return(0); + } + while (sp->write_curstrilelibjpeg_jpeg_query_style==0) + { + if (OJPEGPreDecodeSkipRaw(tif)==0) + return(0); + } + else + { + if (OJPEGPreDecodeSkipScanlines(tif)==0) + return(0); + } + sp->write_curstrile++; + } + return(1); +} + +static int +OJPEGPreDecodeSkipRaw(TIFF* tif) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint32 m; + m=sp->lines_per_strile; + if (sp->subsampling_convert_state!=0) + { + if (sp->subsampling_convert_clines-sp->subsampling_convert_state>=m) + { + sp->subsampling_convert_state+=m; + if (sp->subsampling_convert_state==sp->subsampling_convert_clines) + sp->subsampling_convert_state=0; + return(1); + } + m-=sp->subsampling_convert_clines-sp->subsampling_convert_state; + sp->subsampling_convert_state=0; + } + while (m>=sp->subsampling_convert_clines) + { + if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) + return(0); + m-=sp->subsampling_convert_clines; + } + if (m>0) + { + if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) + return(0); + sp->subsampling_convert_state=m; + } + return(1); +} + +static int +OJPEGPreDecodeSkipScanlines(TIFF* tif) +{ + static const char module[]="OJPEGPreDecodeSkipScanlines"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint32 m; + if (sp->skip_buffer==NULL) + { + // add (uint8*) cast + sp->skip_buffer = (uint8*)_TIFFmalloc(sp->bytes_per_line); + if (sp->skip_buffer == NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + } + for (m=0; mlines_per_strile; m++) + { + if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&sp->skip_buffer,1)==0) + return(0); + } + return(1); +} + +static int +OJPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + (void)s; + if (sp->libjpeg_jpeg_query_style==0) + { + if (OJPEGDecodeRaw(tif,buf,cc)==0) + return(0); + } + else + { + if (OJPEGDecodeScanlines(tif,buf,cc)==0) + return(0); + } + return(1); +} + +static int +OJPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc) +{ + static const char module[]="OJPEGDecodeRaw"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8* m; + tmsize_t n; + uint8* oy; + uint8* ocb; + uint8* ocr; + uint8* p; + uint32 q; + uint8* r; + uint8 sx,sy; + if (cc%sp->bytes_per_line!=0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read"); + return(0); + } + assert(cc>0); + m=buf; + n=cc; + do + { + if (sp->subsampling_convert_state==0) + { + if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) + return(0); + } + oy=sp->subsampling_convert_ybuf+sp->subsampling_convert_state*sp->subsampling_ver*sp->subsampling_convert_ylinelen; + ocb=sp->subsampling_convert_cbbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen; + ocr=sp->subsampling_convert_crbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen; + p=m; + for (q=0; qsubsampling_convert_clinelenout; q++) + { + r=oy; + for (sy=0; sysubsampling_ver; sy++) + { + for (sx=0; sxsubsampling_hor; sx++) + *p++=*r++; + r+=sp->subsampling_convert_ylinelen-sp->subsampling_hor; + } + oy+=sp->subsampling_hor; + *p++=*ocb++; + *p++=*ocr++; + } + sp->subsampling_convert_state++; + if (sp->subsampling_convert_state==sp->subsampling_convert_clines) + sp->subsampling_convert_state=0; + m+=sp->bytes_per_line; + n-=sp->bytes_per_line; + } while(n>0); + return(1); +} + +static int +OJPEGDecodeScanlines(TIFF* tif, uint8* buf, tmsize_t cc) +{ + static const char module[]="OJPEGDecodeScanlines"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8* m; + tmsize_t n; + if (cc%sp->bytes_per_line!=0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read"); + return(0); + } + assert(cc>0); + m=buf; + n=cc; + do + { + if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&m,1)==0) + return(0); + m+=sp->bytes_per_line; + n-=sp->bytes_per_line; + } while(n>0); + return(1); +} + +static void +OJPEGPostDecode(TIFF* tif, uint8* buf, tmsize_t cc) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + (void)buf; + (void)cc; + sp->write_curstrile++; + if (sp->write_curstrile%tif->tif_dir.td_stripsperimage==0) + { + assert(sp->libjpeg_session_active!=0); + OJPEGLibjpegSessionAbort(tif); + sp->writeheader_done=0; + } +} + +static int +OJPEGSetupEncode(TIFF* tif) +{ + static const char module[]="OJPEGSetupEncode"; + TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); + return(0); +} + +static int +OJPEGPreEncode(TIFF* tif, uint16 s) +{ + static const char module[]="OJPEGPreEncode"; + (void)s; + TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); + return(0); +} + +static int +OJPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) +{ + static const char module[]="OJPEGEncode"; + (void)buf; + (void)cc; + (void)s; + TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); + return(0); +} + +static int +OJPEGPostEncode(TIFF* tif) +{ + static const char module[]="OJPEGPostEncode"; + TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); + return(0); +} + +static void +OJPEGCleanup(TIFF* tif) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + if (sp!=0) + { + tif->tif_tagmethods.vgetfield=sp->vgetparent; + tif->tif_tagmethods.vsetfield=sp->vsetparent; + tif->tif_tagmethods.printdir=sp->printdir; + if (sp->qtable[0]!=0) + _TIFFfree(sp->qtable[0]); + if (sp->qtable[1]!=0) + _TIFFfree(sp->qtable[1]); + if (sp->qtable[2]!=0) + _TIFFfree(sp->qtable[2]); + if (sp->qtable[3]!=0) + _TIFFfree(sp->qtable[3]); + if (sp->dctable[0]!=0) + _TIFFfree(sp->dctable[0]); + if (sp->dctable[1]!=0) + _TIFFfree(sp->dctable[1]); + if (sp->dctable[2]!=0) + _TIFFfree(sp->dctable[2]); + if (sp->dctable[3]!=0) + _TIFFfree(sp->dctable[3]); + if (sp->actable[0]!=0) + _TIFFfree(sp->actable[0]); + if (sp->actable[1]!=0) + _TIFFfree(sp->actable[1]); + if (sp->actable[2]!=0) + _TIFFfree(sp->actable[2]); + if (sp->actable[3]!=0) + _TIFFfree(sp->actable[3]); + if (sp->libjpeg_session_active!=0) + OJPEGLibjpegSessionAbort(tif); + if (sp->subsampling_convert_ycbcrbuf!=0) + _TIFFfree(sp->subsampling_convert_ycbcrbuf); + if (sp->subsampling_convert_ycbcrimage!=0) + _TIFFfree(sp->subsampling_convert_ycbcrimage); + if (sp->skip_buffer!=0) + _TIFFfree(sp->skip_buffer); + _TIFFfree(sp); + tif->tif_data=NULL; + _TIFFSetDefaultCompressionState(tif); + } +} + +static void +OJPEGSubsamplingCorrect(TIFF* tif) +{ + static const char module[]="OJPEGSubsamplingCorrect"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 mh; + uint8 mv; + _TIFFFillStriles( tif ); + + assert(sp->subsamplingcorrect_done==0); + if ((tif->tif_dir.td_samplesperpixel!=3) || ((tif->tif_dir.td_photometric!=PHOTOMETRIC_YCBCR) && + (tif->tif_dir.td_photometric!=PHOTOMETRIC_ITULAB))) + { + if (sp->subsampling_tag!=0) + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag not appropriate for this Photometric and/or SamplesPerPixel"); + sp->subsampling_hor=1; + sp->subsampling_ver=1; + sp->subsampling_force_desubsampling_inside_decompression=0; + } + else + { + sp->subsamplingcorrect_done=1; + mh=sp->subsampling_hor; + mv=sp->subsampling_ver; + sp->subsamplingcorrect=1; + OJPEGReadHeaderInfoSec(tif); + if (sp->subsampling_force_desubsampling_inside_decompression!=0) + { + sp->subsampling_hor=1; + sp->subsampling_ver=1; + } + sp->subsamplingcorrect=0; + if (((sp->subsampling_hor!=mh) || (sp->subsampling_ver!=mv)) && (sp->subsampling_force_desubsampling_inside_decompression==0)) + { + if (sp->subsampling_tag==0) + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data [%d,%d] does not match default values [2,2]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver); + else + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data [%d,%d] does not match subsampling tag values [%d,%d]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver,mh,mv); + } + if (sp->subsampling_force_desubsampling_inside_decompression!=0) + { + if (sp->subsampling_tag==0) + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data does not match default values [2,2] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression"); + else + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data does not match subsampling tag values [%d,%d] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression",mh,mv); + } + if (sp->subsampling_force_desubsampling_inside_decompression==0) + { + if (sp->subsampling_horsubsampling_ver) + TIFFWarningExt(tif->tif_clientdata,module,"Subsampling values [%d,%d] are not allowed in TIFF",sp->subsampling_hor,sp->subsampling_ver); + } + } + sp->subsamplingcorrect_done=1; +} + +static int +OJPEGReadHeaderInfo(TIFF* tif) +{ + static const char module[]="OJPEGReadHeaderInfo"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(sp->readheader_done==0); + sp->image_width=tif->tif_dir.td_imagewidth; + sp->image_length=tif->tif_dir.td_imagelength; + if isTiled(tif) + { + sp->strile_width=tif->tif_dir.td_tilewidth; + sp->strile_length=tif->tif_dir.td_tilelength; + sp->strile_length_total=((sp->image_length+sp->strile_length-1)/sp->strile_length)*sp->strile_length; + } + else + { + sp->strile_width=sp->image_width; + sp->strile_length=tif->tif_dir.td_rowsperstrip; + sp->strile_length_total=sp->image_length; + } + if (tif->tif_dir.td_samplesperpixel==1) + { + sp->samples_per_pixel=1; + sp->plane_sample_offset=0; + sp->samples_per_pixel_per_plane=sp->samples_per_pixel; + sp->subsampling_hor=1; + sp->subsampling_ver=1; + } + else + { + if (tif->tif_dir.td_samplesperpixel!=3) + { + TIFFErrorExt(tif->tif_clientdata,module,"SamplesPerPixel %d not supported for this compression scheme",sp->samples_per_pixel); + return(0); + } + sp->samples_per_pixel=3; + sp->plane_sample_offset=0; + if (tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG) + sp->samples_per_pixel_per_plane=3; + else + sp->samples_per_pixel_per_plane=1; + } + if (sp->strile_lengthimage_length) + { + if (sp->strile_length%(sp->subsampling_ver*8)!=0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Incompatible vertical subsampling and image strip/tile length"); + return(0); + } + sp->restart_interval=((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8))*(sp->strile_length/(sp->subsampling_ver*8)); + } + if (OJPEGReadHeaderInfoSec(tif)==0) + return(0); + sp->sos_end[0].log=1; + sp->sos_end[0].in_buffer_source=sp->in_buffer_source; + sp->sos_end[0].in_buffer_next_strile=sp->in_buffer_next_strile; + sp->sos_end[0].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo; + sp->sos_end[0].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo; + sp->readheader_done=1; + return(1); +} + +static int +OJPEGReadSecondarySos(TIFF* tif, uint16 s) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + assert(s>0); + assert(s<3); + assert(sp->sos_end[0].log!=0); + assert(sp->sos_end[s].log==0); + sp->plane_sample_offset=s-1; + while(sp->sos_end[sp->plane_sample_offset].log==0) + sp->plane_sample_offset--; + sp->in_buffer_source=sp->sos_end[sp->plane_sample_offset].in_buffer_source; + sp->in_buffer_next_strile=sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile; + sp->in_buffer_file_pos=sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos; + sp->in_buffer_file_pos_log=0; + sp->in_buffer_file_togo=sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo; + sp->in_buffer_togo=0; + sp->in_buffer_cur=0; + while(sp->plane_sample_offsetplane_sample_offset++; + if (OJPEGReadHeaderInfoSecStreamSos(tif)==0) + return(0); + sp->sos_end[sp->plane_sample_offset].log=1; + sp->sos_end[sp->plane_sample_offset].in_buffer_source=sp->in_buffer_source; + sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile=sp->in_buffer_next_strile; + sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo; + sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo; + } + return(1); +} + +static int +OJPEGWriteHeaderInfo(TIFF* tif) +{ + static const char module[]="OJPEGWriteHeaderInfo"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8** m; + uint32 n; + /* if a previous attempt failed, don't try again */ + if (sp->libjpeg_session_active != 0) + return 0; + sp->out_state=ososSoi; + sp->restart_index=0; + jpeg_std_error(&(sp->libjpeg_jpeg_error_mgr)); + sp->libjpeg_jpeg_error_mgr.output_message=OJPEGLibjpegJpegErrorMgrOutputMessage; + sp->libjpeg_jpeg_error_mgr.error_exit=OJPEGLibjpegJpegErrorMgrErrorExit; + sp->libjpeg_jpeg_decompress_struct.err=&(sp->libjpeg_jpeg_error_mgr); + sp->libjpeg_jpeg_decompress_struct.client_data=(void*)tif; + if (jpeg_create_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0) + return(0); + sp->libjpeg_session_active=1; + sp->libjpeg_jpeg_source_mgr.bytes_in_buffer=0; + sp->libjpeg_jpeg_source_mgr.init_source=OJPEGLibjpegJpegSourceMgrInitSource; + sp->libjpeg_jpeg_source_mgr.fill_input_buffer=OJPEGLibjpegJpegSourceMgrFillInputBuffer; + sp->libjpeg_jpeg_source_mgr.skip_input_data=OJPEGLibjpegJpegSourceMgrSkipInputData; + sp->libjpeg_jpeg_source_mgr.resync_to_restart=OJPEGLibjpegJpegSourceMgrResyncToRestart; + sp->libjpeg_jpeg_source_mgr.term_source=OJPEGLibjpegJpegSourceMgrTermSource; + sp->libjpeg_jpeg_decompress_struct.src=&(sp->libjpeg_jpeg_source_mgr); + if (jpeg_read_header_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),1)==0) + return(0); + if ((sp->subsampling_force_desubsampling_inside_decompression==0) && (sp->samples_per_pixel_per_plane>1)) + { + sp->libjpeg_jpeg_decompress_struct.raw_data_out=1; +#if JPEG_LIB_VERSION >= 70 + sp->libjpeg_jpeg_decompress_struct.do_fancy_upsampling=FALSE; +#endif + sp->libjpeg_jpeg_query_style=0; + if (sp->subsampling_convert_log==0) + { + assert(sp->subsampling_convert_ycbcrbuf==0); + assert(sp->subsampling_convert_ycbcrimage==0); + sp->subsampling_convert_ylinelen=((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8)*sp->subsampling_hor*8); + sp->subsampling_convert_ylines=sp->subsampling_ver*8; + sp->subsampling_convert_clinelen=sp->subsampling_convert_ylinelen/sp->subsampling_hor; + sp->subsampling_convert_clines=8; + sp->subsampling_convert_ybuflen=sp->subsampling_convert_ylinelen*sp->subsampling_convert_ylines; + sp->subsampling_convert_cbuflen=sp->subsampling_convert_clinelen*sp->subsampling_convert_clines; + sp->subsampling_convert_ycbcrbuflen=sp->subsampling_convert_ybuflen+2*sp->subsampling_convert_cbuflen; + sp->subsampling_convert_ycbcrbuf = (uint8*)_TIFFmalloc(sp->subsampling_convert_ycbcrbuflen); // add (uint8*) cast + if (sp->subsampling_convert_ycbcrbuf==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + sp->subsampling_convert_ybuf=sp->subsampling_convert_ycbcrbuf; + sp->subsampling_convert_cbbuf=sp->subsampling_convert_ybuf+sp->subsampling_convert_ybuflen; + sp->subsampling_convert_crbuf=sp->subsampling_convert_cbbuf+sp->subsampling_convert_cbuflen; + sp->subsampling_convert_ycbcrimagelen=3+sp->subsampling_convert_ylines+2*sp->subsampling_convert_clines; + sp->subsampling_convert_ycbcrimage = (uint8**)_TIFFmalloc(sp->subsampling_convert_ycbcrimagelen * sizeof(uint8*));// add (uint8**) cast + if (sp->subsampling_convert_ycbcrimage==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + m=sp->subsampling_convert_ycbcrimage; + *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3); + *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines); + *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines+sp->subsampling_convert_clines); + for (n=0; nsubsampling_convert_ylines; n++) + *m++=sp->subsampling_convert_ybuf+n*sp->subsampling_convert_ylinelen; + for (n=0; nsubsampling_convert_clines; n++) + *m++=sp->subsampling_convert_cbbuf+n*sp->subsampling_convert_clinelen; + for (n=0; nsubsampling_convert_clines; n++) + *m++=sp->subsampling_convert_crbuf+n*sp->subsampling_convert_clinelen; + sp->subsampling_convert_clinelenout=((sp->strile_width+sp->subsampling_hor-1)/sp->subsampling_hor); + sp->subsampling_convert_state=0; + sp->bytes_per_line=sp->subsampling_convert_clinelenout*(sp->subsampling_ver*sp->subsampling_hor+2); + sp->lines_per_strile=((sp->strile_length+sp->subsampling_ver-1)/sp->subsampling_ver); + sp->subsampling_convert_log=1; + } + } + else + { + sp->libjpeg_jpeg_decompress_struct.jpeg_color_space=JCS_UNKNOWN; + sp->libjpeg_jpeg_decompress_struct.out_color_space=JCS_UNKNOWN; + sp->libjpeg_jpeg_query_style=1; + sp->bytes_per_line=sp->samples_per_pixel_per_plane*sp->strile_width; + sp->lines_per_strile=sp->strile_length; + } + if (jpeg_start_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0) + return(0); + sp->writeheader_done=1; + return(1); +} + +static void +OJPEGLibjpegSessionAbort(TIFF* tif) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(sp->libjpeg_session_active!=0); + jpeg_destroy((jpeg_common_struct*)(&(sp->libjpeg_jpeg_decompress_struct))); + sp->libjpeg_session_active=0; +} + +static int +OJPEGReadHeaderInfoSec(TIFF* tif) +{ + static const char module[]="OJPEGReadHeaderInfoSec"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + uint16 n; + uint8 o; + if (sp->file_size==0) + sp->file_size=TIFFGetFileSize(tif); + if (sp->jpeg_interchange_format!=0) + { + if (sp->jpeg_interchange_format>=sp->file_size) + { + sp->jpeg_interchange_format=0; + sp->jpeg_interchange_format_length=0; + } + else + { + if ((sp->jpeg_interchange_format_length==0) || (sp->jpeg_interchange_format+sp->jpeg_interchange_format_length>sp->file_size)) + sp->jpeg_interchange_format_length=sp->file_size-sp->jpeg_interchange_format; + } + } + sp->in_buffer_source=osibsNotSetYet; + sp->in_buffer_next_strile=0; + sp->in_buffer_strile_count=tif->tif_dir.td_nstrips; + sp->in_buffer_file_togo=0; + sp->in_buffer_togo=0; + do + { + if (OJPEGReadBytePeek(sp,&m)==0) + return(0); + if (m!=255) + break; + OJPEGReadByteAdvance(sp); + do + { + if (OJPEGReadByte(sp,&m)==0) + return(0); + } while(m==255); + switch(m) + { + case JPEG_MARKER_SOI: + /* this type of marker has no data, and should be skipped */ + break; + case JPEG_MARKER_COM: + case JPEG_MARKER_APP0: + case JPEG_MARKER_APP0+1: + case JPEG_MARKER_APP0+2: + case JPEG_MARKER_APP0+3: + case JPEG_MARKER_APP0+4: + case JPEG_MARKER_APP0+5: + case JPEG_MARKER_APP0+6: + case JPEG_MARKER_APP0+7: + case JPEG_MARKER_APP0+8: + case JPEG_MARKER_APP0+9: + case JPEG_MARKER_APP0+10: + case JPEG_MARKER_APP0+11: + case JPEG_MARKER_APP0+12: + case JPEG_MARKER_APP0+13: + case JPEG_MARKER_APP0+14: + case JPEG_MARKER_APP0+15: + /* this type of marker has data, but it has no use to us (and no place here) and should be skipped */ + if (OJPEGReadWord(sp,&n)==0) + return(0); + if (n<2) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data"); + return(0); + } + if (n>2) + OJPEGReadSkip(sp,n-2); + break; + case JPEG_MARKER_DRI: + if (OJPEGReadHeaderInfoSecStreamDri(tif)==0) + return(0); + break; + case JPEG_MARKER_DQT: + if (OJPEGReadHeaderInfoSecStreamDqt(tif)==0) + return(0); + break; + case JPEG_MARKER_DHT: + if (OJPEGReadHeaderInfoSecStreamDht(tif)==0) + return(0); + break; + case JPEG_MARKER_SOF0: + case JPEG_MARKER_SOF1: + case JPEG_MARKER_SOF3: + if (OJPEGReadHeaderInfoSecStreamSof(tif,m)==0) + return(0); + if (sp->subsamplingcorrect!=0) + return(1); + break; + case JPEG_MARKER_SOS: + if (sp->subsamplingcorrect!=0) + return(1); + assert(sp->plane_sample_offset==0); + if (OJPEGReadHeaderInfoSecStreamSos(tif)==0) + return(0); + break; + default: + TIFFErrorExt(tif->tif_clientdata,module,"Unknown marker type %d in JPEG data",m); + return(0); + } + } while(m!=JPEG_MARKER_SOS); + if (sp->subsamplingcorrect) + return(1); + if (sp->sof_log==0) + { + if (OJPEGReadHeaderInfoSecTablesQTable(tif)==0) + return(0); + sp->sof_marker_id=JPEG_MARKER_SOF0; + for (o=0; osamples_per_pixel; o++) + sp->sof_c[o]=o; + sp->sof_hv[0]=((sp->subsampling_hor<<4)|sp->subsampling_ver); + for (o=1; osamples_per_pixel; o++) + sp->sof_hv[o]=17; + sp->sof_x=sp->strile_width; + sp->sof_y=sp->strile_length_total; + sp->sof_log=1; + if (OJPEGReadHeaderInfoSecTablesDcTable(tif)==0) + return(0); + if (OJPEGReadHeaderInfoSecTablesAcTable(tif)==0) + return(0); + for (o=1; osamples_per_pixel; o++) + sp->sos_cs[o]=o; + } + return(1); +} + +static int +OJPEGReadHeaderInfoSecStreamDri(TIFF* tif) +{ + /* this could easilly cause trouble in some cases... but no such cases have occured sofar */ + static const char module[]="OJPEGReadHeaderInfoSecStreamDri"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint16 m; + if (OJPEGReadWord(sp,&m)==0) + return(0); + if (m!=4) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DRI marker in JPEG data"); + return(0); + } + if (OJPEGReadWord(sp,&m)==0) + return(0); + sp->restart_interval=m; + return(1); +} + +static int +OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif) +{ + /* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */ + static const char module[]="OJPEGReadHeaderInfoSecStreamDqt"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint16 m; + uint32 na; + uint8* nb; + uint8 o; + if (OJPEGReadWord(sp,&m)==0) + return(0); + if (m<=2) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data"); + return(0); + } + if (sp->subsamplingcorrect!=0) + OJPEGReadSkip(sp,m-2); + else + { + m-=2; + do + { + if (m<65) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data"); + return(0); + } + na = sizeof(uint32) + 69; + nb = (uint8*)_TIFFmalloc(na); // add (uint8*) cast + if (nb == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + *(uint32*)nb=na; + nb[sizeof(uint32)]=255; + nb[sizeof(uint32)+1]=JPEG_MARKER_DQT; + nb[sizeof(uint32)+2]=0; + nb[sizeof(uint32)+3]=67; + if (OJPEGReadBlock(sp,65,&nb[sizeof(uint32)+4])==0) { + _TIFFfree(nb); + return(0); + } + o=nb[sizeof(uint32)+4]&15; + if (3tif_clientdata,module,"Corrupt DQT marker in JPEG data"); + _TIFFfree(nb); + return(0); + } + if (sp->qtable[o]!=0) + _TIFFfree(sp->qtable[o]); + sp->qtable[o]=nb; + m-=65; + } while(m>0); + } + return(1); +} + +static int +OJPEGReadHeaderInfoSecStreamDht(TIFF* tif) +{ + /* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */ + /* TODO: the following assumes there is only one table in this marker... but i'm not quite sure that assumption is guaranteed correct */ + static const char module[]="OJPEGReadHeaderInfoSecStreamDht"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint16 m; + uint32 na; + uint8* nb; + uint8 o; + if (OJPEGReadWord(sp,&m)==0) + return(0); + if (m<=2) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data"); + return(0); + } + if (sp->subsamplingcorrect!=0) + { + OJPEGReadSkip(sp,m-2); + } + else + { + na = sizeof(uint32) + 2 + m; + nb = (uint8*)_TIFFmalloc(na); // add (uint8*) cast + if (nb == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + *(uint32*)nb=na; + nb[sizeof(uint32)]=255; + nb[sizeof(uint32)+1]=JPEG_MARKER_DHT; + nb[sizeof(uint32)+2]=(m>>8); + nb[sizeof(uint32)+3]=(m&255); + if (OJPEGReadBlock(sp,m-2,&nb[sizeof(uint32)+4])==0) + return(0); + o=nb[sizeof(uint32)+4]; + if ((o&240)==0) + { + if (3tif_clientdata,module,"Corrupt DHT marker in JPEG data"); + return(0); + } + if (sp->dctable[o]!=0) + _TIFFfree(sp->dctable[o]); + sp->dctable[o]=nb; + } + else + { + if ((o&240)!=16) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data"); + return(0); + } + o&=15; + if (3tif_clientdata,module,"Corrupt DHT marker in JPEG data"); + return(0); + } + if (sp->actable[o]!=0) + _TIFFfree(sp->actable[o]); + sp->actable[o]=nb; + } + } + return(1); +} + +static int +OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id) +{ + /* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */ + static const char module[]="OJPEGReadHeaderInfoSecStreamSof"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint16 m; + uint16 n; + uint8 o; + uint16 p; + uint16 q; + if (sp->sof_log!=0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data"); + return(0); + } + if (sp->subsamplingcorrect==0) + sp->sof_marker_id=marker_id; + /* Lf: data length */ + if (OJPEGReadWord(sp,&m)==0) + return(0); + if (m<11) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); + return(0); + } + m-=8; + if (m%3!=0) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); + return(0); + } + n=m/3; + if (sp->subsamplingcorrect==0) + { + if (n!=sp->samples_per_pixel) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of samples"); + return(0); + } + } + /* P: Sample precision */ + if (OJPEGReadByte(sp,&o)==0) + return(0); + if (o!=8) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of bits per sample"); + return(0); + } + /* Y: Number of lines, X: Number of samples per line */ + if (sp->subsamplingcorrect) + OJPEGReadSkip(sp,4); + else + { + /* Y: Number of lines */ + if (OJPEGReadWord(sp,&p)==0) + return(0); + if (((uint32)pimage_length) && ((uint32)pstrile_length_total)) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected height"); + return(0); + } + sp->sof_y=p; + /* X: Number of samples per line */ + if (OJPEGReadWord(sp,&p)==0) + return(0); + if (((uint32)pimage_width) && ((uint32)pstrile_width)) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected width"); + return(0); + } + if ((uint32)p>sp->strile_width) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data image width exceeds expected image width"); + return(0); + } + sp->sof_x=p; + } + /* Nf: Number of image components in frame */ + if (OJPEGReadByte(sp,&o)==0) + return(0); + if (o!=n) + { + if (sp->subsamplingcorrect==0) + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); + return(0); + } + /* per component stuff */ + /* TODO: double-check that flow implies that n cannot be as big as to make us overflow sof_c, sof_hv and sof_tq arrays */ + for (q=0; qsubsamplingcorrect==0) + sp->sof_c[q]=o; + /* H: Horizontal sampling factor, and V: Vertical sampling factor */ + if (OJPEGReadByte(sp,&o)==0) + return(0); + if (sp->subsamplingcorrect!=0) + { + if (q==0) + { + sp->subsampling_hor=(o>>4); + sp->subsampling_ver=(o&15); + if (((sp->subsampling_hor!=1) && (sp->subsampling_hor!=2) && (sp->subsampling_hor!=4)) || + ((sp->subsampling_ver!=1) && (sp->subsampling_ver!=2) && (sp->subsampling_ver!=4))) + sp->subsampling_force_desubsampling_inside_decompression=1; + } + else + { + if (o!=17) + sp->subsampling_force_desubsampling_inside_decompression=1; + } + } + else + { + sp->sof_hv[q]=o; + if (sp->subsampling_force_desubsampling_inside_decompression==0) + { + if (q==0) + { + if (o!=((sp->subsampling_hor<<4)|sp->subsampling_ver)) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values"); + return(0); + } + } + else + { + if (o!=17) + { + TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values"); + return(0); + } + } + } + } + /* Tq: Quantization table destination selector */ + if (OJPEGReadByte(sp,&o)==0) + return(0); + if (sp->subsamplingcorrect==0) + sp->sof_tq[q]=o; + } + if (sp->subsamplingcorrect==0) + sp->sof_log=1; + return(1); +} + +static int +OJPEGReadHeaderInfoSecStreamSos(TIFF* tif) +{ + /* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */ + static const char module[]="OJPEGReadHeaderInfoSecStreamSos"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint16 m; + uint8 n; + uint8 o; + assert(sp->subsamplingcorrect==0); + if (sp->sof_log==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); + return(0); + } + /* Ls */ + if (OJPEGReadWord(sp,&m)==0) + return(0); + if (m!=6+sp->samples_per_pixel_per_plane*2) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); + return(0); + } + /* Ns */ + if (OJPEGReadByte(sp,&n)==0) + return(0); + if (n!=sp->samples_per_pixel_per_plane) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); + return(0); + } + /* Cs, Td, and Ta */ + for (o=0; osamples_per_pixel_per_plane; o++) + { + /* Cs */ + if (OJPEGReadByte(sp,&n)==0) + return(0); + sp->sos_cs[sp->plane_sample_offset+o]=n; + /* Td and Ta */ + if (OJPEGReadByte(sp,&n)==0) + return(0); + sp->sos_tda[sp->plane_sample_offset+o]=n; + } + /* skip Ss, Se, Ah, en Al -> no check, as per Tom Lane recommendation, as per LibJpeg source */ + OJPEGReadSkip(sp,3); + return(1); +} + +static int +OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif) +{ + static const char module[]="OJPEGReadHeaderInfoSecTablesQTable"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + uint8 n; + uint32 oa; + uint8* ob; + uint32 p; + if (sp->qtable_offset[0]==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); + return(0); + } + sp->in_buffer_file_pos_log=0; + for (m=0; msamples_per_pixel; m++) + { + if ((sp->qtable_offset[m]!=0) && ((m==0) || (sp->qtable_offset[m]!=sp->qtable_offset[m-1]))) + { + for (n=0; nqtable_offset[m]==sp->qtable_offset[n]) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegQTables tag value"); + return(0); + } + } + oa=sizeof(uint32)+69; + ob = (uint8*)_TIFFmalloc(oa); // add (uint8*) cast + if (ob==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + *(uint32*)ob=oa; + ob[sizeof(uint32)]=255; + ob[sizeof(uint32)+1]=JPEG_MARKER_DQT; + ob[sizeof(uint32)+2]=0; + ob[sizeof(uint32)+3]=67; + ob[sizeof(uint32)+4]=m; + TIFFSeekFile(tif,sp->qtable_offset[m],SEEK_SET); + p=(uint32)TIFFReadFile(tif,&ob[sizeof(uint32)+5],64); + if (p!=64) + return(0); + sp->qtable[m]=ob; + sp->sof_tq[m]=m; + } + else + sp->sof_tq[m]=sp->sof_tq[m-1]; + } + return(1); +} + +static int +OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif) +{ + static const char module[]="OJPEGReadHeaderInfoSecTablesDcTable"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + uint8 n; + uint8 o[16]; + uint32 p; + uint32 q; + uint32 ra; + uint8* rb; + if (sp->dctable_offset[0]==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); + return(0); + } + sp->in_buffer_file_pos_log=0; + for (m=0; msamples_per_pixel; m++) + { + if ((sp->dctable_offset[m]!=0) && ((m==0) || (sp->dctable_offset[m]!=sp->dctable_offset[m-1]))) + { + for (n=0; ndctable_offset[m]==sp->dctable_offset[n]) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegDcTables tag value"); + return(0); + } + } + TIFFSeekFile(tif,sp->dctable_offset[m],SEEK_SET); + p=(uint32)TIFFReadFile(tif,o,16); + if (p!=16) + return(0); + q=0; + for (n=0; n<16; n++) + q+=o[n]; + ra=sizeof(uint32)+21+q; + rb = (uint8*)_TIFFmalloc(ra); // add (uint8*) cast + if (rb==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + *(uint32*)rb=ra; + rb[sizeof(uint32)]=255; + rb[sizeof(uint32)+1]=JPEG_MARKER_DHT; + rb[sizeof(uint32)+2]=((19+q)>>8); + rb[sizeof(uint32)+3]=((19+q)&255); + rb[sizeof(uint32)+4]=m; + for (n=0; n<16; n++) + rb[sizeof(uint32)+5+n]=o[n]; + p=(uint32)TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q); + if (p!=q) + return(0); + sp->dctable[m]=rb; + sp->sos_tda[m]=(m<<4); + } + else + sp->sos_tda[m]=sp->sos_tda[m-1]; + } + return(1); +} + +static int +OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif) +{ + static const char module[]="OJPEGReadHeaderInfoSecTablesAcTable"; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + uint8 n; + uint8 o[16]; + uint32 p; + uint32 q; + uint32 ra; + uint8* rb; + if (sp->actable_offset[0]==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); + return(0); + } + sp->in_buffer_file_pos_log=0; + for (m=0; msamples_per_pixel; m++) + { + if ((sp->actable_offset[m]!=0) && ((m==0) || (sp->actable_offset[m]!=sp->actable_offset[m-1]))) + { + for (n=0; nactable_offset[m]==sp->actable_offset[n]) + { + TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegAcTables tag value"); + return(0); + } + } + TIFFSeekFile(tif,sp->actable_offset[m],SEEK_SET); + p=(uint32)TIFFReadFile(tif,o,16); + if (p!=16) + return(0); + q=0; + for (n=0; n<16; n++) + q+=o[n]; + ra=sizeof(uint32)+21+q; + rb = (uint8*)_TIFFmalloc(ra); // add (uint8*) cast + if (rb==0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + *(uint32*)rb=ra; + rb[sizeof(uint32)]=255; + rb[sizeof(uint32)+1]=JPEG_MARKER_DHT; + rb[sizeof(uint32)+2]=((19+q)>>8); + rb[sizeof(uint32)+3]=((19+q)&255); + rb[sizeof(uint32)+4]=(16|m); + for (n=0; n<16; n++) + rb[sizeof(uint32)+5+n]=o[n]; + p=(uint32)TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q); + if (p!=q) + return(0); + sp->actable[m]=rb; + sp->sos_tda[m]=(sp->sos_tda[m]|m); + } + else + sp->sos_tda[m]=(sp->sos_tda[m]|(sp->sos_tda[m-1]&15)); + } + return(1); +} + +static int +OJPEGReadBufferFill(OJPEGState* sp) +{ + uint16 m; + tmsize_t n; + /* TODO: double-check: when subsamplingcorrect is set, no call to TIFFErrorExt or TIFFWarningExt should be made + * in any other case, seek or read errors should be passed through */ + do + { + if (sp->in_buffer_file_togo!=0) + { + if (sp->in_buffer_file_pos_log==0) + { + TIFFSeekFile(sp->tif,sp->in_buffer_file_pos,SEEK_SET); + sp->in_buffer_file_pos_log=1; + } + m=OJPEG_BUFFER; + if ((uint64)m>sp->in_buffer_file_togo) + m=(uint16)sp->in_buffer_file_togo; + n=TIFFReadFile(sp->tif,sp->in_buffer,(tmsize_t)m); + if (n==0) + return(0); + assert(n>0); + assert(n<=OJPEG_BUFFER); + assert(n<65536); + assert((uint64)n<=sp->in_buffer_file_togo); + m=(uint16)n; + sp->in_buffer_togo=m; + sp->in_buffer_cur=sp->in_buffer; + sp->in_buffer_file_togo-=m; + sp->in_buffer_file_pos+=m; + break; + } + sp->in_buffer_file_pos_log=0; + switch(sp->in_buffer_source) + { + case osibsNotSetYet: + if (sp->jpeg_interchange_format!=0) + { + sp->in_buffer_file_pos=sp->jpeg_interchange_format; + sp->in_buffer_file_togo=sp->jpeg_interchange_format_length; + } + sp->in_buffer_source=osibsJpegInterchangeFormat; + break; + case osibsJpegInterchangeFormat: + sp->in_buffer_source=osibsStrile; + case osibsStrile: + if (!_TIFFFillStriles( sp->tif ) + || sp->tif->tif_dir.td_stripoffset == NULL + || sp->tif->tif_dir.td_stripbytecount == NULL) + return 0; + + if (sp->in_buffer_next_strile==sp->in_buffer_strile_count) + sp->in_buffer_source=osibsEof; + else + { + sp->in_buffer_file_pos=sp->tif->tif_dir.td_stripoffset[sp->in_buffer_next_strile]; + if (sp->in_buffer_file_pos!=0) + { + if (sp->in_buffer_file_pos>=sp->file_size) + sp->in_buffer_file_pos=0; + else if (sp->tif->tif_dir.td_stripbytecount==NULL) + sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos; + else + { + if (sp->tif->tif_dir.td_stripbytecount == 0) { + TIFFErrorExt(sp->tif->tif_clientdata,sp->tif->tif_name,"Strip byte counts are missing"); + return(0); + } + sp->in_buffer_file_togo=sp->tif->tif_dir.td_stripbytecount[sp->in_buffer_next_strile]; + if (sp->in_buffer_file_togo==0) + sp->in_buffer_file_pos=0; + else if (sp->in_buffer_file_pos+sp->in_buffer_file_togo>sp->file_size) + sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos; + } + } + sp->in_buffer_next_strile++; + } + break; + default: + return(0); + } + } while (1); + return(1); +} + +static int +OJPEGReadByte(OJPEGState* sp, uint8* byte) +{ + if (sp->in_buffer_togo==0) + { + if (OJPEGReadBufferFill(sp)==0) + return(0); + assert(sp->in_buffer_togo>0); + } + *byte=*(sp->in_buffer_cur); + sp->in_buffer_cur++; + sp->in_buffer_togo--; + return(1); +} + +static int +OJPEGReadBytePeek(OJPEGState* sp, uint8* byte) +{ + if (sp->in_buffer_togo==0) + { + if (OJPEGReadBufferFill(sp)==0) + return(0); + assert(sp->in_buffer_togo>0); + } + *byte=*(sp->in_buffer_cur); + return(1); +} + +static void +OJPEGReadByteAdvance(OJPEGState* sp) +{ + assert(sp->in_buffer_togo>0); + sp->in_buffer_cur++; + sp->in_buffer_togo--; +} + +static int +OJPEGReadWord(OJPEGState* sp, uint16* word) +{ + uint8 m; + if (OJPEGReadByte(sp,&m)==0) + return(0); + *word=(m<<8); + if (OJPEGReadByte(sp,&m)==0) + return(0); + *word|=m; + return(1); +} + +static int +OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem) +{ + uint16 mlen; + uint8* mmem; + uint16 n; + assert(len>0); + mlen=len; + mmem = (uint8*)mem; // add (uint8*) cast + do + { + if (sp->in_buffer_togo==0) + { + if (OJPEGReadBufferFill(sp)==0) + return(0); + assert(sp->in_buffer_togo>0); + } + n=mlen; + if (n>sp->in_buffer_togo) + n=sp->in_buffer_togo; + _TIFFmemcpy(mmem,sp->in_buffer_cur,n); + sp->in_buffer_cur+=n; + sp->in_buffer_togo-=n; + mlen-=n; + mmem+=n; + } while(mlen>0); + return(1); +} + +static void +OJPEGReadSkip(OJPEGState* sp, uint16 len) +{ + uint16 m; + uint16 n; + m=len; + n=m; + if (n>sp->in_buffer_togo) + n=sp->in_buffer_togo; + sp->in_buffer_cur+=n; + sp->in_buffer_togo-=n; + m-=n; + if (m>0) + { + assert(sp->in_buffer_togo==0); + n=m; + if ((uint64)n>sp->in_buffer_file_togo) + n=(uint16)sp->in_buffer_file_togo; + sp->in_buffer_file_pos+=n; + sp->in_buffer_file_togo-=n; + sp->in_buffer_file_pos_log=0; + /* we don't skip past jpeginterchangeformat/strile block... + * if that is asked from us, we're dealing with totally bazurk + * data anyway, and we've not seen this happening on any + * testfile, so we might as well likely cause some other + * meaningless error to be passed at some later time + */ + } +} + +static int +OJPEGWriteStream(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + *len=0; + do + { + assert(sp->out_state<=ososEoi); + switch(sp->out_state) + { + case ososSoi: + OJPEGWriteStreamSoi(tif,mem,len); + break; + case ososQTable0: + OJPEGWriteStreamQTable(tif,0,mem,len); + break; + case ososQTable1: + OJPEGWriteStreamQTable(tif,1,mem,len); + break; + case ososQTable2: + OJPEGWriteStreamQTable(tif,2,mem,len); + break; + case ososQTable3: + OJPEGWriteStreamQTable(tif,3,mem,len); + break; + case ososDcTable0: + OJPEGWriteStreamDcTable(tif,0,mem,len); + break; + case ososDcTable1: + OJPEGWriteStreamDcTable(tif,1,mem,len); + break; + case ososDcTable2: + OJPEGWriteStreamDcTable(tif,2,mem,len); + break; + case ososDcTable3: + OJPEGWriteStreamDcTable(tif,3,mem,len); + break; + case ososAcTable0: + OJPEGWriteStreamAcTable(tif,0,mem,len); + break; + case ososAcTable1: + OJPEGWriteStreamAcTable(tif,1,mem,len); + break; + case ososAcTable2: + OJPEGWriteStreamAcTable(tif,2,mem,len); + break; + case ososAcTable3: + OJPEGWriteStreamAcTable(tif,3,mem,len); + break; + case ososDri: + OJPEGWriteStreamDri(tif,mem,len); + break; + case ososSof: + OJPEGWriteStreamSof(tif,mem,len); + break; + case ososSos: + OJPEGWriteStreamSos(tif,mem,len); + break; + case ososCompressed: + if (OJPEGWriteStreamCompressed(tif,mem,len)==0) + return(0); + break; + case ososRst: + OJPEGWriteStreamRst(tif,mem,len); + break; + case ososEoi: + OJPEGWriteStreamEoi(tif,mem,len); + break; + } + } while (*len==0); + return(1); +} + +static void +OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(OJPEG_BUFFER>=2); + sp->out_buffer[0]=255; + sp->out_buffer[1]=JPEG_MARKER_SOI; + *len=2; + *mem=(void*)sp->out_buffer; + sp->out_state++; +} + +static void +OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + if (sp->qtable[table_index]!=0) + { + *mem=(void*)(sp->qtable[table_index]+sizeof(uint32)); + *len=*((uint32*)sp->qtable[table_index])-sizeof(uint32); + } + sp->out_state++; +} + +static void +OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + if (sp->dctable[table_index]!=0) + { + *mem=(void*)(sp->dctable[table_index]+sizeof(uint32)); + *len=*((uint32*)sp->dctable[table_index])-sizeof(uint32); + } + sp->out_state++; +} + +static void +OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + if (sp->actable[table_index]!=0) + { + *mem=(void*)(sp->actable[table_index]+sizeof(uint32)); + *len=*((uint32*)sp->actable[table_index])-sizeof(uint32); + } + sp->out_state++; +} + +static void +OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(OJPEG_BUFFER>=6); + if (sp->restart_interval!=0) + { + sp->out_buffer[0]=255; + sp->out_buffer[1]=JPEG_MARKER_DRI; + sp->out_buffer[2]=0; + sp->out_buffer[3]=4; + sp->out_buffer[4]=(sp->restart_interval>>8); + sp->out_buffer[5]=(sp->restart_interval&255); + *len=6; + *mem=(void*)sp->out_buffer; + } + sp->out_state++; +} + +static void +OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + assert(OJPEG_BUFFER>=2+8+sp->samples_per_pixel_per_plane*3); + assert(255>=8+sp->samples_per_pixel_per_plane*3); + sp->out_buffer[0]=255; + sp->out_buffer[1]=sp->sof_marker_id; + /* Lf */ + sp->out_buffer[2]=0; + sp->out_buffer[3]=8+sp->samples_per_pixel_per_plane*3; + /* P */ + sp->out_buffer[4]=8; + /* Y */ + sp->out_buffer[5]=(sp->sof_y>>8); + sp->out_buffer[6]=(sp->sof_y&255); + /* X */ + sp->out_buffer[7]=(sp->sof_x>>8); + sp->out_buffer[8]=(sp->sof_x&255); + /* Nf */ + sp->out_buffer[9]=sp->samples_per_pixel_per_plane; + for (m=0; msamples_per_pixel_per_plane; m++) + { + /* C */ + sp->out_buffer[10+m*3]=sp->sof_c[sp->plane_sample_offset+m]; + /* H and V */ + sp->out_buffer[10+m*3+1]=sp->sof_hv[sp->plane_sample_offset+m]; + /* Tq */ + sp->out_buffer[10+m*3+2]=sp->sof_tq[sp->plane_sample_offset+m]; + } + *len=10+sp->samples_per_pixel_per_plane*3; + *mem=(void*)sp->out_buffer; + sp->out_state++; +} + +static void +OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + uint8 m; + assert(OJPEG_BUFFER>=2+6+sp->samples_per_pixel_per_plane*2); + assert(255>=6+sp->samples_per_pixel_per_plane*2); + sp->out_buffer[0]=255; + sp->out_buffer[1]=JPEG_MARKER_SOS; + /* Ls */ + sp->out_buffer[2]=0; + sp->out_buffer[3]=6+sp->samples_per_pixel_per_plane*2; + /* Ns */ + sp->out_buffer[4]=sp->samples_per_pixel_per_plane; + for (m=0; msamples_per_pixel_per_plane; m++) + { + /* Cs */ + sp->out_buffer[5+m*2]=sp->sos_cs[sp->plane_sample_offset+m]; + /* Td and Ta */ + sp->out_buffer[5+m*2+1]=sp->sos_tda[sp->plane_sample_offset+m]; + } + /* Ss */ + sp->out_buffer[5+sp->samples_per_pixel_per_plane*2]=0; + /* Se */ + sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+1]=63; + /* Ah and Al */ + sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+2]=0; + *len=8+sp->samples_per_pixel_per_plane*2; + *mem=(void*)sp->out_buffer; + sp->out_state++; +} + +static int +OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + if (sp->in_buffer_togo==0) + { + if (OJPEGReadBufferFill(sp)==0) + return(0); + assert(sp->in_buffer_togo>0); + } + *len=sp->in_buffer_togo; + *mem=(void*)sp->in_buffer_cur; + sp->in_buffer_togo=0; + if (sp->in_buffer_file_togo==0) + { + switch(sp->in_buffer_source) + { + case osibsStrile: + if (sp->in_buffer_next_strilein_buffer_strile_count) + sp->out_state=ososRst; + else + sp->out_state=ososEoi; + break; + case osibsEof: + sp->out_state=ososEoi; + break; + default: + break; + } + } + return(1); +} + +static void +OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(OJPEG_BUFFER>=2); + sp->out_buffer[0]=255; + sp->out_buffer[1]=JPEG_MARKER_RST0+sp->restart_index; + sp->restart_index++; + if (sp->restart_index==8) + sp->restart_index=0; + *len=2; + *mem=(void*)sp->out_buffer; + sp->out_state=ososCompressed; +} + +static void +OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + assert(OJPEG_BUFFER>=2); + sp->out_buffer[0]=255; + sp->out_buffer[1]=JPEG_MARKER_EOI; + *len=2; + *mem=(void*)sp->out_buffer; +} + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static int +jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo) +{ + return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_create_decompress(cinfo),1)); +} +#endif + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static int +jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image) +{ + return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_header(cinfo,require_image),1)); +} +#endif + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static int +jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo) +{ + return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_start_decompress(cinfo),1)); +} +#endif + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static int +jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines) +{ + return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_scanlines(cinfo,scanlines,max_lines),1)); +} +#endif + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static int +jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines) +{ + return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_raw_data(cinfo,data,max_lines),1)); +} +#endif + +#ifndef LIBJPEG_ENCAP_EXTERNAL +static void +jpeg_encap_unwind(TIFF* tif) +{ + OJPEGState* sp=(OJPEGState*)tif->tif_data; + LONGJMP(sp->exit_jmpbuf,1); +} +#endif + +static void +OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message)(cinfo,buffer); + TIFFWarningExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg","%s",buffer); +} + +static void +OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message)(cinfo,buffer); + TIFFErrorExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg","%s",buffer); + jpeg_encap_unwind((TIFF*)(cinfo->client_data)); +} + +static void +OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo) +{ + (void)cinfo; +} + +static boolean +OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo) +{ + TIFF* tif=(TIFF*)cinfo->client_data; + OJPEGState* sp=(OJPEGState*)tif->tif_data; + void* mem=0; + uint32 len=0U; + if (OJPEGWriteStream(tif,&mem,&len)==0) + { + TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Premature end of JPEG data"); + jpeg_encap_unwind(tif); + } + sp->libjpeg_jpeg_source_mgr.bytes_in_buffer = len; + sp->libjpeg_jpeg_source_mgr.next_input_byte = (const JOCTET * )mem; // add (const JOCTET * ) cast + return(1); +} + +static void +OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes) +{ + TIFF* tif=(TIFF*)cinfo->client_data; + (void)num_bytes; + TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error"); + jpeg_encap_unwind(tif); +} + +static boolean +OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired) +{ + TIFF* tif=(TIFF*)cinfo->client_data; + (void)desired; + TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error"); + jpeg_encap_unwind(tif); + return(0); +} + +static void +OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo) +{ + (void)cinfo; +} + +#endif + + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif//#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_open.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_open.c new file mode 100644 index 0000000000..95e8d1f8b9 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_open.c @@ -0,0 +1,728 @@ +/* $Id: tif_open.c,v 1.46 2010-12-06 16:54:54 faxguy Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +/* + * Dummy functions to fill the omitted client procedures. + */ +static int +_tiffDummyMapProc(thandle_t fd, void** pbase, toff_t* psize) +{ + (void) fd; (void) pbase; (void) psize; + return (0); +} + +static void +_tiffDummyUnmapProc(thandle_t fd, void* base, toff_t size) +{ + (void) fd; (void) base; (void) size; +} + +int +_TIFFgetMode(const char* mode, const char* module) +{ + int m = -1; + + switch (mode[0]) { + case 'r': + m = O_RDONLY; + if (mode[1] == '+') + m = O_RDWR; + break; + case 'w': + case 'a': + m = O_RDWR|O_CREAT; + if (mode[0] == 'w') + m |= O_TRUNC; + break; + default: + TIFFErrorExt(0, module, "\"%s\": Bad mode", mode); + break; + } + return (m); +} + +TIFF* +TIFFClientOpen( + const char* name, const char* mode, + thandle_t clientdata, + TIFFReadWriteProc readproc, + TIFFReadWriteProc writeproc, + TIFFSeekProc seekproc, + TIFFCloseProc closeproc, + TIFFSizeProc sizeproc, + TIFFMapFileProc mapproc, + TIFFUnmapFileProc unmapproc +) +{ + static const char module[] = "TIFFClientOpen"; + TIFF *tif; + int m; + const char* cp; + + /* The following are configuration checks. They should be redundant, but should not + * compile to any actual code in an optimised release build anyway. If any of them + * fail, (makefile-based or other) configuration is not correct */ + assert(sizeof(uint8)==1); + assert(sizeof(int8)==1); + assert(sizeof(uint16)==2); + assert(sizeof(int16)==2); + assert(sizeof(uint32)==4); + assert(sizeof(int32)==4); + assert(sizeof(uint64)==8); + assert(sizeof(int64)==8); + assert(sizeof(tmsize_t)==sizeof(void*)); + { + union{ + uint8 a8[2]; + uint16 a16; + } n; + n.a8[0]=1; + n.a8[1]=0; + #ifdef WORDS_BIGENDIAN + assert(n.a16==256); + #else + assert(n.a16==1); + #endif + } + + m = _TIFFgetMode(mode, module); + if (m == -1) + goto bad2; + tif = (TIFF *)_TIFFmalloc((tmsize_t)(sizeof (TIFF) + strlen(name) + 1)); + if (tif == NULL) { + TIFFErrorExt(clientdata, module, "%s: Out of memory (TIFF structure)", name); + goto bad2; + } + _TIFFmemset(tif, 0, sizeof (*tif)); + tif->tif_name = (char *)tif + sizeof (TIFF); + strcpy(tif->tif_name, name); + tif->tif_mode = m &~ (O_CREAT|O_TRUNC); + tif->tif_curdir = (uint16) -1; /* non-existent directory */ + tif->tif_curoff = 0; + tif->tif_curstrip = (uint32) -1; /* invalid strip */ + tif->tif_row = (uint32) -1; /* read/write pre-increment */ + tif->tif_clientdata = clientdata; + if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc) { + TIFFErrorExt(clientdata, module, + "One of the client procedures is NULL pointer."); + goto bad2; + } + tif->tif_readproc = readproc; + tif->tif_writeproc = writeproc; + tif->tif_seekproc = seekproc; + tif->tif_closeproc = closeproc; + tif->tif_sizeproc = sizeproc; + if (mapproc) + tif->tif_mapproc = mapproc; + else + tif->tif_mapproc = _tiffDummyMapProc; + if (unmapproc) + tif->tif_unmapproc = unmapproc; + else + tif->tif_unmapproc = _tiffDummyUnmapProc; + _TIFFSetDefaultCompressionState(tif); /* setup default state */ + /* + * Default is to return data MSB2LSB and enable the + * use of memory-mapped files and strip chopping when + * a file is opened read-only. + */ + tif->tif_flags = FILLORDER_MSB2LSB; + if (m == O_RDONLY ) + tif->tif_flags |= TIFF_MAPPED; + + #ifdef STRIPCHOP_DEFAULT + if (m == O_RDONLY || m == O_RDWR) + tif->tif_flags |= STRIPCHOP_DEFAULT; + #endif + + /* + * Process library-specific flags in the open mode string. + * The following flags may be used to control intrinsic library + * behaviour that may or may not be desirable (usually for + * compatibility with some application that claims to support + * TIFF but only supports some braindead idea of what the + * vendor thinks TIFF is): + * + * 'l' use little-endian byte order for creating a file + * 'b' use big-endian byte order for creating a file + * 'L' read/write information using LSB2MSB bit order + * 'B' read/write information using MSB2LSB bit order + * 'H' read/write information using host bit order + * 'M' enable use of memory-mapped files when supported + * 'm' disable use of memory-mapped files + * 'C' enable strip chopping support when reading + * 'c' disable strip chopping support + * 'h' read TIFF header only, do not load the first IFD + * '4' ClassicTIFF for creating a file (default) + * '8' BigTIFF for creating a file + * + * The use of the 'l' and 'b' flags is strongly discouraged. + * These flags are provided solely because numerous vendors, + * typically on the PC, do not correctly support TIFF; they + * only support the Intel little-endian byte order. This + * support is not configured by default because it supports + * the violation of the TIFF spec that says that readers *MUST* + * support both byte orders. It is strongly recommended that + * you not use this feature except to deal with busted apps + * that write invalid TIFF. And even in those cases you should + * bang on the vendors to fix their software. + * + * The 'L', 'B', and 'H' flags are intended for applications + * that can optimize operations on data by using a particular + * bit order. By default the library returns data in MSB2LSB + * bit order for compatibiltiy with older versions of this + * library. Returning data in the bit order of the native cpu + * makes the most sense but also requires applications to check + * the value of the FillOrder tag; something they probably do + * not do right now. + * + * The 'M' and 'm' flags are provided because some virtual memory + * systems exhibit poor behaviour when large images are mapped. + * These options permit clients to control the use of memory-mapped + * files on a per-file basis. + * + * The 'C' and 'c' flags are provided because the library support + * for chopping up large strips into multiple smaller strips is not + * application-transparent and as such can cause problems. The 'c' + * option permits applications that only want to look at the tags, + * for example, to get the unadulterated TIFF tag information. + */ + for (cp = mode; *cp; cp++) + switch (*cp) { + case 'b': + #ifndef WORDS_BIGENDIAN + if (m&O_CREAT) + tif->tif_flags |= TIFF_SWAB; + #endif + break; + case 'l': + #ifdef WORDS_BIGENDIAN + if ((m&O_CREAT)) + tif->tif_flags |= TIFF_SWAB; + #endif + break; + case 'B': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + FILLORDER_MSB2LSB; + break; + case 'L': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + FILLORDER_LSB2MSB; + break; + case 'H': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + HOST_FILLORDER; + break; + case 'M': + if (m == O_RDONLY) + tif->tif_flags |= TIFF_MAPPED; + break; + case 'm': + if (m == O_RDONLY) + tif->tif_flags &= ~TIFF_MAPPED; + break; + case 'C': + if (m == O_RDONLY) + tif->tif_flags |= TIFF_STRIPCHOP; + break; + case 'c': + if (m == O_RDONLY) + tif->tif_flags &= ~TIFF_STRIPCHOP; + break; + case 'h': + tif->tif_flags |= TIFF_HEADERONLY; + break; + case '8': + if (m&O_CREAT) + tif->tif_flags |= TIFF_BIGTIFF; + break; + } + /* + * Read in TIFF header. + */ + if ((m & O_TRUNC) || + !ReadOK(tif, &tif->tif_header, sizeof (TIFFHeaderClassic))) { + if (tif->tif_mode == O_RDONLY) { + TIFFErrorExt(tif->tif_clientdata, name, + "Cannot read TIFF header"); + goto bad; + } + /* + * Setup header and write. + */ + #ifdef WORDS_BIGENDIAN + tif->tif_header.common.tiff_magic = tif->tif_flags & TIFF_SWAB + ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN; + #else + tif->tif_header.common.tiff_magic = tif->tif_flags & TIFF_SWAB + ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN; + #endif + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + tif->tif_header.common.tiff_version = TIFF_VERSION_CLASSIC; + tif->tif_header.classic.tiff_diroff = 0; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&tif->tif_header.common.tiff_version); + tif->tif_header_size = sizeof(TIFFHeaderClassic); + } + else + { + tif->tif_header.common.tiff_version = TIFF_VERSION_BIG; + tif->tif_header.big.tiff_offsetsize = 8; + tif->tif_header.big.tiff_unused = 0; + tif->tif_header.big.tiff_diroff = 0; + if (tif->tif_flags & TIFF_SWAB) + { + TIFFSwabShort(&tif->tif_header.common.tiff_version); + TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize); + } + tif->tif_header_size = sizeof (TIFFHeaderBig); + } + /* + * The doc for "fopen" for some STD_C_LIBs says that if you + * open a file for modify ("+"), then you must fseek (or + * fflush?) between any freads and fwrites. This is not + * necessary on most systems, but has been shown to be needed + * on Solaris. + */ + TIFFSeekFile( tif, 0, SEEK_SET ); + if (!WriteOK(tif, &tif->tif_header, (tmsize_t)(tif->tif_header_size))) { + TIFFErrorExt(tif->tif_clientdata, name, + "Error writing TIFF header"); + goto bad; + } + /* + * Setup the byte order handling. + */ + if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) { + #ifndef WORDS_BIGENDIAN + tif->tif_flags |= TIFF_SWAB; + #endif + } else { + #ifdef WORDS_BIGENDIAN + tif->tif_flags |= TIFF_SWAB; + #endif + } + /* + * Setup default directory. + */ + if (!TIFFDefaultDirectory(tif)) + goto bad; + tif->tif_diroff = 0; + tif->tif_dirlist = NULL; + tif->tif_dirlistsize = 0; + tif->tif_dirnumber = 0; + return (tif); + } + /* + * Setup the byte order handling. + */ + if (tif->tif_header.common.tiff_magic != TIFF_BIGENDIAN && + tif->tif_header.common.tiff_magic != TIFF_LITTLEENDIAN + #if MDI_SUPPORT + && + #if HOST_BIGENDIAN + tif->tif_header.common.tiff_magic != MDI_BIGENDIAN + #else + tif->tif_header.common.tiff_magic != MDI_LITTLEENDIAN + #endif + ) { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF or MDI file, bad magic number %d (0x%x)", + #else + ) { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF file, bad magic number %d (0x%x)", + #endif + tif->tif_header.common.tiff_magic, + tif->tif_header.common.tiff_magic); + goto bad; + } + if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) { + #ifndef WORDS_BIGENDIAN + tif->tif_flags |= TIFF_SWAB; + #endif + } else { + #ifdef WORDS_BIGENDIAN + tif->tif_flags |= TIFF_SWAB; + #endif + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&tif->tif_header.common.tiff_version); + if ((tif->tif_header.common.tiff_version != TIFF_VERSION_CLASSIC)&& + (tif->tif_header.common.tiff_version != TIFF_VERSION_BIG)) { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF file, bad version number %d (0x%x)", + tif->tif_header.common.tiff_version, + tif->tif_header.common.tiff_version); + goto bad; + } + if (tif->tif_header.common.tiff_version == TIFF_VERSION_CLASSIC) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&tif->tif_header.classic.tiff_diroff); + tif->tif_header_size = sizeof(TIFFHeaderClassic); + } + else + { + if (!ReadOK(tif, ((uint8*)(&tif->tif_header) + sizeof(TIFFHeaderClassic)), (sizeof(TIFFHeaderBig)-sizeof(TIFFHeaderClassic)))) + { + TIFFErrorExt(tif->tif_clientdata, name, + "Cannot read TIFF header"); + goto bad; + } + if (tif->tif_flags & TIFF_SWAB) + { + TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize); + TIFFSwabLong8(&tif->tif_header.big.tiff_diroff); + } + if (tif->tif_header.big.tiff_offsetsize != 8) + { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF file, bad BigTIFF offsetsize %d (0x%x)", + tif->tif_header.big.tiff_offsetsize, + tif->tif_header.big.tiff_offsetsize); + goto bad; + } + if (tif->tif_header.big.tiff_unused != 0) + { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF file, bad BigTIFF unused %d (0x%x)", + tif->tif_header.big.tiff_unused, + tif->tif_header.big.tiff_unused); + goto bad; + } + tif->tif_header_size = sizeof(TIFFHeaderBig); + tif->tif_flags |= TIFF_BIGTIFF; + } + tif->tif_flags |= TIFF_MYBUFFER; + tif->tif_rawcp = tif->tif_rawdata = 0; + tif->tif_rawdatasize = 0; + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = 0; + + switch (mode[0]) { + case 'r': + if (!(tif->tif_flags&TIFF_BIGTIFF)) + tif->tif_nextdiroff = tif->tif_header.classic.tiff_diroff; + else + tif->tif_nextdiroff = tif->tif_header.big.tiff_diroff; + /* + * Try to use a memory-mapped file if the client + * has not explicitly suppressed usage with the + * 'm' flag in the open mode (see above). + */ + if (tif->tif_flags & TIFF_MAPPED) + { + toff_t n; + if (TIFFMapFileContents(tif,(void**)(&tif->tif_base),&n)) + { + tif->tif_size=(tmsize_t)n; + assert((toff_t)tif->tif_size==n); + } + else + tif->tif_flags &= ~TIFF_MAPPED; + } + /* + * Sometimes we do not want to read the first directory (for example, + * it may be broken) and want to proceed to other directories. I this + * case we use the TIFF_HEADERONLY flag to open file and return + * immediately after reading TIFF header. + */ + if (tif->tif_flags & TIFF_HEADERONLY) + return (tif); + + /* + * Setup initial directory. + */ + if (TIFFReadDirectory(tif)) { + tif->tif_rawcc = (tmsize_t)-1; + tif->tif_flags |= TIFF_BUFFERSETUP; + return (tif); + } + break; + case 'a': + /* + * New directories are automatically append + * to the end of the directory chain when they + * are written out (see TIFFWriteDirectory). + */ + if (!TIFFDefaultDirectory(tif)) + goto bad; + return (tif); + } +bad: + tif->tif_mode = O_RDONLY; /* XXX avoid flush */ + TIFFCleanup(tif); +bad2: + return ((TIFF*)0); +} + +/* + * Query functions to access private data. + */ + +/* + * Return open file's name. + */ +const char * +TIFFFileName(TIFF* tif) +{ + return (tif->tif_name); +} + +/* + * Set the file name. + */ +const char * +TIFFSetFileName(TIFF* tif, const char *name) +{ + const char* old_name = tif->tif_name; + tif->tif_name = (char *)name; + return (old_name); +} + +/* + * Return open file's I/O descriptor. + */ +int +TIFFFileno(TIFF* tif) +{ + return (tif->tif_fd); +} + +/* + * Set open file's I/O descriptor, and return previous value. + */ +int +TIFFSetFileno(TIFF* tif, int fd) +{ + int old_fd = tif->tif_fd; + tif->tif_fd = fd; + return old_fd; +} + +/* + * Return open file's clientdata. + */ +thandle_t +TIFFClientdata(TIFF* tif) +{ + return (tif->tif_clientdata); +} + +/* + * Set open file's clientdata, and return previous value. + */ +thandle_t +TIFFSetClientdata(TIFF* tif, thandle_t newvalue) +{ + thandle_t m = tif->tif_clientdata; + tif->tif_clientdata = newvalue; + return m; +} + +/* + * Return read/write mode. + */ +int +TIFFGetMode(TIFF* tif) +{ + return (tif->tif_mode); +} + +/* + * Return read/write mode. + */ +int +TIFFSetMode(TIFF* tif, int mode) +{ + int old_mode = tif->tif_mode; + tif->tif_mode = mode; + return (old_mode); +} + +/* + * Return nonzero if file is organized in + * tiles; zero if organized as strips. + */ +int +TIFFIsTiled(TIFF* tif) +{ + return (isTiled(tif)); +} + +/* + * Return current row being read/written. + */ +uint32 +TIFFCurrentRow(TIFF* tif) +{ + return (tif->tif_row); +} + +/* + * Return index of the current directory. + */ +uint16 +TIFFCurrentDirectory(TIFF* tif) +{ + return (tif->tif_curdir); +} + +/* + * Return current strip. + */ +uint32 +TIFFCurrentStrip(TIFF* tif) +{ + return (tif->tif_curstrip); +} + +/* + * Return current tile. + */ +uint32 +TIFFCurrentTile(TIFF* tif) +{ + return (tif->tif_curtile); +} + +/* + * Return nonzero if the file has byte-swapped data. + */ +int +TIFFIsByteSwapped(TIFF* tif) +{ + return ((tif->tif_flags & TIFF_SWAB) != 0); +} + +/* + * Return nonzero if the data is returned up-sampled. + */ +int +TIFFIsUpSampled(TIFF* tif) +{ + return (isUpSampled(tif)); +} + +/* + * Return nonzero if the data is returned in MSB-to-LSB bit order. + */ +int +TIFFIsMSB2LSB(TIFF* tif) +{ + return (isFillOrder(tif, FILLORDER_MSB2LSB)); +} + +/* + * Return nonzero if given file was written in big-endian order. + */ +int +TIFFIsBigEndian(TIFF* tif) +{ + return (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN); +} + +/* + * Return pointer to file read method. + */ +TIFFReadWriteProc +TIFFGetReadProc(TIFF* tif) +{ + return (tif->tif_readproc); +} + +/* + * Return pointer to file write method. + */ +TIFFReadWriteProc +TIFFGetWriteProc(TIFF* tif) +{ + return (tif->tif_writeproc); +} + +/* + * Return pointer to file seek method. + */ +TIFFSeekProc +TIFFGetSeekProc(TIFF* tif) +{ + return (tif->tif_seekproc); +} + +/* + * Return pointer to file close method. + */ +TIFFCloseProc +TIFFGetCloseProc(TIFF* tif) +{ + return (tif->tif_closeproc); +} + +/* + * Return pointer to file size requesting method. + */ +TIFFSizeProc +TIFFGetSizeProc(TIFF* tif) +{ + return (tif->tif_sizeproc); +} + +/* + * Return pointer to memory mapping method. + */ +TIFFMapFileProc +TIFFGetMapFileProc(TIFF* tif) +{ + return (tif->tif_mapproc); +} + +/* + * Return pointer to memory unmapping method. + */ +TIFFUnmapFileProc +TIFFGetUnmapFileProc(TIFF* tif) +{ + return (tif->tif_unmapproc); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_packbits.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_packbits.c new file mode 100644 index 0000000000..6fb517f7e5 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_packbits.c @@ -0,0 +1,302 @@ +/* $Id: tif_packbits.c,v 1.22 2012-06-20 05:25:33 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#ifdef PACKBITS_SUPPORT +/* + * TIFF Library. + * + * PackBits Compression Algorithm Support + */ +#include + +static int +PackBitsPreEncode(TIFF* tif, uint16 s) +{ + (void) s; + + if (!(tif->tif_data = (uint8*)_TIFFmalloc(sizeof(tmsize_t)))) + return (0); + /* + * Calculate the scanline/tile-width size in bytes. + */ + if (isTiled(tif)) + *(tmsize_t*)tif->tif_data = TIFFTileRowSize(tif); + else + *(tmsize_t*)tif->tif_data = TIFFScanlineSize(tif); + return (1); +} + +static int +PackBitsPostEncode(TIFF* tif) +{ + if (tif->tif_data) + _TIFFfree(tif->tif_data); + return (1); +} + +/* + * Encode a run of pixels. + */ +static int +PackBitsEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s) +{ + unsigned char* bp = (unsigned char*) buf; + uint8* op; + uint8* ep; + uint8* lastliteral; + long n, slop; + int b; + enum { BASE, LITERAL, RUN, LITERAL_RUN } state; + + (void) s; + op = tif->tif_rawcp; + ep = tif->tif_rawdata + tif->tif_rawdatasize; + state = BASE; + lastliteral = 0; + while (cc > 0) { + /* + * Find the longest string of identical bytes. + */ + b = *bp++, cc--, n = 1; + for (; cc > 0 && b == *bp; cc--, bp++) + n++; + again: + if (op + 2 >= ep) { /* insure space for new data */ + /* + * Be careful about writing the last + * literal. Must write up to that point + * and then copy the remainder to the + * front of the buffer. + */ + if (state == LITERAL || state == LITERAL_RUN) { + slop = (long)(op - lastliteral); + tif->tif_rawcc += (tmsize_t)(lastliteral - tif->tif_rawcp); + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + while (slop-- > 0) + *op++ = *lastliteral++; + lastliteral = tif->tif_rawcp; + } else { + tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp); + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + } + } + switch (state) { + case BASE: /* initial state, set run/literal */ + if (n > 1) { + state = RUN; + if (n > 128) { + *op++ = (uint8) -127; + *op++ = (uint8) b; + n -= 128; + goto again; + } + *op++ = (uint8)(-(n-1)); + *op++ = (uint8) b; + } else { + lastliteral = op; + *op++ = 0; + *op++ = (uint8) b; + state = LITERAL; + } + break; + case LITERAL: /* last object was literal string */ + if (n > 1) { + state = LITERAL_RUN; + if (n > 128) { + *op++ = (uint8) -127; + *op++ = (uint8) b; + n -= 128; + goto again; + } + *op++ = (uint8)(-(n-1)); /* encode run */ + *op++ = (uint8) b; + } else { /* extend literal */ + if (++(*lastliteral) == 127) + state = BASE; + *op++ = (uint8) b; + } + break; + case RUN: /* last object was run */ + if (n > 1) { + if (n > 128) { + *op++ = (uint8) -127; + *op++ = (uint8) b; + n -= 128; + goto again; + } + *op++ = (uint8)(-(n-1)); + *op++ = (uint8) b; + } else { + lastliteral = op; + *op++ = 0; + *op++ = (uint8) b; + state = LITERAL; + } + break; + case LITERAL_RUN: /* literal followed by a run */ + /* + * Check to see if previous run should + * be converted to a literal, in which + * case we convert literal-run-literal + * to a single literal. + */ + if (n == 1 && op[-2] == (uint8) -1 && + *lastliteral < 126) { + state = (((*lastliteral) += 2) == 127 ? + BASE : LITERAL); + op[-2] = op[-1]; /* replicate */ + } else + state = RUN; + goto again; + } + } + tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp); + tif->tif_rawcp = op; + return (1); +} + +/* + * Encode a rectangular chunk of pixels. We break it up + * into row-sized pieces to insure that encoded runs do + * not span rows. Otherwise, there can be problems with + * the decoder if data is read, for example, by scanlines + * when it was encoded by strips. + */ +static int +PackBitsEncodeChunk(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + tmsize_t rowsize = *(tmsize_t*)tif->tif_data; + + while (cc > 0) { + tmsize_t chunk = rowsize; + + if( cc < chunk ) + chunk = cc; + + if (PackBitsEncode(tif, bp, chunk, s) < 0) + return (-1); + bp += chunk; + cc -= chunk; + } + return (1); +} + +static int +PackBitsDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s) +{ + static const char module[] = "PackBitsDecode"; + char *bp; + tmsize_t cc; + long n; + int b; + + (void) s; + bp = (char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + while (cc > 0 && occ > 0) { + n = (long) *bp++, cc--; + /* + * Watch out for compilers that + * don't sign extend chars... + */ + if (n >= 128) + n -= 256; + if (n < 0) { /* replicate next byte -n+1 times */ + if (n == -128) /* nop */ + continue; + n = -n + 1; + if( occ < (tmsize_t)n ) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Discarding %lu bytes to avoid buffer overrun", + (unsigned long) ((tmsize_t)n - occ)); + n = (long)occ; + } + occ -= n; + b = *bp++, cc--; + while (n-- > 0) + *op++ = (uint8) b; + } else { /* copy next n+1 bytes literally */ + if (occ < (tmsize_t)(n + 1)) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Discarding %lu bytes to avoid buffer overrun", + (unsigned long) ((tmsize_t)n - occ + 1)); + n = (long)occ - 1; + } + if (cc < (tmsize_t) (n+1)) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Terminating PackBitsDecode due to lack of data."); + break; + } + _TIFFmemcpy(op, bp, ++n); + op += n; occ -= n; + bp += n; cc -= n; + } + } + tif->tif_rawcp = (uint8*) bp; + tif->tif_rawcc = cc; + if (occ > 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data for scanline %lu", + (unsigned long) tif->tif_row); + return (0); + } + return (1); +} + +int +TIFFInitPackBits(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_decoderow = PackBitsDecode; + tif->tif_decodestrip = PackBitsDecode; + tif->tif_decodetile = PackBitsDecode; + tif->tif_preencode = PackBitsPreEncode; + tif->tif_postencode = PackBitsPostEncode; + tif->tif_encoderow = PackBitsEncode; + tif->tif_encodestrip = PackBitsEncodeChunk; + tif->tif_encodetile = PackBitsEncodeChunk; + return (1); +} +#endif /* PACKBITS_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_pixarlog.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_pixarlog.c new file mode 100644 index 0000000000..5aaf8be0d9 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_pixarlog.c @@ -0,0 +1,1428 @@ +/* $Id: tif_pixarlog.c,v 1.38 2012-06-21 01:01:53 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1996-1997 Sam Leffler + * Copyright (c) 1996 Pixar + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Pixar, Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Pixar, Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL PIXAR, SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#ifdef PIXARLOG_SUPPORT + +/* + * TIFF Library. + * PixarLog Compression Support + * + * Contributed by Dan McCoy. + * + * PixarLog film support uses the TIFF library to store companded + * 11 bit values into a tiff file, which are compressed using the + * zip compressor. + * + * The codec can take as input and produce as output 32-bit IEEE float values + * as well as 16-bit or 8-bit unsigned integer values. + * + * On writing any of the above are converted into the internal + * 11-bit log format. In the case of 8 and 16 bit values, the + * input is assumed to be unsigned linear color values that represent + * the range 0-1. In the case of IEEE values, the 0-1 range is assumed to + * be the normal linear color range, in addition over 1 values are + * accepted up to a value of about 25.0 to encode "hot" hightlights and such. + * The encoding is lossless for 8-bit values, slightly lossy for the + * other bit depths. The actual color precision should be better + * than the human eye can perceive with extra room to allow for + * error introduced by further image computation. As with any quantized + * color format, it is possible to perform image calculations which + * expose the quantization error. This format should certainly be less + * susceptable to such errors than standard 8-bit encodings, but more + * susceptable than straight 16-bit or 32-bit encodings. + * + * On reading the internal format is converted to the desired output format. + * The program can request which format it desires by setting the internal + * pseudo tag TIFFTAG_PIXARLOGDATAFMT to one of these possible values: + * PIXARLOGDATAFMT_FLOAT = provide IEEE float values. + * PIXARLOGDATAFMT_16BIT = provide unsigned 16-bit integer values + * PIXARLOGDATAFMT_8BIT = provide unsigned 8-bit integer values + * + * alternately PIXARLOGDATAFMT_8BITABGR provides unsigned 8-bit integer + * values with the difference that if there are exactly three or four channels + * (rgb or rgba) it swaps the channel order (bgr or abgr). + * + * PIXARLOGDATAFMT_11BITLOG provides the internal encoding directly + * packed in 16-bit values. However no tools are supplied for interpreting + * these values. + * + * "hot" (over 1.0) areas written in floating point get clamped to + * 1.0 in the integer data types. + * + * When the file is closed after writing, the bit depth and sample format + * are set always to appear as if 8-bit data has been written into it. + * That way a naive program unaware of the particulars of the encoding + * gets the format it is most likely able to handle. + * + * The codec does it's own horizontal differencing step on the coded + * values so the libraries predictor stuff should be turned off. + * The codec also handle byte swapping the encoded values as necessary + * since the library does not have the information necessary + * to know the bit depth of the raw unencoded buffer. + * + * NOTE: This decoder does not appear to update tif_rawcp, and tif_rawcc. + * This can cause problems with the implementation of CHUNKY_STRIP_READ_SUPPORT + * as noted in http://trac.osgeo.org/gdal/ticket/3894. FrankW - Jan'11 + */ + +#include "tif_predict.h" +#include "../../fx_zlib/include/fx_zlib.h" + +#include +#include +#include + +/* Tables for converting to/from 11 bit coded values */ + +#define TSIZE 2048 /* decode table size (11-bit tokens) */ +#define TSIZEP1 2049 /* Plus one for slop */ +#define ONE 1250 /* token value of 1.0 exactly */ +#define RATIO 1.004 /* nominal ratio for log part */ + +#define CODE_MASK 0x7ff /* 11 bits. */ + +static float Fltsize; +static float LogK1, LogK2; + +#define REPEAT(n, op) { int i; i=n; do { i--; op; } while (i>0); } + +static void +horizontalAccumulateF(uint16 *wp, int n, int stride, float *op, + float *ToLinearF) +{ + register unsigned int cr, cg, cb, ca, mask; + register float t0, t1, t2, t3; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + t0 = ToLinearF[cr = (wp[0] & mask)]; + t1 = ToLinearF[cg = (wp[1] & mask)]; + t2 = ToLinearF[cb = (wp[2] & mask)]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + t0 = ToLinearF[(cr += wp[0]) & mask]; + t1 = ToLinearF[(cg += wp[1]) & mask]; + t2 = ToLinearF[(cb += wp[2]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + } + } else if (stride == 4) { + t0 = ToLinearF[cr = (wp[0] & mask)]; + t1 = ToLinearF[cg = (wp[1] & mask)]; + t2 = ToLinearF[cb = (wp[2] & mask)]; + t3 = ToLinearF[ca = (wp[3] & mask)]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + t0 = ToLinearF[(cr += wp[0]) & mask]; + t1 = ToLinearF[(cg += wp[1]) & mask]; + t2 = ToLinearF[(cb += wp[2]) & mask]; + t3 = ToLinearF[(ca += wp[3]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else { + REPEAT(stride, *op = ToLinearF[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinearF[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate12(uint16 *wp, int n, int stride, int16 *op, + float *ToLinearF) +{ + register unsigned int cr, cg, cb, ca, mask; + register float t0, t1, t2, t3; + +#define SCALE12 2048.0F +#define CLAMP12(t) (((t) < 3071) ? (uint16) (t) : 3071) + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + t0 = ToLinearF[cr = (wp[0] & mask)] * SCALE12; + t1 = ToLinearF[cg = (wp[1] & mask)] * SCALE12; + t2 = ToLinearF[cb = (wp[2] & mask)] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12; + t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12; + t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + } + } else if (stride == 4) { + t0 = ToLinearF[cr = (wp[0] & mask)] * SCALE12; + t1 = ToLinearF[cg = (wp[1] & mask)] * SCALE12; + t2 = ToLinearF[cb = (wp[2] & mask)] * SCALE12; + t3 = ToLinearF[ca = (wp[3] & mask)] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + op[3] = CLAMP12(t3); + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12; + t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12; + t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12; + t3 = ToLinearF[(ca += wp[3]) & mask] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + op[3] = CLAMP12(t3); + } + } else { + REPEAT(stride, t0 = ToLinearF[*wp&mask] * SCALE12; + *op = CLAMP12(t0); wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; t0 = ToLinearF[wp[stride]&mask]*SCALE12; + *op = CLAMP12(t0); wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate16(uint16 *wp, int n, int stride, uint16 *op, + uint16 *ToLinear16) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = ToLinear16[cr = (wp[0] & mask)]; + op[1] = ToLinear16[cg = (wp[1] & mask)]; + op[2] = ToLinear16[cb = (wp[2] & mask)]; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + op[0] = ToLinear16[(cr += wp[0]) & mask]; + op[1] = ToLinear16[(cg += wp[1]) & mask]; + op[2] = ToLinear16[(cb += wp[2]) & mask]; + } + } else if (stride == 4) { + op[0] = ToLinear16[cr = (wp[0] & mask)]; + op[1] = ToLinear16[cg = (wp[1] & mask)]; + op[2] = ToLinear16[cb = (wp[2] & mask)]; + op[3] = ToLinear16[ca = (wp[3] & mask)]; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + op[0] = ToLinear16[(cr += wp[0]) & mask]; + op[1] = ToLinear16[(cg += wp[1]) & mask]; + op[2] = ToLinear16[(cb += wp[2]) & mask]; + op[3] = ToLinear16[(ca += wp[3]) & mask]; + } + } else { + REPEAT(stride, *op = ToLinear16[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear16[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +/* + * Returns the log encoded 11-bit values with the horizontal + * differencing undone. + */ +static void +horizontalAccumulate11(uint16 *wp, int n, int stride, uint16 *op) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = cr = wp[0]; op[1] = cg = wp[1]; op[2] = cb = wp[2]; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + op[0] = (cr += wp[0]) & mask; + op[1] = (cg += wp[1]) & mask; + op[2] = (cb += wp[2]) & mask; + } + } else if (stride == 4) { + op[0] = cr = wp[0]; op[1] = cg = wp[1]; + op[2] = cb = wp[2]; op[3] = ca = wp[3]; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + op[0] = (cr += wp[0]) & mask; + op[1] = (cg += wp[1]) & mask; + op[2] = (cb += wp[2]) & mask; + op[3] = (ca += wp[3]) & mask; + } + } else { + REPEAT(stride, *op = *wp&mask; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = *wp&mask; wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate8(uint16 *wp, int n, int stride, unsigned char *op, + unsigned char *ToLinear8) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = ToLinear8[cr = (wp[0] & mask)]; + op[1] = ToLinear8[cg = (wp[1] & mask)]; + op[2] = ToLinear8[cb = (wp[2] & mask)]; + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + op += 3; + op[0] = ToLinear8[(cr += wp[0]) & mask]; + op[1] = ToLinear8[(cg += wp[1]) & mask]; + op[2] = ToLinear8[(cb += wp[2]) & mask]; + } + } else if (stride == 4) { + op[0] = ToLinear8[cr = (wp[0] & mask)]; + op[1] = ToLinear8[cg = (wp[1] & mask)]; + op[2] = ToLinear8[cb = (wp[2] & mask)]; + op[3] = ToLinear8[ca = (wp[3] & mask)]; + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + op += 4; + op[0] = ToLinear8[(cr += wp[0]) & mask]; + op[1] = ToLinear8[(cg += wp[1]) & mask]; + op[2] = ToLinear8[(cb += wp[2]) & mask]; + op[3] = ToLinear8[(ca += wp[3]) & mask]; + } + } else { + REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + + +static void +horizontalAccumulate8abgr(uint16 *wp, int n, int stride, unsigned char *op, + unsigned char *ToLinear8) +{ + register unsigned int cr, cg, cb, ca, mask; + register unsigned char t0, t1, t2, t3; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = 0; + t1 = ToLinear8[cb = (wp[2] & mask)]; + t2 = ToLinear8[cg = (wp[1] & mask)]; + t3 = ToLinear8[cr = (wp[0] & mask)]; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + op += 4; + op[0] = 0; + t1 = ToLinear8[(cb += wp[2]) & mask]; + t2 = ToLinear8[(cg += wp[1]) & mask]; + t3 = ToLinear8[(cr += wp[0]) & mask]; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else if (stride == 4) { + t0 = ToLinear8[ca = (wp[3] & mask)]; + t1 = ToLinear8[cb = (wp[2] & mask)]; + t2 = ToLinear8[cg = (wp[1] & mask)]; + t3 = ToLinear8[cr = (wp[0] & mask)]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + op += 4; + t0 = ToLinear8[(ca += wp[3]) & mask]; + t1 = ToLinear8[(cb += wp[2]) & mask]; + t2 = ToLinear8[(cg += wp[1]) & mask]; + t3 = ToLinear8[(cr += wp[0]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else { + REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +/* + * State block for each open TIFF + * file using PixarLog compression/decompression. + */ +typedef struct { + TIFFPredictorState predict; + z_stream stream; + uint16 *tbuf; + uint16 stride; + int state; + int user_datafmt; + int quality; +#define PLSTATE_INIT 1 + + TIFFVSetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + + float *ToLinearF; + uint16 *ToLinear16; + unsigned char *ToLinear8; + uint16 *FromLT2; + uint16 *From14; /* Really for 16-bit data, but we shift down 2 */ + uint16 *From8; + +} PixarLogState; + +static int +PixarLogMakeTables(PixarLogState *sp) +{ + +/* + * We make several tables here to convert between various external + * representations (float, 16-bit, and 8-bit) and the internal + * 11-bit companded representation. The 11-bit representation has two + * distinct regions. A linear bottom end up through .018316 in steps + * of about .000073, and a region of constant ratio up to about 25. + * These floating point numbers are stored in the main table ToLinearF. + * All other tables are derived from this one. The tables (and the + * ratios) are continuous at the internal seam. + */ + + int nlin, lt2size; + int i, j; + double b, c, linstep, v; + float *ToLinearF; + uint16 *ToLinear16; + unsigned char *ToLinear8; + uint16 *FromLT2; + uint16 *From14; /* Really for 16-bit data, but we shift down 2 */ + uint16 *From8; + + c = log(RATIO); + nlin = (int)(1./c); /* nlin must be an integer */ + c = 1./nlin; + b = exp(-c*ONE); /* multiplicative scale factor [b*exp(c*ONE) = 1] */ + linstep = b*c*exp(1.); + + LogK1 = (float)(1./c); /* if (v >= 2) token = k1*log(v*k2) */ + LogK2 = (float)(1./b); + lt2size = (int)(2./linstep) + 1; + FromLT2 = (uint16 *)_TIFFmalloc(lt2size*sizeof(uint16)); + From14 = (uint16 *)_TIFFmalloc(16384*sizeof(uint16)); + From8 = (uint16 *)_TIFFmalloc(256*sizeof(uint16)); + ToLinearF = (float *)_TIFFmalloc(TSIZEP1 * sizeof(float)); + ToLinear16 = (uint16 *)_TIFFmalloc(TSIZEP1 * sizeof(uint16)); + ToLinear8 = (unsigned char *)_TIFFmalloc(TSIZEP1 * sizeof(unsigned char)); + if (FromLT2 == NULL || From14 == NULL || From8 == NULL || + ToLinearF == NULL || ToLinear16 == NULL || ToLinear8 == NULL) { + if (FromLT2) _TIFFfree(FromLT2); + if (From14) _TIFFfree(From14); + if (From8) _TIFFfree(From8); + if (ToLinearF) _TIFFfree(ToLinearF); + if (ToLinear16) _TIFFfree(ToLinear16); + if (ToLinear8) _TIFFfree(ToLinear8); + sp->FromLT2 = NULL; + sp->From14 = NULL; + sp->From8 = NULL; + sp->ToLinearF = NULL; + sp->ToLinear16 = NULL; + sp->ToLinear8 = NULL; + return 0; + } + + j = 0; + + for (i = 0; i < nlin; i++) { + v = i * linstep; + ToLinearF[j++] = (float)v; + } + + for (i = nlin; i < TSIZE; i++) + ToLinearF[j++] = (float)(b*exp(c*i)); + + ToLinearF[2048] = ToLinearF[2047]; + + for (i = 0; i < TSIZEP1; i++) { + v = ToLinearF[i]*65535.0 + 0.5; + ToLinear16[i] = (v > 65535.0) ? 65535 : (uint16)v; + v = ToLinearF[i]*255.0 + 0.5; + ToLinear8[i] = (v > 255.0) ? 255 : (unsigned char)v; + } + + j = 0; + for (i = 0; i < lt2size; i++) { + if ((i*linstep)*(i*linstep) > ToLinearF[j]*ToLinearF[j+1]) + j++; + FromLT2[i] = j; + } + + /* + * Since we lose info anyway on 16-bit data, we set up a 14-bit + * table and shift 16-bit values down two bits on input. + * saves a little table space. + */ + j = 0; + for (i = 0; i < 16384; i++) { + while ((i/16383.)*(i/16383.) > ToLinearF[j]*ToLinearF[j+1]) + j++; + From14[i] = j; + } + + j = 0; + for (i = 0; i < 256; i++) { + while ((i/255.)*(i/255.) > ToLinearF[j]*ToLinearF[j+1]) + j++; + From8[i] = j; + } + + Fltsize = (float)(lt2size/2); + + sp->ToLinearF = ToLinearF; + sp->ToLinear16 = ToLinear16; + sp->ToLinear8 = ToLinear8; + sp->FromLT2 = FromLT2; + sp->From14 = From14; + sp->From8 = From8; + + return 1; +} + +#define DecoderState(tif) ((PixarLogState*) (tif)->tif_data) +#define EncoderState(tif) ((PixarLogState*) (tif)->tif_data) + +static int PixarLogEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s); +static int PixarLogDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s); + +#define PIXARLOGDATAFMT_UNKNOWN -1 + +static int +PixarLogGuessDataFmt(TIFFDirectory *td) +{ + int guess = PIXARLOGDATAFMT_UNKNOWN; + int format = td->td_sampleformat; + + /* If the user didn't tell us his datafmt, + * take our best guess from the bitspersample. + */ + switch (td->td_bitspersample) { + case 32: + if (format == SAMPLEFORMAT_IEEEFP) + guess = PIXARLOGDATAFMT_FLOAT; + break; + case 16: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_16BIT; + break; + case 12: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_INT) + guess = PIXARLOGDATAFMT_12BITPICIO; + break; + case 11: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_11BITLOG; + break; + case 8: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_8BIT; + break; + } + + return guess; +} + +static tmsize_t +multiply_ms(tmsize_t m1, tmsize_t m2) +{ + tmsize_t bytes = m1 * m2; + + if (m1 && bytes / m1 != m2) + bytes = 0; + + return bytes; +} + +static int +PixarLogFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +static int +PixarLogSetupDecode(TIFF* tif) +{ + static const char module[] = "PixarLogSetupDecode"; + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = DecoderState(tif); + tmsize_t tbuf_size; + + assert(sp != NULL); + + /* Make sure no byte swapping happens on the data + * after decompression. */ + tif->tif_postdecode = _TIFFNoPostDecode; + + /* for some reason, we can't do this in TIFFInitPixarLog */ + + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + tbuf_size = multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth), + td->td_rowsperstrip), sizeof(uint16)); + if (tbuf_size == 0) + return (0); /* TODO: this is an error return without error report through TIFFErrorExt */ + sp->tbuf = (uint16 *) _TIFFmalloc(tbuf_size+sizeof(uint16)*sp->stride); + if (sp->tbuf == NULL) + return (0); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) + sp->user_datafmt = PixarLogGuessDataFmt(td); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) { + TIFFErrorExt(tif->tif_clientdata, module, + "PixarLog compression can't handle bits depth/data format combination (depth: %d)", + td->td_bitspersample); + return (0); + } + + if (inflateInit(&sp->stream) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg); + return (0); + } else { + sp->state |= PLSTATE_INIT; + return (1); + } +} + +/* + * Setup state for decoding a strip. + */ +static int +PixarLogPreDecode(TIFF* tif, uint16 s) +{ + static const char module[] = "PixarLogPreDecode"; + PixarLogState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + sp->stream.next_in = tif->tif_rawdata; + assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + apropriately even before we simplify it */ + sp->stream.avail_in = (uInt) tif->tif_rawcc; + if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc) + { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size"); + return (0); + } + return (inflateReset(&sp->stream) == Z_OK); +} + +static int +PixarLogDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s) +{ + static const char module[] = "PixarLogDecode"; + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = DecoderState(tif); + tmsize_t i; + tmsize_t nsamples; + int llen; + uint16 *up; + + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + nsamples = occ / sizeof(float); /* XXX float == 32 bits */ + break; + case PIXARLOGDATAFMT_16BIT: + case PIXARLOGDATAFMT_12BITPICIO: + case PIXARLOGDATAFMT_11BITLOG: + nsamples = occ / sizeof(uint16); /* XXX uint16 == 16 bits */ + break; + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + nsamples = occ; + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "%d bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + + llen = sp->stride * td->td_imagewidth; + + (void) s; + assert(sp != NULL); + sp->stream.next_out = (unsigned char *) sp->tbuf; + assert(sizeof(sp->stream.avail_out)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + apropriately even before we simplify it */ + sp->stream.avail_out = (uInt) (nsamples * sizeof(uint16)); + if (sp->stream.avail_out != nsamples * sizeof(uint16)) + { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size"); + return (0); + } + do { + int state = inflate(&sp->stream, Z_PARTIAL_FLUSH); + if (state == Z_STREAM_END) { + break; /* XXX */ + } + if (state == Z_DATA_ERROR) { + TIFFErrorExt(tif->tif_clientdata, module, + "Decoding error at scanline %lu, %s", + (unsigned long) tif->tif_row, sp->stream.msg); + if (inflateSync(&sp->stream) != Z_OK) + return (0); + continue; + } + if (state != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", + sp->stream.msg); + return (0); + } + } while (sp->stream.avail_out > 0); + + /* hopefully, we got all the bytes we needed */ + if (sp->stream.avail_out != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at scanline %lu (short " TIFF_UINT64_FORMAT " bytes)", + (unsigned long) tif->tif_row, (TIFF_UINT64_T) sp->stream.avail_out); + return (0); + } + + up = sp->tbuf; + /* Swap bytes in the data if from a different endian machine. */ + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabArrayOfShort(up, nsamples); + + /* + * if llen is not an exact multiple of nsamples, the decode operation + * may overflow the output buffer, so truncate it enough to prevent + * that but still salvage as much data as possible. + */ + if (nsamples % llen) { + TIFFWarningExt(tif->tif_clientdata, module, + "stride %lu is not a multiple of sample count, " + "%lu, data truncated.", (unsigned long) llen, (unsigned long) nsamples); + nsamples -= nsamples % llen; + } + + for (i = 0; i < nsamples; i += llen, up += llen) { + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + horizontalAccumulateF(up, llen, sp->stride, + (float *)op, sp->ToLinearF); + op += llen * sizeof(float); + break; + case PIXARLOGDATAFMT_16BIT: + horizontalAccumulate16(up, llen, sp->stride, + (uint16 *)op, sp->ToLinear16); + op += llen * sizeof(uint16); + break; + case PIXARLOGDATAFMT_12BITPICIO: + horizontalAccumulate12(up, llen, sp->stride, + (int16 *)op, sp->ToLinearF); + op += llen * sizeof(int16); + break; + case PIXARLOGDATAFMT_11BITLOG: + horizontalAccumulate11(up, llen, sp->stride, + (uint16 *)op); + op += llen * sizeof(uint16); + break; + case PIXARLOGDATAFMT_8BIT: + horizontalAccumulate8(up, llen, sp->stride, + (unsigned char *)op, sp->ToLinear8); + op += llen * sizeof(unsigned char); + break; + case PIXARLOGDATAFMT_8BITABGR: + horizontalAccumulate8abgr(up, llen, sp->stride, + (unsigned char *)op, sp->ToLinear8); + op += llen * sizeof(unsigned char); + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "Unsupported bits/sample: %d", + td->td_bitspersample); + return (0); + } + } + + return (1); +} + +static int +PixarLogSetupEncode(TIFF* tif) +{ + static const char module[] = "PixarLogSetupEncode"; + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = EncoderState(tif); + tmsize_t tbuf_size; + + assert(sp != NULL); + + /* for some reason, we can't do this in TIFFInitPixarLog */ + + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + tbuf_size = multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth), + td->td_rowsperstrip), sizeof(uint16)); + if (tbuf_size == 0) + return (0); /* TODO: this is an error return without error report through TIFFErrorExt */ + sp->tbuf = (uint16 *) _TIFFmalloc(tbuf_size); + if (sp->tbuf == NULL) + return (0); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) + sp->user_datafmt = PixarLogGuessDataFmt(td); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) { + TIFFErrorExt(tif->tif_clientdata, module, "PixarLog compression can't handle %d bit linear encodings", td->td_bitspersample); + return (0); + } + + if (deflateInit(&sp->stream, sp->quality) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg); + return (0); + } else { + sp->state |= PLSTATE_INIT; + return (1); + } +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +PixarLogPreEncode(TIFF* tif, uint16 s) +{ + static const char module[] = "PixarLogPreEncode"; + PixarLogState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + sp->stream.next_out = tif->tif_rawdata; + assert(sizeof(sp->stream.avail_out)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + apropriately even before we simplify it */ + sp->stream.avail_out = (uInt)tif->tif_rawdatasize; + if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) + { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size"); + return (0); + } + return (deflateReset(&sp->stream) == Z_OK); +} + +static void +horizontalDifferenceF(float *ip, int n, int stride, uint16 *wp, uint16 *FromLT2) +{ + int32 r1, g1, b1, a1, r2, g2, b2, a2, mask; + float fltsize = Fltsize; + +#define CLAMP(v) ( (v<(float)0.) ? 0 \ + : (v<(float)2.) ? FromLT2[(int)(v*fltsize)] \ + : (v>(float)24.2) ? 2047 \ + : LogK1*log(v*LogK2) + 0.5 ) + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = (uint16) CLAMP(ip[0]); + g2 = wp[1] = (uint16) CLAMP(ip[1]); + b2 = wp[2] = (uint16) CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + ip += 3; + r1 = (int32) CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = (int32) CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = (int32) CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + } + } else if (stride == 4) { + r2 = wp[0] = (uint16) CLAMP(ip[0]); + g2 = wp[1] = (uint16) CLAMP(ip[1]); + b2 = wp[2] = (uint16) CLAMP(ip[2]); + a2 = wp[3] = (uint16) CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + ip += 4; + r1 = (int32) CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = (int32) CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = (int32) CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + a1 = (int32) CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1; + } + } else { + ip += n - 1; /* point to last one */ + wp += n - 1; /* point to last one */ + n -= stride; + while (n > 0) { + REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]); + wp[stride] -= wp[0]; + wp[stride] &= mask; + wp--; ip--) + n -= stride; + } + REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]); wp--; ip--) + } + } +} + +static void +horizontalDifference16(unsigned short *ip, int n, int stride, + unsigned short *wp, uint16 *From14) +{ + register int r1, g1, b1, a1, r2, g2, b2, a2, mask; + +/* assumption is unsigned pixel values */ +#undef CLAMP +#define CLAMP(v) From14[(v) >> 2] + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + ip += 3; + r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + } + } else if (stride == 4) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); a2 = wp[3] = CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + ip += 4; + r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + a1 = CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1; + } + } else { + ip += n - 1; /* point to last one */ + wp += n - 1; /* point to last one */ + n -= stride; + while (n > 0) { + REPEAT(stride, wp[0] = CLAMP(ip[0]); + wp[stride] -= wp[0]; + wp[stride] &= mask; + wp--; ip--) + n -= stride; + } + REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--) + } + } +} + + +static void +horizontalDifference8(unsigned char *ip, int n, int stride, + unsigned short *wp, uint16 *From8) +{ + register int r1, g1, b1, a1, r2, g2, b2, a2, mask; + +#undef CLAMP +#define CLAMP(v) (From8[(v)]) + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + r1 = CLAMP(ip[3]); wp[3] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[4]); wp[4] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[5]); wp[5] = (b1-b2) & mask; b2 = b1; + wp += 3; + ip += 3; + } + } else if (stride == 4) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); a2 = wp[3] = CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + r1 = CLAMP(ip[4]); wp[4] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[5]); wp[5] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[6]); wp[6] = (b1-b2) & mask; b2 = b1; + a1 = CLAMP(ip[7]); wp[7] = (a1-a2) & mask; a2 = a1; + wp += 4; + ip += 4; + } + } else { + wp += n + stride - 1; /* point to last one */ + ip += n + stride - 1; /* point to last one */ + n -= stride; + while (n > 0) { + REPEAT(stride, wp[0] = CLAMP(ip[0]); + wp[stride] -= wp[0]; + wp[stride] &= mask; + wp--; ip--) + n -= stride; + } + REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--) + } + } +} + +/* + * Encode a chunk of pixels. + */ +static int +PixarLogEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + static const char module[] = "PixarLogEncode"; + TIFFDirectory *td = &tif->tif_dir; + PixarLogState *sp = EncoderState(tif); + tmsize_t i; + tmsize_t n; + int llen; + unsigned short * up; + + (void) s; + + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + n = cc / sizeof(float); /* XXX float == 32 bits */ + break; + case PIXARLOGDATAFMT_16BIT: + case PIXARLOGDATAFMT_12BITPICIO: + case PIXARLOGDATAFMT_11BITLOG: + n = cc / sizeof(uint16); /* XXX uint16 == 16 bits */ + break; + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + n = cc; + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "%d bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + + llen = sp->stride * td->td_imagewidth; + + for (i = 0, up = sp->tbuf; i < n; i += llen, up += llen) { + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + horizontalDifferenceF((float *)bp, llen, + sp->stride, up, sp->FromLT2); + bp += llen * sizeof(float); + break; + case PIXARLOGDATAFMT_16BIT: + horizontalDifference16((uint16 *)bp, llen, + sp->stride, up, sp->From14); + bp += llen * sizeof(uint16); + break; + case PIXARLOGDATAFMT_8BIT: + horizontalDifference8((unsigned char *)bp, llen, + sp->stride, up, sp->From8); + bp += llen * sizeof(unsigned char); + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "%d bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + } + + sp->stream.next_in = (unsigned char *) sp->tbuf; + assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + apropriately even before we simplify it */ + sp->stream.avail_in = (uInt) (n * sizeof(uint16)); + if ((sp->stream.avail_in / sizeof(uint16)) != (uInt) n) + { + TIFFErrorExt(tif->tif_clientdata, module, + "ZLib cannot deal with buffers this size"); + return (0); + } + + do { + if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "Encoder error: %s", + sp->stream.msg); + return (0); + } + if (sp->stream.avail_out == 0) { + tif->tif_rawcc = tif->tif_rawdatasize; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (uInt) tif->tif_rawdatasize; /* this is a safe typecast, as check is made already in PixarLogPreEncode */ + } + } while (sp->stream.avail_in > 0); + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ + +static int +PixarLogPostEncode(TIFF* tif) +{ + static const char module[] = "PixarLogPostEncode"; + PixarLogState *sp = EncoderState(tif); + int state; + + sp->stream.avail_in = 0; + + do { + state = deflate(&sp->stream, Z_FINISH); + switch (state) { + case Z_STREAM_END: + case Z_OK: + if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) { + tif->tif_rawcc = + tif->tif_rawdatasize - sp->stream.avail_out; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (uInt) tif->tif_rawdatasize; /* this is a safe typecast, as check is made already in PixarLogPreEncode */ + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", + sp->stream.msg); + return (0); + } + } while (state != Z_STREAM_END); + return (1); +} + +static void +PixarLogClose(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + + /* In a really sneaky (and really incorrect, and untruthfull, and + * troublesome, and error-prone) maneuver that completely goes against + * the spirit of TIFF, and breaks TIFF, on close, we covertly + * modify both bitspersample and sampleformat in the directory to + * indicate 8-bit linear. This way, the decode "just works" even for + * readers that don't know about PixarLog, or how to set + * the PIXARLOGDATFMT pseudo-tag. + */ + td->td_bitspersample = 8; + td->td_sampleformat = SAMPLEFORMAT_UINT; +} + +static void +PixarLogCleanup(TIFF* tif) +{ + PixarLogState* sp = (PixarLogState*) tif->tif_data; + + assert(sp != 0); + + (void)TIFFPredictorCleanup(tif); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->FromLT2) _TIFFfree(sp->FromLT2); + if (sp->From14) _TIFFfree(sp->From14); + if (sp->From8) _TIFFfree(sp->From8); + if (sp->ToLinearF) _TIFFfree(sp->ToLinearF); + if (sp->ToLinear16) _TIFFfree(sp->ToLinear16); + if (sp->ToLinear8) _TIFFfree(sp->ToLinear8); + if (sp->state&PLSTATE_INIT) { + if (tif->tif_mode == O_RDONLY) + inflateEnd(&sp->stream); + else + deflateEnd(&sp->stream); + } + if (sp->tbuf) + _TIFFfree(sp->tbuf); + _TIFFfree(sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int +PixarLogVSetField(TIFF* tif, uint32 tag, va_list ap) +{ + static const char module[] = "PixarLogVSetField"; + PixarLogState *sp = (PixarLogState *)tif->tif_data; + int result; + + switch (tag) { + case TIFFTAG_PIXARLOGQUALITY: + sp->quality = (int) va_arg(ap, int); + if (tif->tif_mode != O_RDONLY && (sp->state&PLSTATE_INIT)) { + if (deflateParams(&sp->stream, + sp->quality, Z_DEFAULT_STRATEGY) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", + sp->stream.msg); + return (0); + } + } + return (1); + case TIFFTAG_PIXARLOGDATAFMT: + sp->user_datafmt = (int) va_arg(ap, int); + /* Tweak the TIFF header so that the rest of libtiff knows what + * size of data will be passed between app and library, and + * assume that the app knows what it is doing and is not + * confused by these header manipulations... + */ + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_11BITLOG: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_12BITPICIO: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + break; + case PIXARLOGDATAFMT_16BIT: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_FLOAT: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); + break; + } + /* + * Must recalculate sizes should bits/sample change. + */ + tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t)(-1); + tif->tif_scanlinesize = TIFFScanlineSize(tif); + result = 1; /* NB: pseudo tag */ + break; + default: + result = (*sp->vsetparent)(tif, tag, ap); + } + return (result); +} + +static int +PixarLogVGetField(TIFF* tif, uint32 tag, va_list ap) +{ + PixarLogState *sp = (PixarLogState *)tif->tif_data; + + switch (tag) { + case TIFFTAG_PIXARLOGQUALITY: + *va_arg(ap, int*) = sp->quality; + break; + case TIFFTAG_PIXARLOGDATAFMT: + *va_arg(ap, int*) = sp->user_datafmt; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static const TIFFField pixarlogFields[] = { + {TIFFTAG_PIXARLOGDATAFMT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL}, + {TIFFTAG_PIXARLOGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL} +}; + +int +TIFFInitPixarLog(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitPixarLog"; + + PixarLogState* sp; + + assert(scheme == COMPRESSION_PIXARLOG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, pixarlogFields, + TIFFArrayCount(pixarlogFields))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging PixarLog codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8*) _TIFFmalloc(sizeof (PixarLogState)); + if (tif->tif_data == NULL) + goto bad; + sp = (PixarLogState*) tif->tif_data; + _TIFFmemset(sp, 0, sizeof (*sp)); + sp->stream.data_type = Z_BINARY; + sp->user_datafmt = PIXARLOGDATAFMT_UNKNOWN; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = PixarLogFixupTags; + tif->tif_setupdecode = PixarLogSetupDecode; + tif->tif_predecode = PixarLogPreDecode; + tif->tif_decoderow = PixarLogDecode; + tif->tif_decodestrip = PixarLogDecode; + tif->tif_decodetile = PixarLogDecode; + tif->tif_setupencode = PixarLogSetupEncode; + tif->tif_preencode = PixarLogPreEncode; + tif->tif_postencode = PixarLogPostEncode; + tif->tif_encoderow = PixarLogEncode; + tif->tif_encodestrip = PixarLogEncode; + tif->tif_encodetile = PixarLogEncode; + tif->tif_close = PixarLogClose; + tif->tif_cleanup = PixarLogCleanup; + + /* Override SetField so we can handle our private pseudo-tag */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = PixarLogVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = PixarLogVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->quality = Z_DEFAULT_COMPRESSION; /* default comp. level */ + sp->state = 0; + + /* we don't wish to use the predictor, + * the default is none, which predictor value 1 + */ + (void) TIFFPredictorInit(tif); + + /* + * build the companding tables + */ + PixarLogMakeTables(sp); + + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "No space for PixarLog state block"); + return (0); +} +#endif /* PIXARLOG_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.c new file mode 100644 index 0000000000..190d01644a --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.c @@ -0,0 +1,813 @@ +/* $Id: tif_predict.c,v 1.32 2010-03-10 18:56:49 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Predictor Tag Support (used by multiple codecs). + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#include "tif_predict.h" + +#define PredictorState(tif) ((TIFFPredictorState*) (tif)->tif_data) + +static void horAcc8(TIFF* tif, uint8* cp0, tmsize_t cc); +static void horAcc16(TIFF* tif, uint8* cp0, tmsize_t cc); +static void horAcc32(TIFF* tif, uint8* cp0, tmsize_t cc); +static void swabHorAcc16(TIFF* tif, uint8* cp0, tmsize_t cc); +static void swabHorAcc32(TIFF* tif, uint8* cp0, tmsize_t cc); +static void horDiff8(TIFF* tif, uint8* cp0, tmsize_t cc); +static void horDiff16(TIFF* tif, uint8* cp0, tmsize_t cc); +static void horDiff32(TIFF* tif, uint8* cp0, tmsize_t cc); +static void fpAcc(TIFF* tif, uint8* cp0, tmsize_t cc); +static void fpDiff(TIFF* tif, uint8* cp0, tmsize_t cc); +static int PredictorDecodeRow(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s); +static int PredictorDecodeTile(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s); +static int PredictorEncodeRow(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s); +static int PredictorEncodeTile(TIFF* tif, uint8* bp0, tmsize_t cc0, uint16 s); + +static int +PredictorSetup(TIFF* tif) +{ + static const char module[] = "PredictorSetup"; + + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + switch (sp->predictor) /* no differencing */ + { + case PREDICTOR_NONE: + return 1; + case PREDICTOR_HORIZONTAL: + if (td->td_bitspersample != 8 + && td->td_bitspersample != 16 + && td->td_bitspersample != 32) { + TIFFErrorExt(tif->tif_clientdata, module, + "Horizontal differencing \"Predictor\" not supported with %d-bit samples", + td->td_bitspersample); + return 0; + } + break; + case PREDICTOR_FLOATINGPOINT: + if (td->td_sampleformat != SAMPLEFORMAT_IEEEFP) { + TIFFErrorExt(tif->tif_clientdata, module, + "Floating point \"Predictor\" not supported with %d data format", + td->td_sampleformat); + return 0; + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "\"Predictor\" value %d not supported", + sp->predictor); + return 0; + } + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + /* + * Calculate the scanline/tile-width size in bytes. + */ + if (isTiled(tif)) + sp->rowsize = TIFFTileRowSize(tif); + else + sp->rowsize = TIFFScanlineSize(tif); + if (sp->rowsize == 0) + return 0; + + return 1; +} + +static int +PredictorSetupDecode(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + if (!(*sp->setupdecode)(tif) || !PredictorSetup(tif)) + return 0; + + if (sp->predictor == 2) { + switch (td->td_bitspersample) { + case 8: sp->decodepfunc = horAcc8; break; + case 16: sp->decodepfunc = horAcc16; break; + case 32: sp->decodepfunc = horAcc32; break; + } + /* + * Override default decoding method with one that does the + * predictor stuff. + */ + if( tif->tif_decoderow != PredictorDecodeRow ) + { + sp->decoderow = tif->tif_decoderow; + tif->tif_decoderow = PredictorDecodeRow; + sp->decodestrip = tif->tif_decodestrip; + tif->tif_decodestrip = PredictorDecodeTile; + sp->decodetile = tif->tif_decodetile; + tif->tif_decodetile = PredictorDecodeTile; + } + + /* + * If the data is horizontally differenced 16-bit data that + * requires byte-swapping, then it must be byte swapped before + * the accumulation step. We do this with a special-purpose + * routine and override the normal post decoding logic that + * the library setup when the directory was read. + */ + if (tif->tif_flags & TIFF_SWAB) { + if (sp->decodepfunc == horAcc16) { + sp->decodepfunc = swabHorAcc16; + tif->tif_postdecode = _TIFFNoPostDecode; + } else if (sp->decodepfunc == horAcc32) { + sp->decodepfunc = swabHorAcc32; + tif->tif_postdecode = _TIFFNoPostDecode; + } + } + } + + else if (sp->predictor == 3) { + sp->decodepfunc = fpAcc; + /* + * Override default decoding method with one that does the + * predictor stuff. + */ + if( tif->tif_decoderow != PredictorDecodeRow ) + { + sp->decoderow = tif->tif_decoderow; + tif->tif_decoderow = PredictorDecodeRow; + sp->decodestrip = tif->tif_decodestrip; + tif->tif_decodestrip = PredictorDecodeTile; + sp->decodetile = tif->tif_decodetile; + tif->tif_decodetile = PredictorDecodeTile; + } + /* + * The data should not be swapped outside of the floating + * point predictor, the accumulation routine should return + * byres in the native order. + */ + if (tif->tif_flags & TIFF_SWAB) { + tif->tif_postdecode = _TIFFNoPostDecode; + } + /* + * Allocate buffer to keep the decoded bytes before + * rearranging in the ight order + */ + } + + return 1; +} + +static int +PredictorSetupEncode(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + if (!(*sp->setupencode)(tif) || !PredictorSetup(tif)) + return 0; + + if (sp->predictor == 2) { + switch (td->td_bitspersample) { + case 8: sp->encodepfunc = horDiff8; break; + case 16: sp->encodepfunc = horDiff16; break; + case 32: sp->encodepfunc = horDiff32; break; + } + /* + * Override default encoding method with one that does the + * predictor stuff. + */ + if( tif->tif_encoderow != PredictorEncodeRow ) + { + sp->encoderow = tif->tif_encoderow; + tif->tif_encoderow = PredictorEncodeRow; + sp->encodestrip = tif->tif_encodestrip; + tif->tif_encodestrip = PredictorEncodeTile; + sp->encodetile = tif->tif_encodetile; + tif->tif_encodetile = PredictorEncodeTile; + } + } + + else if (sp->predictor == 3) { + sp->encodepfunc = fpDiff; + /* + * Override default encoding method with one that does the + * predictor stuff. + */ + if( tif->tif_encoderow != PredictorEncodeRow ) + { + sp->encoderow = tif->tif_encoderow; + tif->tif_encoderow = PredictorEncodeRow; + sp->encodestrip = tif->tif_encodestrip; + tif->tif_encodestrip = PredictorEncodeTile; + sp->encodetile = tif->tif_encodetile; + tif->tif_encodetile = PredictorEncodeTile; + } + } + + return 1; +} + +#define REPEAT4(n, op) \ + switch (n) { \ + default: { tmsize_t i; for (i = n-4; i > 0; i--) { op; } } \ + case 4: op; \ + case 3: op; \ + case 2: op; \ + case 1: op; \ + case 0: ; \ + } + +static void +horAcc8(TIFF* tif, uint8* cp0, tmsize_t cc) +{ + /* + * compare v4.0.3 with v3.9.5, + * we find that horAcc8 uses while loop in the v4.0.3 and uses do while loop in the v3.9.5. + * times of do while loop are less than while loop, so we use v3.9.5 instead of v4.0.3. + */ +#if 0 + tmsize_t stride = PredictorState(tif)->stride; + + char* cp = (char*) cp0; + assert((cc%stride)==0); + if (cc > stride) { + /* + * Pipeline the most common cases. + */ + if (stride == 3) { + unsigned int cr = cp[0]; + unsigned int cg = cp[1]; + unsigned int cb = cp[2]; + cc -= 3; + cp += 3; + while (cc>0) { + cp[0] = (char) (cr += cp[0]); + cp[1] = (char) (cg += cp[1]); + cp[2] = (char) (cb += cp[2]); + cc -= 3; + cp += 3; + } + } else if (stride == 4) { + unsigned int cr = cp[0]; + unsigned int cg = cp[1]; + unsigned int cb = cp[2]; + unsigned int ca = cp[3]; + cc -= 4; + cp += 4; + while (cc>0) { + cp[0] = (char) (cr += cp[0]); + cp[1] = (char) (cg += cp[1]); + cp[2] = (char) (cb += cp[2]); + cp[3] = (char) (ca += cp[3]); + cc -= 4; + cp += 4; + } + } else { + cc -= stride; + do { + REPEAT4(stride, cp[stride] = + (char) (cp[stride] + *cp); cp++) + cc -= stride; + } while (cc>0); + } + } +#else + tsize_t stride = PredictorState(tif)->stride; + + char* cp = (char*) cp0; + if (cc > stride) { + cc -= stride; + /* + * Pipeline the most common cases. + */ + if (stride == 3) { + unsigned int cr = cp[0]; + unsigned int cg = cp[1]; + unsigned int cb = cp[2]; + do { + cc -= 3, cp += 3; + cp[0] = (char) (cr += cp[0]); + cp[1] = (char) (cg += cp[1]); + cp[2] = (char) (cb += cp[2]); + } while ((int32) cc > 0); + } else if (stride == 4) { + unsigned int cr = cp[0]; + unsigned int cg = cp[1]; + unsigned int cb = cp[2]; + unsigned int ca = cp[3]; + do { + cc -= 4, cp += 4; + cp[0] = (char) (cr += cp[0]); + cp[1] = (char) (cg += cp[1]); + cp[2] = (char) (cb += cp[2]); + cp[3] = (char) (ca += cp[3]); + } while ((int32) cc > 0); + } else { + do { + REPEAT4(stride, cp[stride] = + (char) (cp[stride] + *cp); cp++) + cc -= stride; + } while ((int32) cc > 0); + } + } +#endif +} + +static void +swabHorAcc16(TIFF* tif, uint8* cp0, tmsize_t cc) +{ + tmsize_t stride = PredictorState(tif)->stride; + uint16* wp = (uint16*) cp0; + tmsize_t wc = cc / 2; + + assert((cc%(2*stride))==0); + + if (wc > stride) { + TIFFSwabArrayOfShort(wp, wc); + wc -= stride; + do { + REPEAT4(stride, wp[stride] += wp[0]; wp++) + wc -= stride; + } while (wc > 0); + } +} + +static void +horAcc16(TIFF* tif, uint8* cp0, tmsize_t cc) +{ + tmsize_t stride = PredictorState(tif)->stride; + uint16* wp = (uint16*) cp0; + tmsize_t wc = cc / 2; + + assert((cc%(2*stride))==0); + + if (wc > stride) { + wc -= stride; + do { + REPEAT4(stride, wp[stride] += wp[0]; wp++) + wc -= stride; + } while (wc > 0); + } +} + +static void +swabHorAcc32(TIFF* tif, uint8* cp0, tmsize_t cc) +{ + tmsize_t stride = PredictorState(tif)->stride; + uint32* wp = (uint32*) cp0; + tmsize_t wc = cc / 4; + + assert((cc%(4*stride))==0); + + if (wc > stride) { + TIFFSwabArrayOfLong(wp, wc); + wc -= stride; + do { + REPEAT4(stride, wp[stride] += wp[0]; wp++) + wc -= stride; + } while (wc > 0); + } +} + +static void +horAcc32(TIFF* tif, uint8* cp0, tmsize_t cc) +{ + tmsize_t stride = PredictorState(tif)->stride; + uint32* wp = (uint32*) cp0; + tmsize_t wc = cc / 4; + + assert((cc%(4*stride))==0); + + if (wc > stride) { + wc -= stride; + do { + REPEAT4(stride, wp[stride] += wp[0]; wp++) + wc -= stride; + } while (wc > 0); + } +} + +/* + * Floating point predictor accumulation routine. + */ +static void +fpAcc(TIFF* tif, uint8* cp0, tmsize_t cc) +{ + tmsize_t stride = PredictorState(tif)->stride; + uint32 bps = tif->tif_dir.td_bitspersample / 8; + tmsize_t wc = cc / bps; + tmsize_t count = cc; + uint8 *cp = (uint8 *) cp0; + uint8 *tmp = (uint8 *)_TIFFmalloc(cc); + + assert((cc%(bps*stride))==0); + + if (!tmp) + return; + + while (count > stride) { + REPEAT4(stride, cp[stride] += cp[0]; cp++) + count -= stride; + } + + _TIFFmemcpy(tmp, cp0, cc); + cp = (uint8 *) cp0; + for (count = 0; count < wc; count++) { + uint32 byte; + for (byte = 0; byte < bps; byte++) { + #if WORDS_BIGENDIAN + cp[bps * count + byte] = tmp[byte * wc + count]; + #else + cp[bps * count + byte] = + tmp[(bps - byte - 1) * wc + count]; + #endif + } + } + _TIFFfree(tmp); +} + +/* + * Decode a scanline and apply the predictor routine. + */ +static int +PredictorDecodeRow(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->decoderow != NULL); + assert(sp->decodepfunc != NULL); + + if ((*sp->decoderow)(tif, op0, occ0, s)) { + (*sp->decodepfunc)(tif, op0, occ0); + return 1; + } else + return 0; +} + +/* + * Decode a tile/strip and apply the predictor routine. + * Note that horizontal differencing must be done on a + * row-by-row basis. The width of a "row" has already + * been calculated at pre-decode time according to the + * strip/tile dimensions. + */ +static int +PredictorDecodeTile(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->decodetile != NULL); + + if ((*sp->decodetile)(tif, op0, occ0, s)) { + tmsize_t rowsize = sp->rowsize; + assert(rowsize > 0); + assert((occ0%rowsize)==0); + assert(sp->decodepfunc != NULL); + while (occ0 > 0) { + (*sp->decodepfunc)(tif, op0, rowsize); + occ0 -= rowsize; + op0 += rowsize; + } + return 1; + } else + return 0; +} + +static void +horDiff8(TIFF* tif, uint8* cp0, tmsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tmsize_t stride = sp->stride; + char* cp = (char*) cp0; + + assert((cc%stride)==0); + + if (cc > stride) { + cc -= stride; + /* + * Pipeline the most common cases. + */ + if (stride == 3) { + int r1, g1, b1; + int r2 = cp[0]; + int g2 = cp[1]; + int b2 = cp[2]; + do { + r1 = cp[3]; cp[3] = r1-r2; r2 = r1; + g1 = cp[4]; cp[4] = g1-g2; g2 = g1; + b1 = cp[5]; cp[5] = b1-b2; b2 = b1; + cp += 3; + } while ((cc -= 3) > 0); + } else if (stride == 4) { + int r1, g1, b1, a1; + int r2 = cp[0]; + int g2 = cp[1]; + int b2 = cp[2]; + int a2 = cp[3]; + do { + r1 = cp[4]; cp[4] = r1-r2; r2 = r1; + g1 = cp[5]; cp[5] = g1-g2; g2 = g1; + b1 = cp[6]; cp[6] = b1-b2; b2 = b1; + a1 = cp[7]; cp[7] = a1-a2; a2 = a1; + cp += 4; + } while ((cc -= 4) > 0); + } else { + cp += cc - 1; + do { + REPEAT4(stride, cp[stride] -= cp[0]; cp--) + } while ((cc -= stride) > 0); + } + } +} + +static void +horDiff16(TIFF* tif, uint8* cp0, tmsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tmsize_t stride = sp->stride; + int16 *wp = (int16*) cp0; + tmsize_t wc = cc/2; + + assert((cc%(2*stride))==0); + + if (wc > stride) { + wc -= stride; + wp += wc - 1; + do { + REPEAT4(stride, wp[stride] -= wp[0]; wp--) + wc -= stride; + } while (wc > 0); + } +} + +static void +horDiff32(TIFF* tif, uint8* cp0, tmsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tmsize_t stride = sp->stride; + int32 *wp = (int32*) cp0; + tmsize_t wc = cc/4; + + assert((cc%(4*stride))==0); + + if (wc > stride) { + wc -= stride; + wp += wc - 1; + do { + REPEAT4(stride, wp[stride] -= wp[0]; wp--) + wc -= stride; + } while (wc > 0); + } +} + +/* + * Floating point predictor differencing routine. + */ +static void +fpDiff(TIFF* tif, uint8* cp0, tmsize_t cc) +{ + tmsize_t stride = PredictorState(tif)->stride; + uint32 bps = tif->tif_dir.td_bitspersample / 8; + tmsize_t wc = cc / bps; + tmsize_t count; + uint8 *cp = (uint8 *) cp0; + uint8 *tmp = (uint8 *)_TIFFmalloc(cc); + + assert((cc%(bps*stride))==0); + + if (!tmp) + return; + + _TIFFmemcpy(tmp, cp0, cc); + for (count = 0; count < wc; count++) { + uint32 byte; + for (byte = 0; byte < bps; byte++) { + #if WORDS_BIGENDIAN + cp[byte * wc + count] = tmp[bps * count + byte]; + #else + cp[(bps - byte - 1) * wc + count] = + tmp[bps * count + byte]; + #endif + } + } + _TIFFfree(tmp); + + cp = (uint8 *) cp0; + cp += cc - stride - 1; + for (count = cc; count > stride; count -= stride) + REPEAT4(stride, cp[stride] -= cp[0]; cp--) +} + +static int +PredictorEncodeRow(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->encodepfunc != NULL); + assert(sp->encoderow != NULL); + + /* XXX horizontal differencing alters user's data XXX */ + (*sp->encodepfunc)(tif, bp, cc); + return (*sp->encoderow)(tif, bp, cc, s); +} + +static int +PredictorEncodeTile(TIFF* tif, uint8* bp0, tmsize_t cc0, uint16 s) +{ + static const char module[] = "PredictorEncodeTile"; + TIFFPredictorState *sp = PredictorState(tif); + uint8 *working_copy; + tmsize_t cc = cc0, rowsize; + unsigned char* bp; + int result_code; + + assert(sp != NULL); + assert(sp->encodepfunc != NULL); + assert(sp->encodetile != NULL); + + /* + * Do predictor manipulation in a working buffer to avoid altering + * the callers buffer. http://trac.osgeo.org/gdal/ticket/1965 + */ + working_copy = (uint8*) _TIFFmalloc(cc0); + if( working_copy == NULL ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Out of memory allocating " TIFF_SSIZE_FORMAT " byte temp buffer.", + cc0 ); + return 0; + } + memcpy( working_copy, bp0, cc0 ); + bp = working_copy; + + rowsize = sp->rowsize; + assert(rowsize > 0); + assert((cc0%rowsize)==0); + while (cc > 0) { + (*sp->encodepfunc)(tif, bp, rowsize); + cc -= rowsize; + bp += rowsize; + } + result_code = (*sp->encodetile)(tif, working_copy, cc0, s); + + _TIFFfree( working_copy ); + + return result_code; +} + +#define FIELD_PREDICTOR (FIELD_CODEC+0) /* XXX */ + +static const TIFFField predictFields[] = { + { TIFFTAG_PREDICTOR, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UINT16, FIELD_PREDICTOR, FALSE, FALSE, "Predictor", NULL }, +}; + +static int +PredictorVSetField(TIFF* tif, uint32 tag, va_list ap) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->vsetparent != NULL); + + switch (tag) { + case TIFFTAG_PREDICTOR: + sp->predictor = (uint16) va_arg(ap, uint16_vap); + TIFFSetFieldBit(tif, FIELD_PREDICTOR); + break; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + tif->tif_flags |= TIFF_DIRTYDIRECT; + return 1; +} + +static int +PredictorVGetField(TIFF* tif, uint32 tag, va_list ap) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->vgetparent != NULL); + + switch (tag) { + case TIFFTAG_PREDICTOR: + *va_arg(ap, uint16*) = sp->predictor; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return 1; +} + +static void +PredictorPrintDir(TIFF* tif, FILE* fd, long flags) +{ + TIFFPredictorState* sp = PredictorState(tif); + + (void) flags; + if (TIFFFieldSet(tif,FIELD_PREDICTOR)) { + fprintf(fd, " Predictor: "); + switch (sp->predictor) { + case 1: fprintf(fd, "none "); break; + case 2: fprintf(fd, "horizontal differencing "); break; + case 3: fprintf(fd, "floating point predictor "); break; + } + fprintf(fd, "%u (0x%x)\n", sp->predictor, sp->predictor); + } + if (sp->printdir) + (*sp->printdir)(tif, fd, flags); +} + +int +TIFFPredictorInit(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + + assert(sp != 0); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, predictFields, + TIFFArrayCount(predictFields))) { + TIFFErrorExt(tif->tif_clientdata, "TIFFPredictorInit", + "Merging Predictor codec-specific tags failed"); + return 0; + } + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = + PredictorVGetField;/* hook for predictor tag */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = + PredictorVSetField;/* hook for predictor tag */ + sp->printdir = tif->tif_tagmethods.printdir; + tif->tif_tagmethods.printdir = + PredictorPrintDir; /* hook for predictor tag */ + + sp->setupdecode = tif->tif_setupdecode; + tif->tif_setupdecode = PredictorSetupDecode; + sp->setupencode = tif->tif_setupencode; + tif->tif_setupencode = PredictorSetupEncode; + + sp->predictor = 1; /* default value */ + sp->encodepfunc = NULL; /* no predictor routine */ + sp->decodepfunc = NULL; /* no predictor routine */ + return 1; +} + +int +TIFFPredictorCleanup(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + tif->tif_tagmethods.printdir = sp->printdir; + tif->tif_setupdecode = sp->setupdecode; + tif->tif_setupencode = sp->setupencode; + + return 1; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.h b/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.h new file mode 100644 index 0000000000..dc7144c69e --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_predict.h @@ -0,0 +1,77 @@ +/* $Id: tif_predict.h,v 1.8 2010-03-10 18:56:49 bfriesen Exp $ */ + +/* + * Copyright (c) 1995-1997 Sam Leffler + * Copyright (c) 1995-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFPREDICT_ +#define _TIFFPREDICT_ +/* + * ``Library-private'' Support for the Predictor Tag + */ + +/* + * Codecs that want to support the Predictor tag must place + * this structure first in their private state block so that + * the predictor code can cast tif_data to find its state. + */ +typedef struct { + int predictor; /* predictor tag value */ + tmsize_t stride; /* sample stride over data */ + tmsize_t rowsize; /* tile/strip row size */ + + TIFFCodeMethod encoderow; /* parent codec encode/decode row */ + TIFFCodeMethod encodestrip; /* parent codec encode/decode strip */ + TIFFCodeMethod encodetile; /* parent codec encode/decode tile */ + TIFFPostMethod encodepfunc; /* horizontal differencer */ + + TIFFCodeMethod decoderow; /* parent codec encode/decode row */ + TIFFCodeMethod decodestrip; /* parent codec encode/decode strip */ + TIFFCodeMethod decodetile; /* parent codec encode/decode tile */ + TIFFPostMethod decodepfunc; /* horizontal accumulator */ + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFPrintMethod printdir; /* super-class method */ + TIFFBoolMethod setupdecode; /* super-class method */ + TIFFBoolMethod setupencode; /* super-class method */ +} TIFFPredictorState; + +#if defined(__cplusplus) +extern "C" { +#endif +extern int TIFFPredictorInit(TIFF*); +extern int TIFFPredictorCleanup(TIFF*); +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFPREDICT_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_print.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_print.c new file mode 100644 index 0000000000..3ee43fc79f --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_print.c @@ -0,0 +1,719 @@ +/* $Id: tif_print.c,v 1.60 2012-08-19 16:56:35 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Printing Support + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#include + +#include + +static void +_TIFFprintAsciiBounded(FILE* fd, const char* cp, int max_chars); + +static const char *photoNames[] = { + "min-is-white", /* PHOTOMETRIC_MINISWHITE */ + "min-is-black", /* PHOTOMETRIC_MINISBLACK */ + "RGB color", /* PHOTOMETRIC_RGB */ + "palette color (RGB from colormap)", /* PHOTOMETRIC_PALETTE */ + "transparency mask", /* PHOTOMETRIC_MASK */ + "separated", /* PHOTOMETRIC_SEPARATED */ + "YCbCr", /* PHOTOMETRIC_YCBCR */ + "7 (0x7)", + "CIE L*a*b*", /* PHOTOMETRIC_CIELAB */ + "ICC L*a*b*", /* PHOTOMETRIC_ICCLAB */ + "ITU L*a*b*" /* PHOTOMETRIC_ITULAB */ +}; +#define NPHOTONAMES (sizeof (photoNames) / sizeof (photoNames[0])) + +static const char *orientNames[] = { + "0 (0x0)", + "row 0 top, col 0 lhs", /* ORIENTATION_TOPLEFT */ + "row 0 top, col 0 rhs", /* ORIENTATION_TOPRIGHT */ + "row 0 bottom, col 0 rhs", /* ORIENTATION_BOTRIGHT */ + "row 0 bottom, col 0 lhs", /* ORIENTATION_BOTLEFT */ + "row 0 lhs, col 0 top", /* ORIENTATION_LEFTTOP */ + "row 0 rhs, col 0 top", /* ORIENTATION_RIGHTTOP */ + "row 0 rhs, col 0 bottom", /* ORIENTATION_RIGHTBOT */ + "row 0 lhs, col 0 bottom", /* ORIENTATION_LEFTBOT */ +}; +#define NORIENTNAMES (sizeof (orientNames) / sizeof (orientNames[0])) + +static void +_TIFFPrintField(FILE* fd, const TIFFField *fip, + uint32 value_count, void *raw_data) +{ + uint32 j; + + fprintf(fd, " %s: ", fip->field_name); + + for(j = 0; j < value_count; j++) { + if(fip->field_type == TIFF_BYTE) + fprintf(fd, "%u", ((uint8 *) raw_data)[j]); + else if(fip->field_type == TIFF_UNDEFINED) + fprintf(fd, "0x%x", + (unsigned int) ((unsigned char *) raw_data)[j]); + else if(fip->field_type == TIFF_SBYTE) + fprintf(fd, "%d", ((int8 *) raw_data)[j]); + else if(fip->field_type == TIFF_SHORT) + fprintf(fd, "%u", ((uint16 *) raw_data)[j]); + else if(fip->field_type == TIFF_SSHORT) + fprintf(fd, "%d", ((int16 *) raw_data)[j]); + else if(fip->field_type == TIFF_LONG) + fprintf(fd, "%lu", + (unsigned long)((uint32 *) raw_data)[j]); + else if(fip->field_type == TIFF_SLONG) + fprintf(fd, "%ld", (long)((int32 *) raw_data)[j]); + else if(fip->field_type == TIFF_IFD) + fprintf(fd, "0x%lx", + (unsigned long)((uint32 *) raw_data)[j]); + else if(fip->field_type == TIFF_RATIONAL + || fip->field_type == TIFF_SRATIONAL + || fip->field_type == TIFF_FLOAT) + fprintf(fd, "%f", ((float *) raw_data)[j]); + else if(fip->field_type == TIFF_LONG8) +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + fprintf(fd, "%I64u", + (unsigned __int64)((uint64 *) raw_data)[j]); +#else + fprintf(fd, "%llu", + (unsigned long long)((uint64 *) raw_data)[j]); +#endif + else if(fip->field_type == TIFF_SLONG8) +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + fprintf(fd, "%I64d", (__int64)((int64 *) raw_data)[j]); +#else + fprintf(fd, "%lld", (long long)((int64 *) raw_data)[j]); +#endif + else if(fip->field_type == TIFF_IFD8) +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + fprintf(fd, "0x%I64x", + (unsigned __int64)((uint64 *) raw_data)[j]); +#else + fprintf(fd, "0x%llx", + (unsigned long long)((uint64 *) raw_data)[j]); +#endif + else if(fip->field_type == TIFF_FLOAT) + fprintf(fd, "%f", ((float *)raw_data)[j]); + else if(fip->field_type == TIFF_DOUBLE) + fprintf(fd, "%f", ((double *) raw_data)[j]); + else if(fip->field_type == TIFF_ASCII) { + fprintf(fd, "%s", (char *) raw_data); + break; + } + else { + fprintf(fd, ""); + break; + } + + if(j < value_count - 1) + fprintf(fd, ","); + } + + fprintf(fd, "\n"); +} + +static int +_TIFFPrettyPrintField(TIFF* tif, const TIFFField *fip, FILE* fd, uint32 tag, + uint32 value_count, void *raw_data) +{ + (void) tif; + + /* do not try to pretty print auto-defined fields */ + if (strncmp(fip->field_name,"Tag ", 4) == 0) { + return 0; + } + + switch (tag) + { + case TIFFTAG_INKSET: + if (value_count == 2 && fip->field_type == TIFF_SHORT) { + fprintf(fd, " Ink Set: "); + switch (*((uint16*)raw_data)) { + case INKSET_CMYK: + fprintf(fd, "CMYK\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + *((uint16*)raw_data), + *((uint16*)raw_data)); + break; + } + return 1; + } + return 0; + + case TIFFTAG_DOTRANGE: + if (value_count == 2 && fip->field_type == TIFF_SHORT) { + fprintf(fd, " Dot Range: %u-%u\n", + ((uint16*)raw_data)[0], ((uint16*)raw_data)[1]); + return 1; + } + return 0; + + case TIFFTAG_WHITEPOINT: + if (value_count == 2 && fip->field_type == TIFF_RATIONAL) { + fprintf(fd, " White Point: %g-%g\n", + ((float *)raw_data)[0], ((float *)raw_data)[1]); + return 1; + } + return 0; + + case TIFFTAG_XMLPACKET: + { + uint32 i; + + fprintf(fd, " XMLPacket (XMP Metadata):\n" ); + for(i = 0; i < value_count; i++) + fputc(((char *)raw_data)[i], fd); + fprintf( fd, "\n" ); + return 1; + } + case TIFFTAG_RICHTIFFIPTC: + /* + * XXX: for some weird reason RichTIFFIPTC tag + * defined as array of LONG values. + */ + fprintf(fd, + " RichTIFFIPTC Data: , %lu bytes\n", + (unsigned long) value_count * 4); + return 1; + + case TIFFTAG_PHOTOSHOP: + fprintf(fd, " Photoshop Data: , %lu bytes\n", + (unsigned long) value_count); + return 1; + + case TIFFTAG_ICCPROFILE: + fprintf(fd, " ICC Profile: , %lu bytes\n", + (unsigned long) value_count); + return 1; + + case TIFFTAG_STONITS: + if (value_count == 1 && fip->field_type == TIFF_DOUBLE) { + fprintf(fd, + " Sample to Nits conversion factor: %.4e\n", + *((double*)raw_data)); + return 1; + } + return 0; + } + + return 0; +} + +/* + * Print the contents of the current directory + * to the specified stdio file stream. + */ +void +TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) +{ + TIFFDirectory *td = &tif->tif_dir; + char *sep; + uint16 i; + long l, n; + +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + fprintf(fd, "TIFF Directory at offset 0x%I64x (%I64u)\n", + (unsigned __int64) tif->tif_diroff, + (unsigned __int64) tif->tif_diroff); +#else + fprintf(fd, "TIFF Directory at offset 0x%llx (%llu)\n", + (unsigned long long) tif->tif_diroff, + (unsigned long long) tif->tif_diroff); +#endif + if (TIFFFieldSet(tif,FIELD_SUBFILETYPE)) { + fprintf(fd, " Subfile Type:"); + sep = " "; + if (td->td_subfiletype & FILETYPE_REDUCEDIMAGE) { + fprintf(fd, "%sreduced-resolution image", sep); + sep = "/"; + } + if (td->td_subfiletype & FILETYPE_PAGE) { + fprintf(fd, "%smulti-page document", sep); + sep = "/"; + } + if (td->td_subfiletype & FILETYPE_MASK) + fprintf(fd, "%stransparency mask", sep); + fprintf(fd, " (%lu = 0x%lx)\n", + (long) td->td_subfiletype, (long) td->td_subfiletype); + } + if (TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS)) { + fprintf(fd, " Image Width: %lu Image Length: %lu", + (unsigned long) td->td_imagewidth, (unsigned long) td->td_imagelength); + if (TIFFFieldSet(tif,FIELD_IMAGEDEPTH)) + fprintf(fd, " Image Depth: %lu", + (unsigned long) td->td_imagedepth); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif,FIELD_TILEDIMENSIONS)) { + fprintf(fd, " Tile Width: %lu Tile Length: %lu", + (unsigned long) td->td_tilewidth, (unsigned long) td->td_tilelength); + if (TIFFFieldSet(tif,FIELD_TILEDEPTH)) + fprintf(fd, " Tile Depth: %lu", + (unsigned long) td->td_tiledepth); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif,FIELD_RESOLUTION)) { + fprintf(fd, " Resolution: %g, %g", + td->td_xresolution, td->td_yresolution); + if (TIFFFieldSet(tif,FIELD_RESOLUTIONUNIT)) { + switch (td->td_resolutionunit) { + case RESUNIT_NONE: + fprintf(fd, " (unitless)"); + break; + case RESUNIT_INCH: + fprintf(fd, " pixels/inch"); + break; + case RESUNIT_CENTIMETER: + fprintf(fd, " pixels/cm"); + break; + default: + fprintf(fd, " (unit %u = 0x%x)", + td->td_resolutionunit, + td->td_resolutionunit); + break; + } + } + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif,FIELD_POSITION)) + fprintf(fd, " Position: %g, %g\n", + td->td_xposition, td->td_yposition); + if (TIFFFieldSet(tif,FIELD_BITSPERSAMPLE)) + fprintf(fd, " Bits/Sample: %u\n", td->td_bitspersample); + if (TIFFFieldSet(tif,FIELD_SAMPLEFORMAT)) { + fprintf(fd, " Sample Format: "); + switch (td->td_sampleformat) { + case SAMPLEFORMAT_VOID: + fprintf(fd, "void\n"); + break; + case SAMPLEFORMAT_INT: + fprintf(fd, "signed integer\n"); + break; + case SAMPLEFORMAT_UINT: + fprintf(fd, "unsigned integer\n"); + break; + case SAMPLEFORMAT_IEEEFP: + fprintf(fd, "IEEE floating point\n"); + break; + case SAMPLEFORMAT_COMPLEXINT: + fprintf(fd, "complex signed integer\n"); + break; + case SAMPLEFORMAT_COMPLEXIEEEFP: + fprintf(fd, "complex IEEE floating point\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_sampleformat, td->td_sampleformat); + break; + } + } + if (TIFFFieldSet(tif,FIELD_COMPRESSION)) { + const TIFFCodec* c = TIFFFindCODEC(td->td_compression); + fprintf(fd, " Compression Scheme: "); + if (c) + fprintf(fd, "%s\n", c->name); + else + fprintf(fd, "%u (0x%x)\n", + td->td_compression, td->td_compression); + } + if (TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) { + fprintf(fd, " Photometric Interpretation: "); + if (td->td_photometric < NPHOTONAMES) + fprintf(fd, "%s\n", photoNames[td->td_photometric]); + else { + switch (td->td_photometric) { + case PHOTOMETRIC_LOGL: + fprintf(fd, "CIE Log2(L)\n"); + break; + case PHOTOMETRIC_LOGLUV: + fprintf(fd, "CIE Log2(L) (u',v')\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_photometric, td->td_photometric); + break; + } + } + } + if (TIFFFieldSet(tif,FIELD_EXTRASAMPLES) && td->td_extrasamples) { + fprintf(fd, " Extra Samples: %u<", td->td_extrasamples); + sep = ""; + for (i = 0; i < td->td_extrasamples; i++) { + switch (td->td_sampleinfo[i]) { + case EXTRASAMPLE_UNSPECIFIED: + fprintf(fd, "%sunspecified", sep); + break; + case EXTRASAMPLE_ASSOCALPHA: + fprintf(fd, "%sassoc-alpha", sep); + break; + case EXTRASAMPLE_UNASSALPHA: + fprintf(fd, "%sunassoc-alpha", sep); + break; + default: + fprintf(fd, "%s%u (0x%x)", sep, + td->td_sampleinfo[i], td->td_sampleinfo[i]); + break; + } + sep = ", "; + } + fprintf(fd, ">\n"); + } + if (TIFFFieldSet(tif,FIELD_INKNAMES)) { + char* cp; + fprintf(fd, " Ink Names: "); + i = td->td_samplesperpixel; + sep = ""; + for (cp = td->td_inknames; + i > 0 && cp < td->td_inknames + td->td_inknameslen; + cp = strchr(cp,'\0')+1, i--) { + int max_chars = + (int)(td->td_inknameslen - (cp - td->td_inknames)); + fputs(sep, fd); + _TIFFprintAsciiBounded(fd, cp, max_chars); + sep = ", "; + } + fputs("\n", fd); + } + if (TIFFFieldSet(tif,FIELD_THRESHHOLDING)) { + fprintf(fd, " Thresholding: "); + switch (td->td_threshholding) { + case THRESHHOLD_BILEVEL: + fprintf(fd, "bilevel art scan\n"); + break; + case THRESHHOLD_HALFTONE: + fprintf(fd, "halftone or dithered scan\n"); + break; + case THRESHHOLD_ERRORDIFFUSE: + fprintf(fd, "error diffused\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_threshholding, td->td_threshholding); + break; + } + } + if (TIFFFieldSet(tif,FIELD_FILLORDER)) { + fprintf(fd, " FillOrder: "); + switch (td->td_fillorder) { + case FILLORDER_MSB2LSB: + fprintf(fd, "msb-to-lsb\n"); + break; + case FILLORDER_LSB2MSB: + fprintf(fd, "lsb-to-msb\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_fillorder, td->td_fillorder); + break; + } + } + if (TIFFFieldSet(tif,FIELD_YCBCRSUBSAMPLING)) + { + fprintf(fd, " YCbCr Subsampling: %u, %u\n", + td->td_ycbcrsubsampling[0], td->td_ycbcrsubsampling[1] ); + } + if (TIFFFieldSet(tif,FIELD_YCBCRPOSITIONING)) { + fprintf(fd, " YCbCr Positioning: "); + switch (td->td_ycbcrpositioning) { + case YCBCRPOSITION_CENTERED: + fprintf(fd, "centered\n"); + break; + case YCBCRPOSITION_COSITED: + fprintf(fd, "cosited\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_ycbcrpositioning, td->td_ycbcrpositioning); + break; + } + } + if (TIFFFieldSet(tif,FIELD_HALFTONEHINTS)) + fprintf(fd, " Halftone Hints: light %u dark %u\n", + td->td_halftonehints[0], td->td_halftonehints[1]); + if (TIFFFieldSet(tif,FIELD_ORIENTATION)) { + fprintf(fd, " Orientation: "); + if (td->td_orientation < NORIENTNAMES) + fprintf(fd, "%s\n", orientNames[td->td_orientation]); + else + fprintf(fd, "%u (0x%x)\n", + td->td_orientation, td->td_orientation); + } + if (TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL)) + fprintf(fd, " Samples/Pixel: %u\n", td->td_samplesperpixel); + if (TIFFFieldSet(tif,FIELD_ROWSPERSTRIP)) { + fprintf(fd, " Rows/Strip: "); + if (td->td_rowsperstrip == (uint32) -1) + fprintf(fd, "(infinite)\n"); + else + fprintf(fd, "%lu\n", (unsigned long) td->td_rowsperstrip); + } + if (TIFFFieldSet(tif,FIELD_MINSAMPLEVALUE)) + fprintf(fd, " Min Sample Value: %u\n", td->td_minsamplevalue); + if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE)) + fprintf(fd, " Max Sample Value: %u\n", td->td_maxsamplevalue); + if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE)) { + int count = (tif->tif_flags & TIFF_PERSAMPLE) ? td->td_samplesperpixel : 1; + fprintf(fd, " SMin Sample Value:"); + for (i = 0; i < count; ++i) + fprintf(fd, " %g", td->td_sminsamplevalue[i]); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE)) { + int count = (tif->tif_flags & TIFF_PERSAMPLE) ? td->td_samplesperpixel : 1; + fprintf(fd, " SMax Sample Value:"); + for (i = 0; i < count; ++i) + fprintf(fd, " %g", td->td_smaxsamplevalue[i]); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif,FIELD_PLANARCONFIG)) { + fprintf(fd, " Planar Configuration: "); + switch (td->td_planarconfig) { + case PLANARCONFIG_CONTIG: + fprintf(fd, "single image plane\n"); + break; + case PLANARCONFIG_SEPARATE: + fprintf(fd, "separate image planes\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_planarconfig, td->td_planarconfig); + break; + } + } + if (TIFFFieldSet(tif,FIELD_PAGENUMBER)) + fprintf(fd, " Page Number: %u-%u\n", + td->td_pagenumber[0], td->td_pagenumber[1]); + if (TIFFFieldSet(tif,FIELD_COLORMAP)) { + fprintf(fd, " Color Map: "); + if (flags & TIFFPRINT_COLORMAP) { + fprintf(fd, "\n"); + n = 1L<td_bitspersample; + for (l = 0; l < n; l++) + fprintf(fd, " %5lu: %5u %5u %5u\n", + l, + td->td_colormap[0][l], + td->td_colormap[1][l], + td->td_colormap[2][l]); + } else + fprintf(fd, "(present)\n"); + } + if (TIFFFieldSet(tif,FIELD_REFBLACKWHITE)) { + fprintf(fd, " Reference Black/White:\n"); + for (i = 0; i < 3; i++) + fprintf(fd, " %2d: %5g %5g\n", i, + td->td_refblackwhite[2*i+0], + td->td_refblackwhite[2*i+1]); + } + if (TIFFFieldSet(tif,FIELD_TRANSFERFUNCTION)) { + fprintf(fd, " Transfer Function: "); + if (flags & TIFFPRINT_CURVES) { + fprintf(fd, "\n"); + n = 1L<td_bitspersample; + for (l = 0; l < n; l++) { + fprintf(fd, " %2lu: %5u", + l, td->td_transferfunction[0][l]); + for (i = 1; i < td->td_samplesperpixel; i++) + fprintf(fd, " %5u", + td->td_transferfunction[i][l]); + fputc('\n', fd); + } + } else + fprintf(fd, "(present)\n"); + } + if (TIFFFieldSet(tif, FIELD_SUBIFD) && (td->td_subifd)) { + fprintf(fd, " SubIFD Offsets:"); + for (i = 0; i < td->td_nsubifd; i++) +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + fprintf(fd, " %5I64u", + (unsigned __int64) td->td_subifd[i]); +#else + fprintf(fd, " %5llu", + (unsigned long long) td->td_subifd[i]); +#endif + fputc('\n', fd); + } + + /* + ** Custom tag support. + */ + { + int i; + short count; + + count = (short) TIFFGetTagListCount(tif); + for(i = 0; i < count; i++) { + uint32 tag = TIFFGetTagListEntry(tif, i); + const TIFFField *fip; + uint32 value_count; + int mem_alloc = 0; + void *raw_data; + + fip = TIFFFieldWithTag(tif, tag); + if(fip == NULL) + continue; + + if(fip->field_passcount) { + if (fip->field_readcount == TIFF_VARIABLE ) { + if(TIFFGetField(tif, tag, &value_count, &raw_data) != 1) + continue; + } else if (fip->field_readcount == TIFF_VARIABLE2 ) { + uint16 small_value_count; + if(TIFFGetField(tif, tag, &small_value_count, &raw_data) != 1) + continue; + value_count = small_value_count; + } else { + assert (fip->field_readcount == TIFF_VARIABLE + || fip->field_readcount == TIFF_VARIABLE2); + continue; + } + } else { + if (fip->field_readcount == TIFF_VARIABLE + || fip->field_readcount == TIFF_VARIABLE2) + value_count = 1; + else if (fip->field_readcount == TIFF_SPP) + value_count = td->td_samplesperpixel; + else + value_count = fip->field_readcount; + if (fip->field_tag == TIFFTAG_DOTRANGE + && strcmp(fip->field_name,"DotRange") == 0) { + /* TODO: This is an evil exception and should not have been + handled this way ... likely best if we move it into + the directory structure with an explicit field in + libtiff 4.1 and assign it a FIELD_ value */ + static uint16 dotrange[2]; + raw_data = dotrange; + TIFFGetField(tif, tag, dotrange+0, dotrange+1); + } else if (fip->field_type == TIFF_ASCII + || fip->field_readcount == TIFF_VARIABLE + || fip->field_readcount == TIFF_VARIABLE2 + || fip->field_readcount == TIFF_SPP + || value_count > 1) { + if(TIFFGetField(tif, tag, &raw_data) != 1) + continue; + } else { + raw_data = _TIFFmalloc( + _TIFFDataSize(fip->field_type) + * value_count); + mem_alloc = 1; + if(TIFFGetField(tif, tag, raw_data) != 1) { + _TIFFfree(raw_data); + continue; + } + } + } + + /* + * Catch the tags which needs to be specially handled + * and pretty print them. If tag not handled in + * _TIFFPrettyPrintField() fall down and print it as + * any other tag. + */ + if (!_TIFFPrettyPrintField(tif, fip, fd, tag, value_count, raw_data)) + _TIFFPrintField(fd, fip, value_count, raw_data); + + if(mem_alloc) + _TIFFfree(raw_data); + } + } + + if (tif->tif_tagmethods.printdir) + (*tif->tif_tagmethods.printdir)(tif, fd, flags); + + _TIFFFillStriles( tif ); + + if ((flags & TIFFPRINT_STRIPS) && + TIFFFieldSet(tif,FIELD_STRIPOFFSETS)) { + uint32 s; + + fprintf(fd, " %lu %s:\n", + (long) td->td_nstrips, + isTiled(tif) ? "Tiles" : "Strips"); + for (s = 0; s < td->td_nstrips; s++) +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + fprintf(fd, " %3lu: [%8I64u, %8I64u]\n", + (unsigned long) s, + (unsigned __int64) td->td_stripoffset[s], + (unsigned __int64) td->td_stripbytecount[s]); +#else + fprintf(fd, " %3lu: [%8llu, %8llu]\n", + (unsigned long) s, + (unsigned long long) td->td_stripoffset[s], + (unsigned long long) td->td_stripbytecount[s]); +#endif + } +} + +void +_TIFFprintAscii(FILE* fd, const char* cp) +{ + _TIFFprintAsciiBounded( fd, cp, (int)strlen(cp)); +} + +static void +_TIFFprintAsciiBounded(FILE* fd, const char* cp, int max_chars) +{ + for (; max_chars > 0 && *cp != '\0'; cp++, max_chars--) { + const char* tp; + + if (isprint((int)*cp)) { + fputc(*cp, fd); + continue; + } + for (tp = "\tt\bb\rr\nn\vv"; *tp; tp++) + if (*tp++ == *cp) + break; + if (*tp) + fprintf(fd, "\\%c", *tp); + else + fprintf(fd, "\\%03o", *cp & 0xff); + } +} + +void +_TIFFprintAsciiTag(FILE* fd, const char* name, const char* value) +{ + fprintf(fd, " %s: \"", name); + _TIFFprintAscii(fd, value); + fprintf(fd, "\"\n"); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_read.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_read.c new file mode 100644 index 0000000000..a25a5a6894 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_read.c @@ -0,0 +1,1116 @@ +/* $Id: tif_read.c,v 1.41 2012-07-06 19:22:58 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * Scanline-oriented Read Support + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#include + +int TIFFFillStrip(TIFF* tif, uint32 strip); +int TIFFFillTile(TIFF* tif, uint32 tile); +static int TIFFStartStrip(TIFF* tif, uint32 strip); +static int TIFFStartTile(TIFF* tif, uint32 tile); +static int TIFFCheckRead(TIFF*, int); +static tmsize_t +TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size,const char* module); + +#define NOSTRIP ((uint32)(-1)) /* undefined state */ +#define NOTILE ((uint32)(-1)) /* undefined state */ + +static int +TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) +{ + static const char module[] = "TIFFFillStripPartial"; + register TIFFDirectory *td = &tif->tif_dir; + uint64 unused_data; + uint64 read_offset; + tmsize_t cc, to_read; + /* tmsize_t bytecountm; */ + + if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) + return 0; + + /* + * Expand raw data buffer, if needed, to hold data + * strip coming from file (perhaps should set upper + * bound on the size of a buffer we'll use?). + */ + + /* bytecountm=(tmsize_t) td->td_stripbytecount[strip]; */ + if (read_ahead*2 > tif->tif_rawdatasize) { + assert( restart ); + + tif->tif_curstrip = NOSTRIP; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Data buffer too small to hold part of strip %lu", + (unsigned long) strip); + return (0); + } + if (!TIFFReadBufferSetup(tif, 0, read_ahead*2)) + return (0); + } + + if( restart ) + { + tif->tif_rawdataloaded = 0; + tif->tif_rawdataoff = 0; + } + + /* + ** If we are reading more data, move any unused data to the + ** start of the buffer. + */ + if( tif->tif_rawdataloaded > 0 ) + unused_data = tif->tif_rawdataloaded - (tif->tif_rawcp - tif->tif_rawdata); + else + unused_data = 0; + + if( unused_data > 0 ) + { + assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); + memmove( tif->tif_rawdata, tif->tif_rawcp, (size_t)unused_data ); + } + + /* + ** Seek to the point in the file where more data should be read. + */ + read_offset = td->td_stripoffset[strip] + + tif->tif_rawdataoff + tif->tif_rawdataloaded; + + if (!SeekOK(tif, read_offset)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Seek error at scanline %lu, strip %lu", + (unsigned long) tif->tif_row, (unsigned long) strip); + return 0; + } + + /* + ** How much do we want to read? + */ + to_read = (tmsize_t)(tif->tif_rawdatasize - unused_data); + if( (uint64) to_read > td->td_stripbytecount[strip] + - tif->tif_rawdataoff - tif->tif_rawdataloaded ) + { + to_read = (tmsize_t)(td->td_stripbytecount[strip] + - tif->tif_rawdataoff - tif->tif_rawdataloaded); + } + + assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); + cc = TIFFReadFile(tif, tif->tif_rawdata + unused_data, to_read); + + if (cc != to_read) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at scanline %lu; got %I64u bytes, expected %I64u", + (unsigned long) tif->tif_row, + (unsigned __int64) cc, + (unsigned __int64) to_read); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at scanline %lu; got %llu bytes, expected %llu", + (unsigned long) tif->tif_row, + (unsigned long long) cc, + (unsigned long long) to_read); +#endif + return 0; + } + + tif->tif_rawdataoff = (tmsize_t)(tif->tif_rawdataoff + tif->tif_rawdataloaded - unused_data) ; + tif->tif_rawdataloaded = (tmsize_t)unused_data + to_read; + + tif->tif_rawcp = tif->tif_rawdata; + + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) { + assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); + TIFFReverseBits(tif->tif_rawdata + unused_data, to_read ); + } + + /* + ** When starting a strip from the beginning we need to + ** restart the decoder. + */ + if( restart ) + return TIFFStartStrip(tif, strip); + else + return 1; +} + +/* + * Seek to a random row+sample in a file. + * + * Only used by TIFFReadScanline, and is only used on + * strip organized files. We do some tricky stuff to try + * and avoid reading the whole compressed raw data for big + * strips. + */ +static int +TIFFSeek(TIFF* tif, uint32 row, uint16 sample ) +{ + register TIFFDirectory *td = &tif->tif_dir; + uint32 strip; + int whole_strip; + tmsize_t read_ahead = 0; + + /* + ** Establish what strip we are working from. + */ + if (row >= td->td_imagelength) { /* out of range */ + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Row out of range, max %lu", + (unsigned long) row, + (unsigned long) td->td_imagelength); + return (0); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Sample out of range, max %lu", + (unsigned long) sample, (unsigned long) td->td_samplesperpixel); + return (0); + } + strip = (uint32)sample*td->td_stripsperimage + row/td->td_rowsperstrip; + } else + strip = row / td->td_rowsperstrip; + + /* + * Do we want to treat this strip as one whole chunk or + * read it a few lines at a time? + */ +#if defined(CHUNKY_STRIP_READ_SUPPORT) + if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) + return 0; + whole_strip = tif->tif_dir.td_stripbytecount[strip] < 10 + || isMapped(tif); +#else + whole_strip = 1; +#endif + + if( !whole_strip ) + { + read_ahead = tif->tif_scanlinesize * 16 + 5000; + } + + /* + * If we haven't loaded this strip, do so now, possibly + * only reading the first part. + */ + if (strip != tif->tif_curstrip) { /* different strip, refill */ + + if( whole_strip ) + { + if (!TIFFFillStrip(tif, strip)) + return (0); + } + else + { + if( !TIFFFillStripPartial(tif,strip,read_ahead,1) ) + return 0; + } + } + + /* + ** If we already have some data loaded, do we need to read some more? + */ + else if( !whole_strip ) + { + if( ((tif->tif_rawdata + tif->tif_rawdataloaded) - tif->tif_rawcp) < read_ahead + && (uint64) tif->tif_rawdataoff+tif->tif_rawdataloaded < td->td_stripbytecount[strip] ) + { + if( !TIFFFillStripPartial(tif,strip,read_ahead,0) ) + return 0; + } + } + + if (row < tif->tif_row) { + /* + * Moving backwards within the same strip: backup + * to the start and then decode forward (below). + * + * NB: If you're planning on lots of random access within a + * strip, it's better to just read and decode the entire + * strip, and then access the decoded data in a random fashion. + */ + + if( tif->tif_rawdataoff != 0 ) + { + if( !TIFFFillStripPartial(tif,strip,read_ahead,1) ) + return 0; + } + else + { + if (!TIFFStartStrip(tif, strip)) + return (0); + } + } + + if (row != tif->tif_row) { + /* + * Seek forward to the desired row. + */ + + /* TODO: Will this really work with partial buffers? */ + + if (!(*tif->tif_seek)(tif, row - tif->tif_row)) + return (0); + tif->tif_row = row; + } + + return (1); +} + +int +TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample) +{ + int e; + + if (!TIFFCheckRead(tif, 0)) + return (-1); + if( (e = TIFFSeek(tif, row, sample)) != 0) { + /* + * Decompress desired row into user buffer. + */ + e = (*tif->tif_decoderow) + (tif, (uint8*) buf, tif->tif_scanlinesize, sample); + + /* we are now poised at the beginning of the next row */ + tif->tif_row = row + 1; + + if (e) + (*tif->tif_postdecode)(tif, (uint8*) buf, + tif->tif_scanlinesize); + } + return (e > 0 ? 1 : -1); +} + +/* + * Read a strip of data and decompress the specified + * amount into the user-supplied buffer. + */ +tmsize_t +TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size) +{ + static const char module[] = "TIFFReadEncodedStrip"; + TIFFDirectory *td = &tif->tif_dir; + uint32 rowsperstrip; + uint32 stripsperplane; + uint32 stripinplane; + uint16 plane, comp; + uint32 rows; + tmsize_t stripsize; + if (!TIFFCheckRead(tif,0)) + return((tmsize_t)(-1)); + if (strip>=td->td_nstrips) + { + TIFFErrorExt(tif->tif_clientdata,module, + "%lu: Strip out of range, max %lu",(unsigned long)strip, + (unsigned long)td->td_nstrips); + return((tmsize_t)(-1)); + } + /* + * Calculate the strip size according to the number of + * rows in the strip (check for truncated last strip on any + * of the separations). + */ + rowsperstrip=td->td_rowsperstrip; + if (rowsperstrip>td->td_imagelength) + rowsperstrip=td->td_imagelength; + stripsperplane=((td->td_imagelength+rowsperstrip-1)/rowsperstrip); + stripinplane=(strip%stripsperplane); + plane=(strip/stripsperplane); + rows=td->td_imagelength-stripinplane*rowsperstrip; + if (rows>rowsperstrip) + rows=rowsperstrip; + stripsize=TIFFVStripSize(tif,rows); + if (stripsize==0) + return((tmsize_t)(-1)); + if ((size!=(tmsize_t)(-1))&&(sizetif_decodestrip)(tif,buf,stripsize,plane)<=0) + return((tmsize_t)(-1)); + (*tif->tif_postdecode)(tif,buf,stripsize); + return(stripsize);*/ + + /* + * Changjin Gao 20110726 fixed decode error issue. + * Test file: mantis #27308 020511-1158450.tiff. + */ + comp = COMPRESSION_NONE; +StripDecode: + if (TIFFFillStrip(tif, strip) && (*tif->tif_decodestrip)(tif, buf, stripsize, plane) > 0) + { + (*tif->tif_postdecode)(tif, buf, stripsize); + return (stripsize); + } + else + { + if (comp < 9) + { + TIFFSetField(tif, TIFFTAG_COMPRESSION, comp); + TIFFSetField(tif, TIFFTAG_FAXMODE,FAXMODE_CLASSIC); + comp++; + goto StripDecode; + } + + return ((tsize_t) -1); + } +} + +static tmsize_t +TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size, + const char* module) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (!_TIFFFillStriles( tif )) + return ((tmsize_t)(-1)); + + assert((tif->tif_flags&TIFF_NOREADRAW)==0); + if (!isMapped(tif)) { + tmsize_t cc; + + if (!SeekOK(tif, td->td_stripoffset[strip])) { + TIFFErrorExt(tif->tif_clientdata, module, + "Seek error at scanline %lu, strip %lu", + (unsigned long) tif->tif_row, (unsigned long) strip); + return ((tmsize_t)(-1)); + } + cc = TIFFReadFile(tif, buf, size); + if (cc != size) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at scanline %lu; got %I64u bytes, expected %I64u", + (unsigned long) tif->tif_row, + (unsigned __int64) cc, + (unsigned __int64) size); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at scanline %lu; got %llu bytes, expected %llu", + (unsigned long) tif->tif_row, + (unsigned long long) cc, + (unsigned long long) size); +#endif + return ((tmsize_t)(-1)); + } + } else { + tmsize_t ma,mb; + tmsize_t n; + ma=(tmsize_t)td->td_stripoffset[strip]; + mb=ma+size; + if (((uint64)ma!=td->td_stripoffset[strip])||(ma>tif->tif_size)) + n=0; + else if ((mbtif->tif_size)) + n=tif->tif_size-ma; + else + n=size; + if (n!=size) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at scanline %lu, strip %lu; got %I64u bytes, expected %I64u", + (unsigned long) tif->tif_row, + (unsigned long) strip, + (unsigned __int64) n, + (unsigned __int64) size); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at scanline %lu, strip %lu; got %llu bytes, expected %llu", + (unsigned long) tif->tif_row, + (unsigned long) strip, + (unsigned long long) n, + (unsigned long long) size); +#endif + return ((tmsize_t)(-1)); + } + _TIFFmemcpy(buf, tif->tif_base + ma, + size); + } + return (size); +} + +/* + * Read a strip of data from the file. + */ +tmsize_t +TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size) +{ + static const char module[] = "TIFFReadRawStrip"; + TIFFDirectory *td = &tif->tif_dir; + uint64 bytecount; + tmsize_t bytecountm; + + if (!TIFFCheckRead(tif, 0)) + return ((tmsize_t)(-1)); + if (strip >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, + "%lu: Strip out of range, max %lu", + (unsigned long) strip, + (unsigned long) td->td_nstrips); + return ((tmsize_t)(-1)); + } + if (tif->tif_flags&TIFF_NOREADRAW) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Compression scheme does not support access to raw uncompressed data"); + return ((tmsize_t)(-1)); + } + bytecount = td->td_stripbytecount[strip]; + if (bytecount <= 0) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "%I64u: Invalid strip byte count, strip %lu", + (unsigned __int64) bytecount, + (unsigned long) strip); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "%llu: Invalid strip byte count, strip %lu", + (unsigned long long) bytecount, + (unsigned long) strip); +#endif + return ((tmsize_t)(-1)); + } + bytecountm = (tmsize_t)bytecount; + if ((uint64)bytecountm!=bytecount) { + TIFFErrorExt(tif->tif_clientdata, module, "Integer overflow"); + return ((tmsize_t)(-1)); + } + if (size != (tmsize_t)(-1) && size < bytecountm) + bytecountm = size; + return (TIFFReadRawStrip1(tif, strip, buf, bytecountm, module)); +} + +/* + * Read the specified strip and setup for decoding. The data buffer is + * expanded, as necessary, to hold the strip's data. + */ +int +TIFFFillStrip(TIFF* tif, uint32 strip) +{ + static const char module[] = "TIFFFillStrip"; + TIFFDirectory *td = &tif->tif_dir; + + if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) + return 0; + + if ((tif->tif_flags&TIFF_NOREADRAW)==0) + { + uint64 bytecount = td->td_stripbytecount[strip]; + if (bytecount <= 0) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "Invalid strip byte count %I64u, strip %lu", + (unsigned __int64) bytecount, + (unsigned long) strip); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "Invalid strip byte count %llu, strip %lu", + (unsigned long long) bytecount, + (unsigned long) strip); +#endif + return (0); + } + if (isMapped(tif) && + (isFillOrder(tif, td->td_fillorder) + || (tif->tif_flags & TIFF_NOBITREV))) { + /* + * The image is mapped into memory and we either don't + * need to flip bits or the compression routine is + * going to handle this operation itself. In this + * case, avoid copying the raw data and instead just + * reference the data from the memory mapped file + * image. This assumes that the decompression + * routines do not modify the contents of the raw data + * buffer (if they try to, the application will get a + * fault since the file is mapped read-only). + */ + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; + } + tif->tif_flags &= ~TIFF_MYBUFFER; + /* + * We must check for overflow, potentially causing + * an OOB read. Instead of simple + * + * td->td_stripoffset[strip]+bytecount > tif->tif_size + * + * comparison (which can overflow) we do the following + * two comparisons: + */ + if (bytecount > (uint64)tif->tif_size || + td->td_stripoffset[strip] > (uint64)tif->tif_size - bytecount) { + /* + * This error message might seem strange, but + * it's what would happen if a read were done + * instead. + */ +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + + "Read error on strip %lu; " + "got %I64u bytes, expected %I64u", + (unsigned long) strip, + (unsigned __int64) tif->tif_size - td->td_stripoffset[strip], + (unsigned __int64) bytecount); +#else + TIFFErrorExt(tif->tif_clientdata, module, + + "Read error on strip %lu; " + "got %llu bytes, expected %llu", + (unsigned long) strip, + (unsigned long long) tif->tif_size - td->td_stripoffset[strip], + (unsigned long long) bytecount); +#endif + tif->tif_curstrip = NOSTRIP; + return (0); + } + tif->tif_rawdatasize = (tmsize_t)bytecount; + tif->tif_rawdata = tif->tif_base + (tmsize_t)td->td_stripoffset[strip]; + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = (tmsize_t) bytecount; + + /* + * When we have tif_rawdata reference directly into the memory mapped file + * we need to be pretty careful about how we use the rawdata. It is not + * a general purpose working buffer as it normally otherwise is. So we + * keep track of this fact to avoid using it improperly. + */ + tif->tif_flags |= TIFF_BUFFERMMAP; + } else { + /* + * Expand raw data buffer, if needed, to hold data + * strip coming from file (perhaps should set upper + * bound on the size of a buffer we'll use?). + */ + tmsize_t bytecountm; + bytecountm=(tmsize_t)bytecount; + if ((uint64)bytecountm!=bytecount) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + return(0); + } + if (bytecountm > tif->tif_rawdatasize) { + tif->tif_curstrip = NOSTRIP; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Data buffer too small to hold strip %lu", + (unsigned long) strip); + return (0); + } + if (!TIFFReadBufferSetup(tif, 0, bytecountm)) + return (0); + } + if (tif->tif_flags&TIFF_BUFFERMMAP) { + tif->tif_curstrip = NOSTRIP; + if (!TIFFReadBufferSetup(tif, 0, bytecountm)) + return (0); + } + if (TIFFReadRawStrip1(tif, strip, tif->tif_rawdata, + bytecountm, module) != bytecountm) + return (0); + + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = bytecountm; + + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, bytecountm); + } + } + return (TIFFStartStrip(tif, strip)); +} + +/* + * Tile-oriented Read Support + * Contributed by Nancy Cam (Silicon Graphics). + */ + +/* + * Read and decompress a tile of data. The + * tile is selected by the (x,y,z,s) coordinates. + */ +tmsize_t +TIFFReadTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s) +{ + if (!TIFFCheckRead(tif, 1) || !TIFFCheckTile(tif, x, y, z, s)) + return ((tmsize_t)(-1)); + return (TIFFReadEncodedTile(tif, + TIFFComputeTile(tif, x, y, z, s), buf, (tmsize_t)(-1))); +} + +/* + * Read a tile of data and decompress the specified + * amount into the user-supplied buffer. + */ +tmsize_t +TIFFReadEncodedTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size) +{ + static const char module[] = "TIFFReadEncodedTile"; + TIFFDirectory *td = &tif->tif_dir; + tmsize_t tilesize = tif->tif_tilesize; + + if (!TIFFCheckRead(tif, 1)) + return ((tmsize_t)(-1)); + if (tile >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, + "%lu: Tile out of range, max %lu", + (unsigned long) tile, (unsigned long) td->td_nstrips); + return ((tmsize_t)(-1)); + } + if (size == (tmsize_t)(-1)) + size = tilesize; + else if (size > tilesize) + size = tilesize; + if (TIFFFillTile(tif, tile) && (*tif->tif_decodetile)(tif, + (uint8*) buf, size, (uint16)(tile/td->td_stripsperimage))) { + (*tif->tif_postdecode)(tif, (uint8*) buf, size); + return (size); + } else + return ((tmsize_t)(-1)); +} + +static tmsize_t +TIFFReadRawTile1(TIFF* tif, uint32 tile, void* buf, tmsize_t size, const char* module) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (!_TIFFFillStriles( tif )) + return ((tmsize_t)(-1)); + + assert((tif->tif_flags&TIFF_NOREADRAW)==0); + if (!isMapped(tif)) { + tmsize_t cc; + + if (!SeekOK(tif, td->td_stripoffset[tile])) { + TIFFErrorExt(tif->tif_clientdata, module, + "Seek error at row %lu, col %lu, tile %lu", + (unsigned long) tif->tif_row, + (unsigned long) tif->tif_col, + (unsigned long) tile); + return ((tmsize_t)(-1)); + } + cc = TIFFReadFile(tif, buf, size); + if (cc != size) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at row %lu, col %lu; got %I64u bytes, expected %I64u", + (unsigned long) tif->tif_row, + (unsigned long) tif->tif_col, + (unsigned __int64) cc, + (unsigned __int64) size); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at row %lu, col %lu; got %llu bytes, expected %llu", + (unsigned long) tif->tif_row, + (unsigned long) tif->tif_col, + (unsigned long long) cc, + (unsigned long long) size); +#endif + return ((tmsize_t)(-1)); + } + } else { + tmsize_t ma,mb; + tmsize_t n; + ma=(tmsize_t)td->td_stripoffset[tile]; + mb=ma+size; + if (((uint64)ma!=td->td_stripoffset[tile])||(ma>tif->tif_size)) + n=0; + else if ((mbtif->tif_size)) + n=tif->tif_size-ma; + else + n=size; + if (n!=size) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, +"Read error at row %lu, col %lu, tile %lu; got %I64u bytes, expected %I64u", + (unsigned long) tif->tif_row, + (unsigned long) tif->tif_col, + (unsigned long) tile, + (unsigned __int64) n, + (unsigned __int64) size); +#else + TIFFErrorExt(tif->tif_clientdata, module, +"Read error at row %lu, col %lu, tile %lu; got %llu bytes, expected %llu", + (unsigned long) tif->tif_row, + (unsigned long) tif->tif_col, + (unsigned long) tile, + (unsigned long long) n, + (unsigned long long) size); +#endif + return ((tmsize_t)(-1)); + } + _TIFFmemcpy(buf, tif->tif_base + ma, size); + } + return (size); +} + +/* + * Read a tile of data from the file. + */ +tmsize_t +TIFFReadRawTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size) +{ + static const char module[] = "TIFFReadRawTile"; + TIFFDirectory *td = &tif->tif_dir; + uint64 bytecount64; + tmsize_t bytecountm; + + if (!TIFFCheckRead(tif, 1)) + return ((tmsize_t)(-1)); + if (tile >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, + "%lu: Tile out of range, max %lu", + (unsigned long) tile, (unsigned long) td->td_nstrips); + return ((tmsize_t)(-1)); + } + if (tif->tif_flags&TIFF_NOREADRAW) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Compression scheme does not support access to raw uncompressed data"); + return ((tmsize_t)(-1)); + } + bytecount64 = td->td_stripbytecount[tile]; + if (size != (tmsize_t)(-1) && (uint64)size < bytecount64) + bytecount64 = (uint64)size; + bytecountm = (tmsize_t)bytecount64; + if ((uint64)bytecountm!=bytecount64) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + return ((tmsize_t)(-1)); + } + return (TIFFReadRawTile1(tif, tile, buf, bytecountm, module)); +} + +/* + * Read the specified tile and setup for decoding. The data buffer is + * expanded, as necessary, to hold the tile's data. + */ +int +TIFFFillTile(TIFF* tif, uint32 tile) +{ + static const char module[] = "TIFFFillTile"; + TIFFDirectory *td = &tif->tif_dir; + + if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) + return 0; + + if ((tif->tif_flags&TIFF_NOREADRAW)==0) + { + uint64 bytecount = td->td_stripbytecount[tile]; + if (bytecount <= 0) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "%I64u: Invalid tile byte count, tile %lu", + (unsigned __int64) bytecount, + (unsigned long) tile); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "%llu: Invalid tile byte count, tile %lu", + (unsigned long long) bytecount, + (unsigned long) tile); +#endif + return (0); + } + if (isMapped(tif) && + (isFillOrder(tif, td->td_fillorder) + || (tif->tif_flags & TIFF_NOBITREV))) { + /* + * The image is mapped into memory and we either don't + * need to flip bits or the compression routine is + * going to handle this operation itself. In this + * case, avoid copying the raw data and instead just + * reference the data from the memory mapped file + * image. This assumes that the decompression + * routines do not modify the contents of the raw data + * buffer (if they try to, the application will get a + * fault since the file is mapped read-only). + */ + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; + } + tif->tif_flags &= ~TIFF_MYBUFFER; + /* + * We must check for overflow, potentially causing + * an OOB read. Instead of simple + * + * td->td_stripoffset[tile]+bytecount > tif->tif_size + * + * comparison (which can overflow) we do the following + * two comparisons: + */ + if (bytecount > (uint64)tif->tif_size || + td->td_stripoffset[tile] > (uint64)tif->tif_size - bytecount) { + tif->tif_curtile = NOTILE; + return (0); + } + tif->tif_rawdatasize = (tmsize_t)bytecount; + tif->tif_rawdata = + tif->tif_base + (tmsize_t)td->td_stripoffset[tile]; + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = (tmsize_t) bytecount; + tif->tif_flags |= TIFF_BUFFERMMAP; + } else { + /* + * Expand raw data buffer, if needed, to hold data + * tile coming from file (perhaps should set upper + * bound on the size of a buffer we'll use?). + */ + tmsize_t bytecountm; + bytecountm=(tmsize_t)bytecount; + if ((uint64)bytecountm!=bytecount) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + return(0); + } + if (bytecountm > tif->tif_rawdatasize) { + tif->tif_curtile = NOTILE; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Data buffer too small to hold tile %lu", + (unsigned long) tile); + return (0); + } + if (!TIFFReadBufferSetup(tif, 0, bytecountm)) + return (0); + } + if (tif->tif_flags&TIFF_BUFFERMMAP) { + tif->tif_curtile = NOTILE; + if (!TIFFReadBufferSetup(tif, 0, bytecountm)) + return (0); + } + + if (TIFFReadRawTile1(tif, tile, tif->tif_rawdata, + bytecountm, module) != bytecountm) + return (0); + + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = bytecountm; + + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, + tif->tif_rawdataloaded); + } + } + return (TIFFStartTile(tif, tile)); +} + +/* + * Setup the raw data buffer in preparation for + * reading a strip of raw data. If the buffer + * is specified as zero, then a buffer of appropriate + * size is allocated by the library. Otherwise, + * the client must guarantee that the buffer is + * large enough to hold any individual strip of + * raw data. + */ +int +TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size) +{ + static const char module[] = "TIFFReadBufferSetup"; + + assert((tif->tif_flags&TIFF_NOREADRAW)==0); + tif->tif_flags &= ~TIFF_BUFFERMMAP; + + if (tif->tif_rawdata) { + if (tif->tif_flags & TIFF_MYBUFFER) + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; + } + if (bp) { + tif->tif_rawdatasize = size; + tif->tif_rawdata = (uint8*) bp; + tif->tif_flags &= ~TIFF_MYBUFFER; + } else { + tif->tif_rawdatasize = (tmsize_t)TIFFroundup_64((uint64)size, 1024); + if (tif->tif_rawdatasize==0) + tif->tif_rawdatasize=(tmsize_t)(-1); + tif->tif_rawdata = (uint8*) _TIFFmalloc(tif->tif_rawdatasize); + tif->tif_flags |= TIFF_MYBUFFER; + } + if (tif->tif_rawdata == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for data buffer at scanline %lu", + (unsigned long) tif->tif_row); + tif->tif_rawdatasize = 0; + return (0); + } + return (1); +} + +/* + * Set state to appear as if a + * strip has just been read in. + */ +static int +TIFFStartStrip(TIFF* tif, uint32 strip) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) + return 0; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupdecode)(tif)) + return (0); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_curstrip = strip; + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + tif->tif_flags &= ~TIFF_BUF4WRITE; + + if (tif->tif_flags&TIFF_NOREADRAW) + { + tif->tif_rawcp = NULL; + tif->tif_rawcc = 0; + } + else + { + tif->tif_rawcp = tif->tif_rawdata; + tif->tif_rawcc = (tmsize_t)td->td_stripbytecount[strip]; + } + return ((*tif->tif_predecode)(tif, + (uint16)(strip / td->td_stripsperimage))); +} + +/* + * Set state to appear as if a + * tile has just been read in. + */ +static int +TIFFStartTile(TIFF* tif, uint32 tile) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) + return 0; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupdecode)(tif)) + return (0); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_curtile = tile; + tif->tif_row = + (tile % TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth)) * + td->td_tilelength; + tif->tif_col = + (tile % TIFFhowmany_32(td->td_imagelength, td->td_tilelength)) * + td->td_tilewidth; + tif->tif_flags &= ~TIFF_BUF4WRITE; + if (tif->tif_flags&TIFF_NOREADRAW) + { + tif->tif_rawcp = NULL; + tif->tif_rawcc = 0; + } + else + { + tif->tif_rawcp = tif->tif_rawdata; + tif->tif_rawcc = (tmsize_t)td->td_stripbytecount[tile]; + } + return ((*tif->tif_predecode)(tif, + (uint16)(tile/td->td_stripsperimage))); +} + +static int +TIFFCheckRead(TIFF* tif, int tiles) +{ + if (tif->tif_mode == O_WRONLY) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "File not open for reading"); + return (0); + } + if (tiles ^ isTiled(tif)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, tiles ? + "Can not read tiles from a stripped image" : + "Can not read scanlines from a tiled image"); + return (0); + } + return (1); +} + +void +_TIFFNoPostDecode(TIFF* tif, uint8* buf, tmsize_t cc) +{ + (void) tif; (void) buf; (void) cc; +} + +void +_TIFFSwab16BitData(TIFF* tif, uint8* buf, tmsize_t cc) +{ + (void) tif; + assert((cc & 1) == 0); + TIFFSwabArrayOfShort((uint16*) buf, cc/2); +} + +void +_TIFFSwab24BitData(TIFF* tif, uint8* buf, tmsize_t cc) +{ + (void) tif; + assert((cc % 3) == 0); + TIFFSwabArrayOfTriples((uint8*) buf, cc/3); +} + +void +_TIFFSwab32BitData(TIFF* tif, uint8* buf, tmsize_t cc) +{ + (void) tif; + assert((cc & 3) == 0); + TIFFSwabArrayOfLong((uint32*) buf, cc/4); +} + +void +_TIFFSwab64BitData(TIFF* tif, uint8* buf, tmsize_t cc) +{ + (void) tif; + assert((cc & 7) == 0); + TIFFSwabArrayOfDouble((double*) buf, cc/8); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_strip.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_strip.c new file mode 100644 index 0000000000..047c59814c --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_strip.c @@ -0,0 +1,386 @@ +/* $Id: tif_strip.c,v 1.35 2012-06-06 05:33:55 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Strip-organized Image Support Routines. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +/* + * Compute which strip a (row,sample) value is in. + */ +uint32 +TIFFComputeStrip(TIFF* tif, uint32 row, uint16 sample) +{ + static const char module[] = "TIFFComputeStrip"; + TIFFDirectory *td = &tif->tif_dir; + uint32 strip; + + strip = row / td->td_rowsperstrip; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, module, + "%lu: Sample out of range, max %lu", + (unsigned long) sample, (unsigned long) td->td_samplesperpixel); + return (0); + } + strip += (uint32)sample*td->td_stripsperimage; + } + return (strip); +} + +/* + * Compute how many strips are in an image. + */ +uint32 +TIFFNumberOfStrips(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32 nstrips; + + nstrips = (td->td_rowsperstrip == (uint32) -1 ? 1 : + TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip)); + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + nstrips = _TIFFMultiply32(tif, nstrips, (uint32)td->td_samplesperpixel, + "TIFFNumberOfStrips"); + return (nstrips); +} + +/* + * Compute the # bytes in a variable height, row-aligned strip. + */ +uint64 +TIFFVStripSize64(TIFF* tif, uint32 nrows) +{ + static const char module[] = "TIFFVStripSize64"; + TIFFDirectory *td = &tif->tif_dir; + if (nrows==(uint32)(-1)) + nrows=td->td_imagelength; + if ((td->td_planarconfig==PLANARCONFIG_CONTIG)&& + (td->td_photometric == PHOTOMETRIC_YCBCR)&& + (!isUpSampled(tif))) + { + /* + * Packed YCbCr data contain one Cb+Cr for every + * HorizontalSampling*VerticalSampling Y values. + * Must also roundup width and height when calculating + * since images that are not a multiple of the + * horizontal/vertical subsampling area include + * YCbCr data for the extended image. + */ + uint16 ycbcrsubsampling[2]; + uint16 samplingblock_samples; + uint32 samplingblocks_hor; + uint32 samplingblocks_ver; + uint64 samplingrow_samples; + uint64 samplingrow_size; + if(td->td_samplesperpixel!=3) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Invalid td_samplesperpixel value"); + return 0; + } + TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,ycbcrsubsampling+0, + ycbcrsubsampling+1); + if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && ycbcrsubsampling[0] != 4) + ||(ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && ycbcrsubsampling[1] != 4)) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Invalid YCbCr subsampling (%dx%d)", + ycbcrsubsampling[0], + ycbcrsubsampling[1] ); + return 0; + } + samplingblock_samples=ycbcrsubsampling[0]*ycbcrsubsampling[1]+2; + samplingblocks_hor=TIFFhowmany_32(td->td_imagewidth,ycbcrsubsampling[0]); + samplingblocks_ver=TIFFhowmany_32(nrows,ycbcrsubsampling[1]); + samplingrow_samples=_TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module); + samplingrow_size=TIFFhowmany8_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module)); + return(_TIFFMultiply64(tif,samplingrow_size,samplingblocks_ver,module)); + } + else + return(_TIFFMultiply64(tif,nrows,TIFFScanlineSize64(tif),module)); +} +tmsize_t +TIFFVStripSize(TIFF* tif, uint32 nrows) +{ + static const char module[] = "TIFFVStripSize"; + uint64 m; + tmsize_t n; + m=TIFFVStripSize64(tif,nrows); + n=(tmsize_t)m; + if ((uint64)n!=m) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + n=0; + } + return(n); +} + +/* + * Compute the # bytes in a raw strip. + */ +uint64 +TIFFRawStripSize64(TIFF* tif, uint32 strip) +{ + static const char module[] = "TIFFRawStripSize64"; + TIFFDirectory* td = &tif->tif_dir; + uint64 bytecount = td->td_stripbytecount[strip]; + + if (bytecount == 0) + { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "%I64u: Invalid strip byte count, strip %lu", + (unsigned __int64) bytecount, + (unsigned long) strip); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "%llu: Invalid strip byte count, strip %lu", + (unsigned long long) bytecount, + (unsigned long) strip); +#endif + bytecount = (uint64) -1; + } + + return bytecount; +} +tmsize_t +TIFFRawStripSize(TIFF* tif, uint32 strip) +{ + static const char module[] = "TIFFRawStripSize"; + uint64 m; + tmsize_t n; + m=TIFFRawStripSize64(tif,strip); + if (m==(uint64)(-1)) + n=(tmsize_t)(-1); + else + { + n=(tmsize_t)m; + if ((uint64)n!=m) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + n=0; + } + } + return(n); +} + +/* + * Compute the # bytes in a (row-aligned) strip. + * + * Note that if RowsPerStrip is larger than the + * recorded ImageLength, then the strip size is + * truncated to reflect the actual space required + * to hold the strip. + */ +uint64 +TIFFStripSize64(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + uint32 rps = td->td_rowsperstrip; + if (rps > td->td_imagelength) + rps = td->td_imagelength; + return (TIFFVStripSize64(tif, rps)); +} +tmsize_t +TIFFStripSize(TIFF* tif) +{ + static const char module[] = "TIFFStripSize"; + uint64 m; + tmsize_t n; + m=TIFFStripSize64(tif); + n=(tmsize_t)m; + if ((uint64)n!=m) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + n=0; + } + return(n); +} + +/* + * Compute a default strip size based on the image + * characteristics and a requested value. If the + * request is <1 then we choose a strip size according + * to certain heuristics. + */ +uint32 +TIFFDefaultStripSize(TIFF* tif, uint32 request) +{ + return (*tif->tif_defstripsize)(tif, request); +} + +uint32 +_TIFFDefaultStripSize(TIFF* tif, uint32 s) +{ + if ((int32) s < 1) { + /* + * If RowsPerStrip is unspecified, try to break the + * image up into strips that are approximately + * STRIP_SIZE_DEFAULT bytes long. + */ + uint64 scanlinesize; + uint64 rows; + scanlinesize=TIFFScanlineSize64(tif); + if (scanlinesize==0) + scanlinesize=1; + rows=(uint64)STRIP_SIZE_DEFAULT/scanlinesize; + if (rows==0) + rows=1; + else if (rows>0xFFFFFFFF) + rows=0xFFFFFFFF; + s=(uint32)rows; + } + return (s); +} + +/* + * Return the number of bytes to read/write in a call to + * one of the scanline-oriented i/o routines. Note that + * this number may be 1/samples-per-pixel if data is + * stored as separate planes. + * The ScanlineSize in case of YCbCrSubsampling is defined as the + * strip size divided by the strip height, i.e. the size of a pack of vertical + * subsampling lines divided by vertical subsampling. It should thus make + * sense when multiplied by a multiple of vertical subsampling. + */ +uint64 +TIFFScanlineSize64(TIFF* tif) +{ + static const char module[] = "TIFFScanlineSize64"; + TIFFDirectory *td = &tif->tif_dir; + uint64 scanline_size; + if (td->td_planarconfig==PLANARCONFIG_CONTIG) + { + if ((td->td_photometric==PHOTOMETRIC_YCBCR)&& + (td->td_samplesperpixel==3)&& + (!isUpSampled(tif))) + { + uint16 ycbcrsubsampling[2]; + uint16 samplingblock_samples; + uint32 samplingblocks_hor; + uint64 samplingrow_samples; + uint64 samplingrow_size; + if(td->td_samplesperpixel!=3) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Invalid td_samplesperpixel value"); + return 0; + } + TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING, + ycbcrsubsampling+0, + ycbcrsubsampling+1); + if (((ycbcrsubsampling[0]!=1)&&(ycbcrsubsampling[0]!=2)&&(ycbcrsubsampling[0]!=4)) || + ((ycbcrsubsampling[1]!=1)&&(ycbcrsubsampling[1]!=2)&&(ycbcrsubsampling[1]!=4))) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Invalid YCbCr subsampling"); + return 0; + } + samplingblock_samples = ycbcrsubsampling[0]*ycbcrsubsampling[1]+2; + samplingblocks_hor = TIFFhowmany_32(td->td_imagewidth,ycbcrsubsampling[0]); + samplingrow_samples = _TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module); + samplingrow_size = TIFFhowmany_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module),8); + scanline_size = (samplingrow_size/ycbcrsubsampling[1]); + } + else + { + uint64 scanline_samples; + scanline_samples=_TIFFMultiply64(tif,td->td_imagewidth,td->td_samplesperpixel,module); + scanline_size=TIFFhowmany_64(_TIFFMultiply64(tif,scanline_samples,td->td_bitspersample,module),8); + } + } + else + scanline_size=TIFFhowmany_64(_TIFFMultiply64(tif,td->td_imagewidth,td->td_bitspersample,module),8); + return(scanline_size); +} +tmsize_t +TIFFScanlineSize(TIFF* tif) +{ + static const char module[] = "TIFFScanlineSize"; + uint64 m; + tmsize_t n; + m=TIFFScanlineSize64(tif); + n=(tmsize_t)m; + if ((uint64)n!=m) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer arithmetic overflow"); + n=0; + } + return(n); +} + +/* + * Return the number of bytes required to store a complete + * decoded and packed raster scanline (as opposed to the + * I/O size returned by TIFFScanlineSize which may be less + * if data is store as separate planes). + */ +uint64 +TIFFRasterScanlineSize64(TIFF* tif) +{ + static const char module[] = "TIFFRasterScanlineSize64"; + TIFFDirectory *td = &tif->tif_dir; + uint64 scanline; + + scanline = _TIFFMultiply64(tif, td->td_bitspersample, td->td_imagewidth, module); + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + scanline = _TIFFMultiply64(tif, scanline, td->td_samplesperpixel, module); + return (TIFFhowmany8_64(scanline)); + } else + return (_TIFFMultiply64(tif, TIFFhowmany8_64(scanline), + td->td_samplesperpixel, module)); +} +tmsize_t +TIFFRasterScanlineSize(TIFF* tif) +{ + static const char module[] = "TIFFRasterScanlineSize"; + uint64 m; + tmsize_t n; + m=TIFFRasterScanlineSize64(tif); + n=(tmsize_t)m; + if ((uint64)n!=m) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer arithmetic overflow"); + n=0; + } + return(n); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_swab.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_swab.c new file mode 100644 index 0000000000..a60814bee2 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_swab.c @@ -0,0 +1,313 @@ +/* $Id: tif_swab.c,v 1.13 2010-03-10 18:56:49 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library Bit & Byte Swapping Support. + * + * XXX We assume short = 16-bits and long = 32-bits XXX + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +#ifndef TIFFSwabShort +void +TIFFSwabShort(uint16* wp) +{ + register unsigned char* cp = (unsigned char*) wp; + unsigned char t; + assert(sizeof(uint16)==2); + t = cp[1]; cp[1] = cp[0]; cp[0] = t; +} +#endif + +#ifndef TIFFSwabLong +void +TIFFSwabLong(uint32* lp) +{ + register unsigned char* cp = (unsigned char*) lp; + unsigned char t; + assert(sizeof(uint32)==4); + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; +} +#endif + +#ifndef TIFFSwabLong8 +void +TIFFSwabLong8(uint64* lp) +{ + register unsigned char* cp = (unsigned char*) lp; + unsigned char t; + assert(sizeof(uint64)==8); + t = cp[7]; cp[7] = cp[0]; cp[0] = t; + t = cp[6]; cp[6] = cp[1]; cp[1] = t; + t = cp[5]; cp[5] = cp[2]; cp[2] = t; + t = cp[4]; cp[4] = cp[3]; cp[3] = t; +} +#endif + +#ifndef TIFFSwabArrayOfShort +void +TIFFSwabArrayOfShort(register uint16* wp, tmsize_t n) +{ + register unsigned char* cp; + register unsigned char t; + assert(sizeof(uint16)==2); + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char*) wp; + t = cp[1]; cp[1] = cp[0]; cp[0] = t; + wp++; + } +} +#endif + +#ifndef TIFFSwabArrayOfTriples +void +TIFFSwabArrayOfTriples(register uint8* tp, tmsize_t n) +{ + unsigned char* cp; + unsigned char t; + + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char*) tp; + t = cp[2]; cp[2] = cp[0]; cp[0] = t; + tp += 3; + } +} +#endif + +#ifndef TIFFSwabArrayOfLong +void +TIFFSwabArrayOfLong(register uint32* lp, tmsize_t n) +{ + register unsigned char *cp; + register unsigned char t; + assert(sizeof(uint32)==4); + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char *)lp; + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; + lp++; + } +} +#endif + +#ifndef TIFFSwabArrayOfLong8 +void +TIFFSwabArrayOfLong8(register uint64* lp, tmsize_t n) +{ + register unsigned char *cp; + register unsigned char t; + assert(sizeof(uint64)==8); + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char *)lp; + t = cp[7]; cp[7] = cp[0]; cp[0] = t; + t = cp[6]; cp[6] = cp[1]; cp[1] = t; + t = cp[5]; cp[5] = cp[2]; cp[2] = t; + t = cp[4]; cp[4] = cp[3]; cp[3] = t; + lp++; + } +} +#endif + +#ifndef TIFFSwabFloat +void +TIFFSwabFloat(float* fp) +{ + register unsigned char* cp = (unsigned char*) fp; + unsigned char t; + assert(sizeof(float)==4); + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; +} +#endif + +#ifndef TIFFSwabArrayOfFloat +void +TIFFSwabArrayOfFloat(register float* fp, tmsize_t n) +{ + register unsigned char *cp; + register unsigned char t; + assert(sizeof(float)==4); + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char *)fp; + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; + fp++; + } +} +#endif + +#ifndef TIFFSwabDouble +void +TIFFSwabDouble(double *dp) +{ + register unsigned char* cp = (unsigned char*) dp; + unsigned char t; + assert(sizeof(double)==8); + t = cp[7]; cp[7] = cp[0]; cp[0] = t; + t = cp[6]; cp[6] = cp[1]; cp[1] = t; + t = cp[5]; cp[5] = cp[2]; cp[2] = t; + t = cp[4]; cp[4] = cp[3]; cp[3] = t; +} +#endif + +#ifndef TIFFSwabArrayOfDouble +void +TIFFSwabArrayOfDouble(double* dp, tmsize_t n) +{ + register unsigned char *cp; + register unsigned char t; + assert(sizeof(double)==8); + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char *)dp; + t = cp[7]; cp[7] = cp[0]; cp[0] = t; + t = cp[6]; cp[6] = cp[1]; cp[1] = t; + t = cp[5]; cp[5] = cp[2]; cp[2] = t; + t = cp[4]; cp[4] = cp[3]; cp[3] = t; + dp++; + } +} +#endif + +/* + * Bit reversal tables. TIFFBitRevTable[] gives + * the bit reversed value of . Used in various + * places in the library when the FillOrder requires + * bit reversal of byte values (e.g. CCITT Fax 3 + * encoding/decoding). TIFFNoBitRevTable is provided + * for algorithms that want an equivalent table that + * do not reverse bit values. + */ +static const unsigned char TIFFBitRevTable[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; +static const unsigned char TIFFNoBitRevTable[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}; + +const unsigned char* +TIFFGetBitRevTable(int reversed) +{ + return (reversed ? TIFFBitRevTable : TIFFNoBitRevTable); +} + +void +TIFFReverseBits(uint8* cp, tmsize_t n) +{ + for (; n > 8; n -= 8) { + cp[0] = TIFFBitRevTable[cp[0]]; + cp[1] = TIFFBitRevTable[cp[1]]; + cp[2] = TIFFBitRevTable[cp[2]]; + cp[3] = TIFFBitRevTable[cp[3]]; + cp[4] = TIFFBitRevTable[cp[4]]; + cp[5] = TIFFBitRevTable[cp[5]]; + cp[6] = TIFFBitRevTable[cp[6]]; + cp[7] = TIFFBitRevTable[cp[7]]; + cp += 8; + } + while (n-- > 0) + *cp = TIFFBitRevTable[*cp], cp++; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_thunder.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_thunder.c new file mode 100644 index 0000000000..e7cb0d4df5 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_thunder.c @@ -0,0 +1,210 @@ +/* $Id: tif_thunder.c,v 1.12 2011-04-02 20:54:09 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#include +#ifdef THUNDER_SUPPORT +/* + * TIFF Library. + * + * ThunderScan 4-bit Compression Algorithm Support + */ + +/* + * ThunderScan uses an encoding scheme designed for + * 4-bit pixel values. Data is encoded in bytes, with + * each byte split into a 2-bit code word and a 6-bit + * data value. The encoding gives raw data, runs of + * pixels, or pixel values encoded as a delta from the + * previous pixel value. For the latter, either 2-bit + * or 3-bit delta values are used, with the deltas packed + * into a single byte. + */ +#define THUNDER_DATA 0x3f /* mask for 6-bit data */ +#define THUNDER_CODE 0xc0 /* mask for 2-bit code word */ +/* code values */ +#define THUNDER_RUN 0x00 /* run of pixels w/ encoded count */ +#define THUNDER_2BITDELTAS 0x40 /* 3 pixels w/ encoded 2-bit deltas */ +#define DELTA2_SKIP 2 /* skip code for 2-bit deltas */ +#define THUNDER_3BITDELTAS 0x80 /* 2 pixels w/ encoded 3-bit deltas */ +#define DELTA3_SKIP 4 /* skip code for 3-bit deltas */ +#define THUNDER_RAW 0xc0 /* raw data encoded */ + +static const int twobitdeltas[4] = { 0, 1, 0, -1 }; +static const int threebitdeltas[8] = { 0, 1, 2, 3, 0, -3, -2, -1 }; + +#define SETPIXEL(op, v) { \ + lastpixel = (v) & 0xf; \ + if ( npixels < maxpixels ) \ + { \ + if (npixels++ & 1) \ + *op++ |= lastpixel; \ + else \ + op[0] = (uint8) (lastpixel << 4); \ + } \ +} + +static int +ThunderSetupDecode(TIFF* tif) +{ + static const char module[] = "ThunderSetupDecode"; + + if( tif->tif_dir.td_bitspersample != 4 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Wrong bitspersample value (%d), Thunder decoder only supports 4bits per sample.", + (int) tif->tif_dir.td_bitspersample ); + return 0; + } + + + return (1); +} + +static int +ThunderDecode(TIFF* tif, uint8* op, tmsize_t maxpixels) +{ + static const char module[] = "ThunderDecode"; + register unsigned char *bp; + register tmsize_t cc; + unsigned int lastpixel; + tmsize_t npixels; + + bp = (unsigned char *)tif->tif_rawcp; + cc = tif->tif_rawcc; + lastpixel = 0; + npixels = 0; + while (cc > 0 && npixels < maxpixels) { + int n, delta; + + n = *bp++, cc--; + switch (n & THUNDER_CODE) { + case THUNDER_RUN: /* pixel run */ + /* + * Replicate the last pixel n times, + * where n is the lower-order 6 bits. + */ + if (npixels & 1) { + op[0] |= lastpixel; + lastpixel = *op++; npixels++; n--; + } else + lastpixel |= lastpixel << 4; + npixels += n; + if (npixels < maxpixels) { + for (; n > 0; n -= 2) + *op++ = (uint8) lastpixel; + } + if (n == -1) + *--op &= 0xf0; + lastpixel &= 0xf; + break; + case THUNDER_2BITDELTAS: /* 2-bit deltas */ + if ((delta = ((n >> 4) & 3)) != DELTA2_SKIP) + SETPIXEL(op, lastpixel + twobitdeltas[delta]); + if ((delta = ((n >> 2) & 3)) != DELTA2_SKIP) + SETPIXEL(op, lastpixel + twobitdeltas[delta]); + if ((delta = (n & 3)) != DELTA2_SKIP) + SETPIXEL(op, lastpixel + twobitdeltas[delta]); + break; + case THUNDER_3BITDELTAS: /* 3-bit deltas */ + if ((delta = ((n >> 3) & 7)) != DELTA3_SKIP) + SETPIXEL(op, lastpixel + threebitdeltas[delta]); + if ((delta = (n & 7)) != DELTA3_SKIP) + SETPIXEL(op, lastpixel + threebitdeltas[delta]); + break; + case THUNDER_RAW: /* raw data */ + SETPIXEL(op, n); + break; + } + } + tif->tif_rawcp = (uint8*) bp; + tif->tif_rawcc = cc; + if (npixels != maxpixels) { +#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "%s data at scanline %lu (%I64u != %I64u)", + npixels < maxpixels ? "Not enough" : "Too much", + (unsigned long) tif->tif_row, + (unsigned __int64) npixels, + (unsigned __int64) maxpixels); +#else + TIFFErrorExt(tif->tif_clientdata, module, + "%s data at scanline %lu (%llu != %llu)", + npixels < maxpixels ? "Not enough" : "Too much", + (unsigned long) tif->tif_row, + (unsigned long long) npixels, + (unsigned long long) maxpixels); +#endif + return (0); + } + + return (1); +} + +static int +ThunderDecodeRow(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s) +{ + static const char module[] = "ThunderDecodeRow"; + uint8* row = buf; + + (void) s; + if (occ % tif->tif_scanlinesize) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (0); + } + while (occ > 0) { + if (!ThunderDecode(tif, row, tif->tif_dir.td_imagewidth)) + return (0); + occ -= tif->tif_scanlinesize; + row += tif->tif_scanlinesize; + } + return (1); +} + +int +TIFFInitThunderScan(TIFF* tif, int scheme) +{ + (void) scheme; + + tif->tif_setupdecode = ThunderSetupDecode; + tif->tif_decoderow = ThunderDecodeRow; + tif->tif_decodestrip = ThunderDecodeRow; + return (1); +} +#endif /* THUNDER_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ + +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_tile.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_tile.c new file mode 100644 index 0000000000..24ba82c040 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_tile.c @@ -0,0 +1,302 @@ +/* $Id: tif_tile.c,v 1.23 2012-06-06 05:33:55 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Tiled Image Support Routines. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +/* + * Compute which tile an (x,y,z,s) value is in. + */ +uint32 +TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32 dx = td->td_tilewidth; + uint32 dy = td->td_tilelength; + uint32 dz = td->td_tiledepth; + uint32 tile = 1; + + if (td->td_imagedepth == 1) + z = 0; + if (dx == (uint32) -1) + dx = td->td_imagewidth; + if (dy == (uint32) -1) + dy = td->td_imagelength; + if (dz == (uint32) -1) + dz = td->td_imagedepth; + if (dx != 0 && dy != 0 && dz != 0) { + uint32 xpt = TIFFhowmany_32(td->td_imagewidth, dx); + uint32 ypt = TIFFhowmany_32(td->td_imagelength, dy); + uint32 zpt = TIFFhowmany_32(td->td_imagedepth, dz); + + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + tile = (xpt*ypt*zpt)*s + + (xpt*ypt)*(z/dz) + + xpt*(y/dy) + + x/dx; + else + tile = (xpt*ypt)*(z/dz) + xpt*(y/dy) + x/dx; + } + return (tile); +} + +/* + * Check an (x,y,z,s) coordinate + * against the image bounds. + */ +int +TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (x >= td->td_imagewidth) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Col out of range, max %lu", + (unsigned long) x, + (unsigned long) (td->td_imagewidth - 1)); + return (0); + } + if (y >= td->td_imagelength) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Row out of range, max %lu", + (unsigned long) y, + (unsigned long) (td->td_imagelength - 1)); + return (0); + } + if (z >= td->td_imagedepth) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Depth out of range, max %lu", + (unsigned long) z, + (unsigned long) (td->td_imagedepth - 1)); + return (0); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && + s >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Sample out of range, max %lu", + (unsigned long) s, + (unsigned long) (td->td_samplesperpixel - 1)); + return (0); + } + return (1); +} + +/* + * Compute how many tiles are in an image. + */ +uint32 +TIFFNumberOfTiles(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32 dx = td->td_tilewidth; + uint32 dy = td->td_tilelength; + uint32 dz = td->td_tiledepth; + uint32 ntiles; + + if (dx == (uint32) -1) + dx = td->td_imagewidth; + if (dy == (uint32) -1) + dy = td->td_imagelength; + if (dz == (uint32) -1) + dz = td->td_imagedepth; + ntiles = (dx == 0 || dy == 0 || dz == 0) ? 0 : + _TIFFMultiply32(tif, _TIFFMultiply32(tif, TIFFhowmany_32(td->td_imagewidth, dx), + TIFFhowmany_32(td->td_imagelength, dy), + "TIFFNumberOfTiles"), + TIFFhowmany_32(td->td_imagedepth, dz), "TIFFNumberOfTiles"); + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + ntiles = _TIFFMultiply32(tif, ntiles, td->td_samplesperpixel, + "TIFFNumberOfTiles"); + return (ntiles); +} + +/* + * Compute the # bytes in each row of a tile. + */ +uint64 +TIFFTileRowSize64(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + uint64 rowsize; + + if (td->td_tilelength == 0 || td->td_tilewidth == 0) + return (0); + rowsize = _TIFFMultiply64(tif, td->td_bitspersample, td->td_tilewidth, + "TIFFTileRowSize"); + if (td->td_planarconfig == PLANARCONFIG_CONTIG) + rowsize = _TIFFMultiply64(tif, rowsize, td->td_samplesperpixel, + "TIFFTileRowSize"); + return (TIFFhowmany8_64(rowsize)); +} +tmsize_t +TIFFTileRowSize(TIFF* tif) +{ + static const char module[] = "TIFFTileRowSize"; + uint64 m; + tmsize_t n; + m=TIFFTileRowSize64(tif); + n=(tmsize_t)m; + if ((uint64)n!=m) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + n=0; + } + return(n); +} + +/* + * Compute the # bytes in a variable length, row-aligned tile. + */ +uint64 +TIFFVTileSize64(TIFF* tif, uint32 nrows) +{ + static const char module[] = "TIFFVTileSize64"; + TIFFDirectory *td = &tif->tif_dir; + if (td->td_tilelength == 0 || td->td_tilewidth == 0 || + td->td_tiledepth == 0) + return (0); + if ((td->td_planarconfig==PLANARCONFIG_CONTIG)&& + (td->td_photometric==PHOTOMETRIC_YCBCR)&& + (td->td_samplesperpixel==3)&& + (!isUpSampled(tif))) + { + /* + * Packed YCbCr data contain one Cb+Cr for every + * HorizontalSampling*VerticalSampling Y values. + * Must also roundup width and height when calculating + * since images that are not a multiple of the + * horizontal/vertical subsampling area include + * YCbCr data for the extended image. + */ + uint16 ycbcrsubsampling[2]; + uint16 samplingblock_samples; + uint32 samplingblocks_hor; + uint32 samplingblocks_ver; + uint64 samplingrow_samples; + uint64 samplingrow_size; + TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,ycbcrsubsampling+0, + ycbcrsubsampling+1); + if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && ycbcrsubsampling[0] != 4) + ||(ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && ycbcrsubsampling[1] != 4)) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Invalid YCbCr subsampling (%dx%d)", + ycbcrsubsampling[0], + ycbcrsubsampling[1] ); + return 0; + } + samplingblock_samples=ycbcrsubsampling[0]*ycbcrsubsampling[1]+2; + samplingblocks_hor=TIFFhowmany_32(td->td_tilewidth,ycbcrsubsampling[0]); + samplingblocks_ver=TIFFhowmany_32(nrows,ycbcrsubsampling[1]); + samplingrow_samples=_TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module); + samplingrow_size=TIFFhowmany8_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module)); + return(_TIFFMultiply64(tif,samplingrow_size,samplingblocks_ver,module)); + } + else + return(_TIFFMultiply64(tif,nrows,TIFFTileRowSize64(tif),module)); +} +tmsize_t +TIFFVTileSize(TIFF* tif, uint32 nrows) +{ + static const char module[] = "TIFFVTileSize"; + uint64 m; + tmsize_t n; + m=TIFFVTileSize64(tif,nrows); + n=(tmsize_t)m; + if ((uint64)n!=m) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + n=0; + } + return(n); +} + +/* + * Compute the # bytes in a row-aligned tile. + */ +uint64 +TIFFTileSize64(TIFF* tif) +{ + return (TIFFVTileSize64(tif, tif->tif_dir.td_tilelength)); +} +tmsize_t +TIFFTileSize(TIFF* tif) +{ + static const char module[] = "TIFFTileSize"; + uint64 m; + tmsize_t n; + m=TIFFTileSize64(tif); + n=(tmsize_t)m; + if ((uint64)n!=m) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + n=0; + } + return(n); +} + +/* + * Compute a default tile size based on the image + * characteristics and a requested value. If a + * request is <1 then we choose a size according + * to certain heuristics. + */ +void +TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +{ + (*tif->tif_deftilesize)(tif, tw, th); +} + +void +_TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +{ + (void) tif; + if (*(int32*) tw < 1) + *tw = 256; + if (*(int32*) th < 1) + *th = 256; + /* roundup to a multiple of 16 per the spec */ + if (*tw & 0xf) + *tw = TIFFroundup_32(*tw, 16); + if (*th & 0xf) + *th = TIFFroundup_32(*th, 16); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_version.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_version.c new file mode 100644 index 0000000000..41aa8b0dcd --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_version.c @@ -0,0 +1,43 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_version.c,v 1.3 2010-03-10 18:56:49 bfriesen Exp $ */ +/* + * Copyright (c) 1992-1997 Sam Leffler + * Copyright (c) 1992-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +static const char TIFFVersion[] = TIFFLIB_VERSION_STR; + +const char* +TIFFGetVersion(void) +{ + return (TIFFVersion); +} +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_warning.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_warning.c new file mode 100644 index 0000000000..ac6b3b938f --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_warning.c @@ -0,0 +1,87 @@ +/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_warning.c,v 1.3 2010-03-10 18:56:49 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" + +/*TIFFErrorHandlerExt _TIFFwarningHandlerExt = NULL;*/ +/* Modify here for use _TIFFwarningHandlerExt by Sunliang.Liu 20090715 */ +TIFFErrorHandler _TIFFwarningHandler = NULL; + +TIFFErrorHandler +TIFFSetWarningHandler(TIFFErrorHandler handler) +{ + TIFFErrorHandler prev = _TIFFwarningHandler; + _TIFFwarningHandler = handler; + return (prev); +} + +TIFFErrorHandlerExt +TIFFSetWarningHandlerExt(TIFFErrorHandlerExt handler) +{ + TIFFErrorHandlerExt prev = _TIFFwarningHandlerExt; + _TIFFwarningHandlerExt = handler; + return (prev); +} + +void +TIFFWarning(const char* module, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (_TIFFwarningHandler) + (*_TIFFwarningHandler)(module, fmt, ap); + if (_TIFFwarningHandlerExt) + (*_TIFFwarningHandlerExt)(0, module, fmt, ap); + va_end(ap); +} + +void +TIFFWarningExt(thandle_t fd, const char* module, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (_TIFFwarningHandler) + (*_TIFFwarningHandler)(module, fmt, ap); + if (_TIFFwarningHandlerExt) + (*_TIFFwarningHandlerExt)(fd, module, fmt, ap); + va_end(ap); +} + + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_write.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_write.c new file mode 100644 index 0000000000..11a537c9d0 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_write.c @@ -0,0 +1,774 @@ +/* $Id: tif_write.c,v 1.37 2012-08-13 22:10:17 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Scanline-oriented Write Support + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#include + +#define STRIPINCR 20 /* expansion factor on strip array */ + +#define WRITECHECKSTRIPS(tif, module) \ + (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),0,module)) +#define WRITECHECKTILES(tif, module) \ + (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),1,module)) +#define BUFFERCHECK(tif) \ + ((((tif)->tif_flags & TIFF_BUFFERSETUP) && tif->tif_rawdata) || \ + TIFFWriteBufferSetup((tif), NULL, (tmsize_t) -1)) + +static int TIFFGrowStrips(TIFF* tif, uint32 delta, const char* module); +static int TIFFAppendToStrip(TIFF* tif, uint32 strip, uint8* data, tmsize_t cc); + +int +TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample) +{ + static const char module[] = "TIFFWriteScanline"; + register TIFFDirectory *td; + int status, imagegrew = 0; + uint32 strip; + + if (!WRITECHECKSTRIPS(tif, module)) + return (-1); + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized more intelligently (using + * directory information). + */ + if (!BUFFERCHECK(tif)) + return (-1); + tif->tif_flags |= TIFF_BUF4WRITE; /* not strictly sure this is right*/ + + td = &tif->tif_dir; + /* + * Extend image length if needed + * (but only for PlanarConfig=1). + */ + if (row >= td->td_imagelength) { /* extend image */ + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not change \"ImageLength\" when using separate planes"); + return (-1); + } + td->td_imagelength = row+1; + imagegrew = 1; + } + /* + * Calculate strip and check for crossings. + */ + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, module, + "%lu: Sample out of range, max %lu", + (unsigned long) sample, (unsigned long) td->td_samplesperpixel); + return (-1); + } + strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip; + } else + strip = row / td->td_rowsperstrip; + /* + * Check strip array to make sure there's space. We don't support + * dynamically growing files that have data organized in separate + * bitplanes because it's too painful. In that case we require that + * the imagelength be set properly before the first write (so that the + * strips array will be fully allocated above). + */ + if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module)) + return (-1); + if (strip != tif->tif_curstrip) { + /* + * Changing strips -- flush any data present. + */ + if (!TIFFFlushData(tif)) + return (-1); + tif->tif_curstrip = strip; + /* + * Watch out for a growing image. The value of strips/image + * will initially be 1 (since it can't be deduced until the + * imagelength is known). + */ + if (strip >= td->td_stripsperimage && imagegrew) + td->td_stripsperimage = + TIFFhowmany_32(td->td_imagelength,td->td_rowsperstrip); + tif->tif_row = + (strip % td->td_stripsperimage) * td->td_rowsperstrip; + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return (-1); + tif->tif_flags |= TIFF_CODERSETUP; + } + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + if( td->td_stripbytecount[strip] > 0 ) + { + /* if we are writing over existing tiles, zero length */ + td->td_stripbytecount[strip] = 0; + + /* this forces TIFFAppendToStrip() to do a seek */ + tif->tif_curoff = 0; + } + + if (!(*tif->tif_preencode)(tif, sample)) + return (-1); + tif->tif_flags |= TIFF_POSTENCODE; + } + /* + * Ensure the write is either sequential or at the + * beginning of a strip (or that we can randomly + * access the data -- i.e. no encoding). + */ + if (row != tif->tif_row) { + if (row < tif->tif_row) { + /* + * Moving backwards within the same strip: + * backup to the start and then decode + * forward (below). + */ + tif->tif_row = (strip % td->td_stripsperimage) * + td->td_rowsperstrip; + tif->tif_rawcp = tif->tif_rawdata; + } + /* + * Seek forward to the desired row. + */ + if (!(*tif->tif_seek)(tif, row - tif->tif_row)) + return (-1); + tif->tif_row = row; + } + + /* swab if needed - note that source buffer will be altered */ + tif->tif_postdecode( tif, (uint8*) buf, tif->tif_scanlinesize ); + + status = (*tif->tif_encoderow)(tif, (uint8*) buf, + tif->tif_scanlinesize, sample); + + /* we are now poised at the beginning of the next row */ + tif->tif_row = row + 1; + return (status); +} + +/* + * Encode the supplied data and write it to the + * specified strip. + * + * NB: Image length must be setup before writing. + */ +tmsize_t +TIFFWriteEncodedStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc) +{ + static const char module[] = "TIFFWriteEncodedStrip"; + TIFFDirectory *td = &tif->tif_dir; + uint16 sample; + + if (!WRITECHECKSTRIPS(tif, module)) + return ((tmsize_t) -1); + /* + * Check strip array to make sure there's space. + * We don't support dynamically growing files that + * have data organized in separate bitplanes because + * it's too painful. In that case we require that + * the imagelength be set properly before the first + * write (so that the strips array will be fully + * allocated above). + */ + if (strip >= td->td_nstrips) { + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not grow image by strips when using separate planes"); + return ((tmsize_t) -1); + } + if (!TIFFGrowStrips(tif, 1, module)) + return ((tmsize_t) -1); + td->td_stripsperimage = + TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip); + } + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized according to the directory + * info. + */ + if (!BUFFERCHECK(tif)) + return ((tmsize_t) -1); + + tif->tif_flags |= TIFF_BUF4WRITE; + tif->tif_curstrip = strip; + + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return ((tmsize_t) -1); + tif->tif_flags |= TIFF_CODERSETUP; + } + + if( td->td_stripbytecount[strip] > 0 ) + { + /* Make sure that at the first attempt of rewriting the tile, we will have */ + /* more bytes available in the output buffer than the previous byte count, */ + /* so that TIFFAppendToStrip() will detect the overflow when it is called the first */ + /* time if the new compressed tile is bigger than the older one. (GDAL #4771) */ + if( tif->tif_rawdatasize <= (tmsize_t)td->td_stripbytecount[strip] ) + { + if( !(TIFFWriteBufferSetup(tif, NULL, + (tmsize_t)TIFFroundup_64((uint64)(td->td_stripbytecount[strip] + 1), 1024))) ) + return ((tmsize_t)(-1)); + } + + /* Force TIFFAppendToStrip() to consider placing data at end + of file. */ + tif->tif_curoff = 0; + } + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + tif->tif_flags &= ~TIFF_POSTENCODE; + sample = (uint16)(strip / td->td_stripsperimage); + if (!(*tif->tif_preencode)(tif, sample)) + return ((tmsize_t) -1); + + /* swab if needed - note that source buffer will be altered */ + tif->tif_postdecode( tif, (uint8*) data, cc ); + + if (!(*tif->tif_encodestrip)(tif, (uint8*) data, cc, sample)) + return (0); + if (!(*tif->tif_postencode)(tif)) + return ((tmsize_t) -1); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, tif->tif_rawcc); + if (tif->tif_rawcc > 0 && + !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, tif->tif_rawcc)) + return ((tmsize_t) -1); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + return (cc); +} + +/* + * Write the supplied data to the specified strip. + * + * NB: Image length must be setup before writing. + */ +tmsize_t +TIFFWriteRawStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc) +{ + static const char module[] = "TIFFWriteRawStrip"; + TIFFDirectory *td = &tif->tif_dir; + + if (!WRITECHECKSTRIPS(tif, module)) + return ((tmsize_t) -1); + /* + * Check strip array to make sure there's space. + * We don't support dynamically growing files that + * have data organized in separate bitplanes because + * it's too painful. In that case we require that + * the imagelength be set properly before the first + * write (so that the strips array will be fully + * allocated above). + */ + if (strip >= td->td_nstrips) { + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not grow image by strips when using separate planes"); + return ((tmsize_t) -1); + } + /* + * Watch out for a growing image. The value of + * strips/image will initially be 1 (since it + * can't be deduced until the imagelength is known). + */ + if (strip >= td->td_stripsperimage) + td->td_stripsperimage = + TIFFhowmany_32(td->td_imagelength,td->td_rowsperstrip); + if (!TIFFGrowStrips(tif, 1, module)) + return ((tmsize_t) -1); + } + tif->tif_curstrip = strip; + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + return (TIFFAppendToStrip(tif, strip, (uint8*) data, cc) ? + cc : (tmsize_t) -1); +} + +/* + * Write and compress a tile of data. The + * tile is selected by the (x,y,z,s) coordinates. + */ +tmsize_t +TIFFWriteTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s) +{ + if (!TIFFCheckTile(tif, x, y, z, s)) + return ((tmsize_t)(-1)); + /* + * NB: A tile size of -1 is used instead of tif_tilesize knowing + * that TIFFWriteEncodedTile will clamp this to the tile size. + * This is done because the tile size may not be defined until + * after the output buffer is setup in TIFFWriteBufferSetup. + */ + return (TIFFWriteEncodedTile(tif, + TIFFComputeTile(tif, x, y, z, s), buf, (tmsize_t)(-1))); +} + +/* + * Encode the supplied data and write it to the + * specified tile. There must be space for the + * data. The function clamps individual writes + * to a tile to the tile size, but does not (and + * can not) check that multiple writes to the same + * tile do not write more than tile size data. + * + * NB: Image length must be setup before writing; this + * interface does not support automatically growing + * the image on each write (as TIFFWriteScanline does). + */ +tmsize_t +TIFFWriteEncodedTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc) +{ + static const char module[] = "TIFFWriteEncodedTile"; + TIFFDirectory *td; + uint16 sample; + + if (!WRITECHECKTILES(tif, module)) + return ((tmsize_t)(-1)); + td = &tif->tif_dir; + if (tile >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, "Tile %lu out of range, max %lu", + (unsigned long) tile, (unsigned long) td->td_nstrips); + return ((tmsize_t)(-1)); + } + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized more intelligently (using + * directory information). + */ + if (!BUFFERCHECK(tif)) + return ((tmsize_t)(-1)); + + tif->tif_flags |= TIFF_BUF4WRITE; + tif->tif_curtile = tile; + + if( td->td_stripbytecount[tile] > 0 ) + { + /* Make sure that at the first attempt of rewriting the tile, we will have */ + /* more bytes available in the output buffer than the previous byte count, */ + /* so that TIFFAppendToStrip() will detect the overflow when it is called the first */ + /* time if the new compressed tile is bigger than the older one. (GDAL #4771) */ + if( tif->tif_rawdatasize <= (tmsize_t)td->td_stripbytecount[tile] ) + { + if( !(TIFFWriteBufferSetup(tif, NULL, + (tmsize_t)TIFFroundup_64((uint64)(td->td_stripbytecount[tile] + 1), 1024))) ) + return ((tmsize_t)(-1)); + } + + /* Force TIFFAppendToStrip() to consider placing data at end + of file. */ + tif->tif_curoff = 0; + } + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + /* + * Compute tiles per row & per column to compute + * current row and column + */ + tif->tif_row = (tile % TIFFhowmany_32(td->td_imagelength, td->td_tilelength)) + * td->td_tilelength; + tif->tif_col = (tile % TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth)) + * td->td_tilewidth; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return ((tmsize_t)(-1)); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_flags &= ~TIFF_POSTENCODE; + sample = (uint16)(tile/td->td_stripsperimage); + if (!(*tif->tif_preencode)(tif, sample)) + return ((tmsize_t)(-1)); + /* + * Clamp write amount to the tile size. This is mostly + * done so that callers can pass in some large number + * (e.g. -1) and have the tile size used instead. + */ + if ( cc < 1 || cc > tif->tif_tilesize) + cc = tif->tif_tilesize; + + /* swab if needed - note that source buffer will be altered */ + tif->tif_postdecode( tif, (uint8*) data, cc ); + + if (!(*tif->tif_encodetile)(tif, (uint8*) data, cc, sample)) + return (0); + if (!(*tif->tif_postencode)(tif)) + return ((tmsize_t)(-1)); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits((uint8*)tif->tif_rawdata, tif->tif_rawcc); + if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, tile, + tif->tif_rawdata, tif->tif_rawcc)) + return ((tmsize_t)(-1)); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + return (cc); +} + +/* + * Write the supplied data to the specified strip. + * There must be space for the data; we don't check + * if strips overlap! + * + * NB: Image length must be setup before writing; this + * interface does not support automatically growing + * the image on each write (as TIFFWriteScanline does). + */ +tmsize_t +TIFFWriteRawTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc) +{ + static const char module[] = "TIFFWriteRawTile"; + + if (!WRITECHECKTILES(tif, module)) + return ((tmsize_t)(-1)); + if (tile >= tif->tif_dir.td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, "Tile %lu out of range, max %lu", + (unsigned long) tile, + (unsigned long) tif->tif_dir.td_nstrips); + return ((tmsize_t)(-1)); + } + return (TIFFAppendToStrip(tif, tile, (uint8*) data, cc) ? + cc : (tmsize_t)(-1)); +} + +#define isUnspecified(tif, f) \ + (TIFFFieldSet(tif,f) && (tif)->tif_dir.td_imagelength == 0) + +int +TIFFSetupStrips(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + + if (isTiled(tif)) + td->td_stripsperimage = + isUnspecified(tif, FIELD_TILEDIMENSIONS) ? + td->td_samplesperpixel : TIFFNumberOfTiles(tif); + else + td->td_stripsperimage = + isUnspecified(tif, FIELD_ROWSPERSTRIP) ? + td->td_samplesperpixel : TIFFNumberOfStrips(tif); + td->td_nstrips = td->td_stripsperimage; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + td->td_stripsperimage /= td->td_samplesperpixel; + td->td_stripoffset = (uint64 *) + _TIFFmalloc(td->td_nstrips * sizeof (uint64)); + td->td_stripbytecount = (uint64 *) + _TIFFmalloc(td->td_nstrips * sizeof (uint64)); + if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL) + return (0); + /* + * Place data at the end-of-file + * (by setting offsets to zero). + */ + _TIFFmemset(td->td_stripoffset, 0, td->td_nstrips*sizeof (uint64)); + _TIFFmemset(td->td_stripbytecount, 0, td->td_nstrips*sizeof (uint64)); + TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); + TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); + return (1); +} +#undef isUnspecified + +/* + * Verify file is writable and that the directory + * information is setup properly. In doing the latter + * we also "freeze" the state of the directory so + * that important information is not changed. + */ +int +TIFFWriteCheck(TIFF* tif, int tiles, const char* module) +{ + if (tif->tif_mode == O_RDONLY) { + TIFFErrorExt(tif->tif_clientdata, module, "File not open for writing"); + return (0); + } + if (tiles ^ isTiled(tif)) { + TIFFErrorExt(tif->tif_clientdata, module, tiles ? + "Can not write tiles to a stripped image" : + "Can not write scanlines to a tiled image"); + return (0); + } + + _TIFFFillStriles( tif ); + + /* + * On the first write verify all the required information + * has been setup and initialize any data structures that + * had to wait until directory information was set. + * Note that a lot of our work is assumed to remain valid + * because we disallow any of the important parameters + * from changing after we start writing (i.e. once + * TIFF_BEENWRITING is set, TIFFSetField will only allow + * the image's length to be changed). + */ + if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Must set \"ImageWidth\" before writing data"); + return (0); + } + if (tif->tif_dir.td_samplesperpixel == 1) { + /* + * Planarconfiguration is irrelevant in case of single band + * images and need not be included. We will set it anyway, + * because this field is used in other parts of library even + * in the single band case. + */ + if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) + tif->tif_dir.td_planarconfig = PLANARCONFIG_CONTIG; + } else { + if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Must set \"PlanarConfiguration\" before writing data"); + return (0); + } + } + if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) { + tif->tif_dir.td_nstrips = 0; + TIFFErrorExt(tif->tif_clientdata, module, "No space for %s arrays", + isTiled(tif) ? "tile" : "strip"); + return (0); + } + if (isTiled(tif)) + { + tif->tif_tilesize = TIFFTileSize(tif); + if (tif->tif_tilesize == 0) + return (0); + } + else + tif->tif_tilesize = (tmsize_t)(-1); + tif->tif_scanlinesize = TIFFScanlineSize(tif); + if (tif->tif_scanlinesize == 0) + return (0); + tif->tif_flags |= TIFF_BEENWRITING; + return (1); +} + +/* + * Setup the raw data buffer used for encoding. + */ +int +TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size) +{ + static const char module[] = "TIFFWriteBufferSetup"; + + if (tif->tif_rawdata) { + if (tif->tif_flags & TIFF_MYBUFFER) { + _TIFFfree(tif->tif_rawdata); + tif->tif_flags &= ~TIFF_MYBUFFER; + } + tif->tif_rawdata = NULL; + } + if (size == (tmsize_t)(-1)) { + size = (isTiled(tif) ? + tif->tif_tilesize : TIFFStripSize(tif)); + /* + * Make raw data buffer at least 8K + */ + if (size < 8*1024) + size = 8*1024; + bp = NULL; /* NB: force malloc */ + } + if (bp == NULL) { + bp = _TIFFmalloc(size); + if (bp == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, "No space for output buffer"); + return (0); + } + tif->tif_flags |= TIFF_MYBUFFER; + } else + tif->tif_flags &= ~TIFF_MYBUFFER; + tif->tif_rawdata = (uint8*) bp; + tif->tif_rawdatasize = size; + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + tif->tif_flags |= TIFF_BUFFERSETUP; + return (1); +} + +/* + * Grow the strip data structures by delta strips. + */ +static int +TIFFGrowStrips(TIFF* tif, uint32 delta, const char* module) +{ + TIFFDirectory *td = &tif->tif_dir; + uint64* new_stripoffset; + uint64* new_stripbytecount; + + assert(td->td_planarconfig == PLANARCONFIG_CONTIG); + new_stripoffset = (uint64*)_TIFFrealloc(td->td_stripoffset, + (td->td_nstrips + delta) * sizeof (uint64)); + new_stripbytecount = (uint64*)_TIFFrealloc(td->td_stripbytecount, + (td->td_nstrips + delta) * sizeof (uint64)); + if (new_stripoffset == NULL || new_stripbytecount == NULL) { + if (new_stripoffset) + _TIFFfree(new_stripoffset); + if (new_stripbytecount) + _TIFFfree(new_stripbytecount); + td->td_nstrips = 0; + TIFFErrorExt(tif->tif_clientdata, module, "No space to expand strip arrays"); + return (0); + } + td->td_stripoffset = new_stripoffset; + td->td_stripbytecount = new_stripbytecount; + _TIFFmemset(td->td_stripoffset + td->td_nstrips, + 0, delta*sizeof (uint64)); + _TIFFmemset(td->td_stripbytecount + td->td_nstrips, + 0, delta*sizeof (uint64)); + td->td_nstrips += delta; + tif->tif_flags |= TIFF_DIRTYDIRECT; + + return (1); +} + +/* + * Append the data to the specified strip. + */ +static int +TIFFAppendToStrip(TIFF* tif, uint32 strip, uint8* data, tmsize_t cc) +{ + static const char module[] = "TIFFAppendToStrip"; + TIFFDirectory *td = &tif->tif_dir; + uint64 m; + int64 old_byte_count = -1; + + if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) { + assert(td->td_nstrips > 0); + + if( td->td_stripbytecount[strip] != 0 + && td->td_stripoffset[strip] != 0 + && td->td_stripbytecount[strip] >= (uint64) cc ) + { + /* + * There is already tile data on disk, and the new tile + * data we have will fit in the same space. The only + * aspect of this that is risky is that there could be + * more data to append to this strip before we are done + * depending on how we are getting called. + */ + if (!SeekOK(tif, td->td_stripoffset[strip])) { + TIFFErrorExt(tif->tif_clientdata, module, + "Seek error at scanline %lu", + (unsigned long)tif->tif_row); + return (0); + } + } + else + { + /* + * Seek to end of file, and set that as our location to + * write this strip. + */ + td->td_stripoffset[strip] = TIFFSeekFile(tif, 0, SEEK_END); + tif->tif_flags |= TIFF_DIRTYSTRIP; + } + + tif->tif_curoff = td->td_stripoffset[strip]; + + /* + * We are starting a fresh strip/tile, so set the size to zero. + */ + old_byte_count = td->td_stripbytecount[strip]; + td->td_stripbytecount[strip] = 0; + } + + m = tif->tif_curoff+cc; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + m = (uint32)m; + if ((mtif_curoff)||(m<(uint64)cc)) + { + TIFFErrorExt(tif->tif_clientdata, module, "Maximum TIFF file size exceeded"); + return (0); + } + if (!WriteOK(tif, data, cc)) { + TIFFErrorExt(tif->tif_clientdata, module, "Write error at scanline %lu", + (unsigned long) tif->tif_row); + return (0); + } + tif->tif_curoff = m; + td->td_stripbytecount[strip] += cc; + + if( (int64) td->td_stripbytecount[strip] != old_byte_count ) + tif->tif_flags |= TIFF_DIRTYSTRIP; + + return (1); +} + +/* + * Internal version of TIFFFlushData that can be + * called by ``encodestrip routines'' w/o concern + * for infinite recursion. + */ +int +TIFFFlushData1(TIFF* tif) +{ + if (tif->tif_rawcc > 0 && tif->tif_flags & TIFF_BUF4WRITE ) { + if (!isFillOrder(tif, tif->tif_dir.td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits((uint8*)tif->tif_rawdata, + tif->tif_rawcc); + if (!TIFFAppendToStrip(tif, + isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip, + tif->tif_rawdata, tif->tif_rawcc)) + return (0); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + } + return (1); +} + +/* + * Set the current write offset. This should only be + * used to set the offset to a known previous location + * (very carefully), or to 0 so that the next write gets + * appended to the end of the file. + */ +void +TIFFSetWriteOffset(TIFF* tif, toff_t off) +{ + tif->tif_curoff = off; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tif_zip.c b/core/src/fxcodec/fx_tiff/tiff_v403/tif_zip.c new file mode 100644 index 0000000000..0bb2a8cb29 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tif_zip.c @@ -0,0 +1,471 @@ +/* $Id: tif_zip.c,v 1.31 2011-01-06 16:00:23 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1995-1997 Sam Leffler + * Copyright (c) 1995-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#if (!defined(_FPDFAPI_MINI_) || defined(_TIFF_DECODER_)) && !defined(_USE_ADDIN_) && !defined _FX_NO_ANSIC_ && !defined(_FX_EMB_NOUSE_DECODER_) +#include "tiffiop.h" +#ifdef ZIP_SUPPORT +/* + * TIFF Library. + * + * ZIP (aka Deflate) Compression Support + * + * This file is simply an interface to the zlib library written by + * Jean-loup Gailly and Mark Adler. You must use version 1.0 or later + * of the library: this code assumes the 1.0 API and also depends on + * the ability to write the zlib header multiple times (one per strip) + * which was not possible with versions prior to 0.95. Note also that + * older versions of this codec avoided this bug by supressing the header + * entirely. This means that files written with the old library cannot + * be read; they should be converted to a different compression scheme + * and then reconverted. + * + * The data format used by the zlib library is described in the files + * zlib-3.1.doc, deflate-1.1.doc and gzip-4.1.doc, available in the + * directory ftp://ftp.uu.net/pub/archiving/zip/doc. The library was + * last found at ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib-0.99.tar.gz. + */ +#include "tif_predict.h" +#include "../../fx_zlib/include/fx_zlib.h" + +#include + +/* + * Sigh, ZLIB_VERSION is defined as a string so there's no + * way to do a proper check here. Instead we guess based + * on the presence of #defines that were added between the + * 0.95 and 1.0 distributions. + */ +#if !defined(Z_NO_COMPRESSION) || !defined(Z_DEFLATED) +#error "Antiquated ZLIB software; you must use version 1.0 or later" +#endif + +/* + * State block for each open TIFF + * file using ZIP compression/decompression. + */ +typedef struct { + TIFFPredictorState predict; + z_stream stream; + int zipquality; /* compression level */ + int state; /* state flags */ +#define ZSTATE_INIT_DECODE 0x01 +#define ZSTATE_INIT_ENCODE 0x02 + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +} ZIPState; + +#define ZState(tif) ((ZIPState*) (tif)->tif_data) +#define DecoderState(tif) ZState(tif) +#define EncoderState(tif) ZState(tif) + +static int ZIPEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s); +static int ZIPDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s); + +static int +ZIPFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +static int +ZIPSetupDecode(TIFF* tif) +{ + static const char module[] = "ZIPSetupDecode"; + ZIPState* sp = DecoderState(tif); + + assert(sp != NULL); + + /* if we were last encoding, terminate this mode */ + if (sp->state & ZSTATE_INIT_ENCODE) { + deflateEnd(&sp->stream); + sp->state = 0; + } + + if (inflateInit(&sp->stream) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg); + return (0); + } else { + sp->state |= ZSTATE_INIT_DECODE; + return (1); + } +} + +/* + * Setup state for decoding a strip. + */ +static int +ZIPPreDecode(TIFF* tif, uint16 s) +{ + static const char module[] = "ZIPPreDecode"; + ZIPState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + + if( (sp->state & ZSTATE_INIT_DECODE) == 0 ) + tif->tif_setupdecode( tif ); + + sp->stream.next_in = tif->tif_rawdata; + assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + apropriately even before we simplify it */ + sp->stream.avail_in = (uInt) tif->tif_rawcc; + if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc) + { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size"); + return (0); + } + return (inflateReset(&sp->stream) == Z_OK); +} + +static int +ZIPDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s) +{ + static const char module[] = "ZIPDecode"; + ZIPState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + assert(sp->state == ZSTATE_INIT_DECODE); + + sp->stream.next_in = tif->tif_rawcp; + sp->stream.avail_in = (uInt) tif->tif_rawcc; + + sp->stream.next_out = op; + assert(sizeof(sp->stream.avail_out)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + apropriately even before we simplify it */ + sp->stream.avail_out = (uInt) occ; + if ((tmsize_t)sp->stream.avail_out != occ) + { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size"); + return (0); + } + do { + int state = inflate(&sp->stream, Z_PARTIAL_FLUSH); + if (state == Z_STREAM_END) + break; + if (state == Z_DATA_ERROR) { + TIFFErrorExt(tif->tif_clientdata, module, + "Decoding error at scanline %lu, %s", + (unsigned long) tif->tif_row, sp->stream.msg); + if (inflateSync(&sp->stream) != Z_OK) + return (0); + continue; + } + if (state != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", + sp->stream.msg); + return (0); + } + } while (sp->stream.avail_out > 0); + if (sp->stream.avail_out != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at scanline %lu (short " TIFF_UINT64_FORMAT " bytes)", + (unsigned long) tif->tif_row, (TIFF_UINT64_T) sp->stream.avail_out); + return (0); + } + + tif->tif_rawcp = sp->stream.next_in; + tif->tif_rawcc = sp->stream.avail_in; + + return (1); +} + +static int +ZIPSetupEncode(TIFF* tif) +{ + static const char module[] = "ZIPSetupEncode"; + ZIPState* sp = EncoderState(tif); + + assert(sp != NULL); + if (sp->state & ZSTATE_INIT_DECODE) { + inflateEnd(&sp->stream); + sp->state = 0; + } + + if (deflateInit(&sp->stream, sp->zipquality) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg); + return (0); + } else { + sp->state |= ZSTATE_INIT_ENCODE; + return (1); + } +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +ZIPPreEncode(TIFF* tif, uint16 s) +{ + static const char module[] = "ZIPPreEncode"; + ZIPState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + if( sp->state != ZSTATE_INIT_ENCODE ) + tif->tif_setupencode( tif ); + + sp->stream.next_out = tif->tif_rawdata; + assert(sizeof(sp->stream.avail_out)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + apropriately even before we simplify it */ + sp->stream.avail_out = (uInt)tif->tif_rawdatasize; + if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) + { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size"); + return (0); + } + return (deflateReset(&sp->stream) == Z_OK); +} + +/* + * Encode a chunk of pixels. + */ +static int +ZIPEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) +{ + static const char module[] = "ZIPEncode"; + ZIPState *sp = EncoderState(tif); + + assert(sp != NULL); + assert(sp->state == ZSTATE_INIT_ENCODE); + + (void) s; + sp->stream.next_in = bp; + assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + apropriately even before we simplify it */ + sp->stream.avail_in = (uInt) cc; + if ((tmsize_t)sp->stream.avail_in != cc) + { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size"); + return (0); + } + do { + if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "Encoder error: %s", + sp->stream.msg); + return (0); + } + if (sp->stream.avail_out == 0) { + tif->tif_rawcc = tif->tif_rawdatasize; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (uInt) tif->tif_rawdatasize; /* this is a safe typecast, as check is made already in ZIPPreEncode */ + } + } while (sp->stream.avail_in > 0); + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ +static int +ZIPPostEncode(TIFF* tif) +{ + static const char module[] = "ZIPPostEncode"; + ZIPState *sp = EncoderState(tif); + int state; + + sp->stream.avail_in = 0; + do { + state = deflate(&sp->stream, Z_FINISH); + switch (state) { + case Z_STREAM_END: + case Z_OK: + if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) + { + tif->tif_rawcc = tif->tif_rawdatasize - sp->stream.avail_out; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (uInt) tif->tif_rawdatasize; /* this is a safe typecast, as check is made already in ZIPPreEncode */ + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", + sp->stream.msg); + return (0); + } + } while (state != Z_STREAM_END); + return (1); +} + +static void +ZIPCleanup(TIFF* tif) +{ + ZIPState* sp = ZState(tif); + + assert(sp != 0); + + (void)TIFFPredictorCleanup(tif); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->state & ZSTATE_INIT_ENCODE) { + deflateEnd(&sp->stream); + sp->state = 0; + } else if( sp->state & ZSTATE_INIT_DECODE) { + inflateEnd(&sp->stream); + sp->state = 0; + } + _TIFFfree(sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int +ZIPVSetField(TIFF* tif, uint32 tag, va_list ap) +{ + static const char module[] = "ZIPVSetField"; + ZIPState* sp = ZState(tif); + + switch (tag) { + case TIFFTAG_ZIPQUALITY: + sp->zipquality = (int) va_arg(ap, int); + if ( sp->state&ZSTATE_INIT_ENCODE ) { + if (deflateParams(&sp->stream, + sp->zipquality, Z_DEFAULT_STRATEGY) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", + sp->stream.msg); + return (0); + } + } + return (1); + default: + return (*sp->vsetparent)(tif, tag, ap); + } + /*NOTREACHED*/ +} + +static int +ZIPVGetField(TIFF* tif, uint32 tag, va_list ap) +{ + ZIPState* sp = ZState(tif); + + switch (tag) { + case TIFFTAG_ZIPQUALITY: + *va_arg(ap, int*) = sp->zipquality; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static const TIFFField zipFields[] = { + { TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL }, +}; + +int +TIFFInitZIP(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitZIP"; + ZIPState* sp; + + assert( (scheme == COMPRESSION_DEFLATE) + || (scheme == COMPRESSION_ADOBE_DEFLATE)); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, zipFields, TIFFArrayCount(zipFields))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging Deflate codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8*) _TIFFmalloc(sizeof (ZIPState)); + if (tif->tif_data == NULL) + goto bad; + sp = ZState(tif); + sp->stream.zalloc = NULL; + sp->stream.zfree = NULL; + sp->stream.opaque = NULL; + sp->stream.data_type = Z_BINARY; + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = ZIPVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = ZIPVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->zipquality = Z_DEFAULT_COMPRESSION; /* default comp. level */ + sp->state = 0; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = ZIPFixupTags; + tif->tif_setupdecode = ZIPSetupDecode; + tif->tif_predecode = ZIPPreDecode; + tif->tif_decoderow = ZIPDecode; + tif->tif_decodestrip = ZIPDecode; + tif->tif_decodetile = ZIPDecode; + tif->tif_setupencode = ZIPSetupEncode; + tif->tif_preencode = ZIPPreEncode; + tif->tif_postencode = ZIPPostEncode; + tif->tif_encoderow = ZIPEncode; + tif->tif_encodestrip = ZIPEncode; + tif->tif_encodetile = ZIPEncode; + tif->tif_cleanup = ZIPCleanup; + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "No space for ZIP state block"); + return (0); +} +#endif /* ZIP_SUPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ +#endif + diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tiff.h b/core/src/fxcodec/fx_tiff/tiff_v403/tiff.h new file mode 100644 index 0000000000..19b4e7976d --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tiff.h @@ -0,0 +1,678 @@ +/* $Id: tiff.h,v 1.68 2012-08-19 16:56:35 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFF_ +#define _TIFF_ + +#include "tiffconf.h" + +/* + * Tag Image File Format (TIFF) + * + * Based on Rev 6.0 from: + * Developer's Desk + * Aldus Corporation + * 411 First Ave. South + * Suite 200 + * Seattle, WA 98104 + * 206-622-5500 + * + * (http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf) + * + * For BigTIFF design notes see the following links + * http://www.remotesensing.org/libtiff/bigtiffdesign.html + * http://www.awaresystems.be/imaging/tiff/bigtiff.html + */ + +#define TIFF_VERSION_CLASSIC 42 +#define TIFF_VERSION_BIG 43 + +#define TIFF_BIGENDIAN 0x4d4d +#define TIFF_LITTLEENDIAN 0x4949 +#define MDI_LITTLEENDIAN 0x5045 +#define MDI_BIGENDIAN 0x4550 + +/* + * Intrinsic data types required by the file format: + * + * 8-bit quantities int8/uint8 + * 16-bit quantities int16/uint16 + * 32-bit quantities int32/uint32 + * 64-bit quantities int64/uint64 + * strings unsigned char* + */ + +typedef TIFF_INT8_T int8; +typedef TIFF_UINT8_T uint8; + +typedef TIFF_INT16_T int16; +typedef TIFF_UINT16_T uint16; + +typedef TIFF_INT32_T int32; +typedef TIFF_UINT32_T uint32; + +typedef TIFF_INT64_T int64; +typedef TIFF_UINT64_T uint64; + +/* + * Some types as promoted in a variable argument list + * We use uint16_vap rather then directly using int, because this way + * we document the type we actually want to pass through, conceptually, + * rather then confusing the issue by merely stating the type it gets + * promoted to + */ + +typedef int uint16_vap; + +/* + * TIFF header. + */ +typedef struct { + uint16 tiff_magic; /* magic number (defines byte order) */ + uint16 tiff_version; /* TIFF version number */ +} TIFFHeaderCommon; +typedef struct { + uint16 tiff_magic; /* magic number (defines byte order) */ + uint16 tiff_version; /* TIFF version number */ + uint32 tiff_diroff; /* byte offset to first directory */ +} TIFFHeaderClassic; +typedef struct { + uint16 tiff_magic; /* magic number (defines byte order) */ + uint16 tiff_version; /* TIFF version number */ + uint16 tiff_offsetsize; /* size of offsets, should be 8 */ + uint16 tiff_unused; /* unused word, should be 0 */ + uint64 tiff_diroff; /* byte offset to first directory */ +} TIFFHeaderBig; + + +/* + * NB: In the comments below, + * - items marked with a + are obsoleted by revision 5.0, + * - items marked with a ! are introduced in revision 6.0. + * - items marked with a % are introduced post revision 6.0. + * - items marked with a $ are obsoleted by revision 6.0. + * - items marked with a & are introduced by Adobe DNG specification. + */ + +/* + * Tag data type information. + * + * Note: RATIONALs are the ratio of two 32-bit integer values. + */ +typedef enum { + TIFF_NOTYPE = 0, /* placeholder */ + TIFF_BYTE = 1, /* 8-bit unsigned integer */ + TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */ + TIFF_SHORT = 3, /* 16-bit unsigned integer */ + TIFF_LONG = 4, /* 32-bit unsigned integer */ + TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */ + TIFF_SBYTE = 6, /* !8-bit signed integer */ + TIFF_UNDEFINED = 7, /* !8-bit untyped data */ + TIFF_SSHORT = 8, /* !16-bit signed integer */ + TIFF_SLONG = 9, /* !32-bit signed integer */ + TIFF_SRATIONAL = 10, /* !64-bit signed fraction */ + TIFF_FLOAT = 11, /* !32-bit IEEE floating point */ + TIFF_DOUBLE = 12, /* !64-bit IEEE floating point */ + TIFF_IFD = 13, /* %32-bit unsigned integer (offset) */ + TIFF_LONG8 = 16, /* BigTIFF 64-bit unsigned integer */ + TIFF_SLONG8 = 17, /* BigTIFF 64-bit signed integer */ + TIFF_IFD8 = 18 /* BigTIFF 64-bit unsigned integer (offset) */ +} TIFFDataType; + +/* + * TIFF Tag Definitions. + */ +#define TIFFTAG_SUBFILETYPE 254 /* subfile data descriptor */ +#define FILETYPE_REDUCEDIMAGE 0x1 /* reduced resolution version */ +#define FILETYPE_PAGE 0x2 /* one page of many */ +#define FILETYPE_MASK 0x4 /* transparency mask */ +#define TIFFTAG_OSUBFILETYPE 255 /* +kind of data in subfile */ +#define OFILETYPE_IMAGE 1 /* full resolution image data */ +#define OFILETYPE_REDUCEDIMAGE 2 /* reduced size image data */ +#define OFILETYPE_PAGE 3 /* one page of many */ +#define TIFFTAG_IMAGEWIDTH 256 /* image width in pixels */ +#define TIFFTAG_IMAGELENGTH 257 /* image height in pixels */ +#define TIFFTAG_BITSPERSAMPLE 258 /* bits per channel (sample) */ +#define TIFFTAG_COMPRESSION 259 /* data compression technique */ +#define COMPRESSION_NONE 1 /* dump mode */ +#define COMPRESSION_CCITTRLE 2 /* CCITT modified Huffman RLE */ +#define COMPRESSION_CCITTFAX3 3 /* CCITT Group 3 fax encoding */ +#define COMPRESSION_CCITT_T4 3 /* CCITT T.4 (TIFF 6 name) */ +#define COMPRESSION_CCITTFAX4 4 /* CCITT Group 4 fax encoding */ +#define COMPRESSION_CCITT_T6 4 /* CCITT T.6 (TIFF 6 name) */ +#define COMPRESSION_LZW 5 /* Lempel-Ziv & Welch */ +#define COMPRESSION_OJPEG 6 /* !6.0 JPEG */ +#define COMPRESSION_JPEG 7 /* %JPEG DCT compression */ +#define COMPRESSION_T85 9 /* !TIFF/FX T.85 JBIG compression */ +#define COMPRESSION_T43 10 /* !TIFF/FX T.43 colour by layered JBIG compression */ +#define COMPRESSION_NEXT 32766 /* NeXT 2-bit RLE */ +#define COMPRESSION_CCITTRLEW 32771 /* #1 w/ word alignment */ +#define COMPRESSION_PACKBITS 32773 /* Macintosh RLE */ +#define COMPRESSION_THUNDERSCAN 32809 /* ThunderScan RLE */ +/* codes 32895-32898 are reserved for ANSI IT8 TIFF/IT */ +#define COMPRESSION_DCS 32947 /* Kodak DCS encoding */ +#define COMPRESSION_JBIG 34661 /* ISO JBIG */ +#define COMPRESSION_SGILOG 34676 /* SGI Log Luminance RLE */ +#define COMPRESSION_SGILOG24 34677 /* SGI Log 24-bit packed */ +#define COMPRESSION_JP2000 34712 /* Leadtools JPEG2000 */ +#define COMPRESSION_LZMA 34925 /* LZMA2 */ +#define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */ +#define PHOTOMETRIC_MINISWHITE 0 /* min value is white */ +#define PHOTOMETRIC_MINISBLACK 1 /* min value is black */ +#define PHOTOMETRIC_RGB 2 /* RGB color model */ +#define PHOTOMETRIC_PALETTE 3 /* color map indexed */ +#define PHOTOMETRIC_MASK 4 /* $holdout mask */ +#define PHOTOMETRIC_SEPARATED 5 /* !color separations */ +#define PHOTOMETRIC_YCBCR 6 /* !CCIR 601 */ +#define PHOTOMETRIC_CIELAB 8 /* !1976 CIE L*a*b* */ +#define PHOTOMETRIC_ICCLAB 9 /* ICC L*a*b* [Adobe TIFF Technote 4] */ +#define PHOTOMETRIC_ITULAB 10 /* ITU L*a*b* */ +#define PHOTOMETRIC_LOGL 32844 /* CIE Log2(L) */ +#define PHOTOMETRIC_LOGLUV 32845 /* CIE Log2(L) (u',v') */ +#define TIFFTAG_THRESHHOLDING 263 /* +thresholding used on data */ +#define THRESHHOLD_BILEVEL 1 /* b&w art scan */ +#define THRESHHOLD_HALFTONE 2 /* or dithered scan */ +#define THRESHHOLD_ERRORDIFFUSE 3 /* usually floyd-steinberg */ +#define TIFFTAG_CELLWIDTH 264 /* +dithering matrix width */ +#define TIFFTAG_CELLLENGTH 265 /* +dithering matrix height */ +#define TIFFTAG_FILLORDER 266 /* data order within a byte */ +#define FILLORDER_MSB2LSB 1 /* most significant -> least */ +#define FILLORDER_LSB2MSB 2 /* least significant -> most */ +#define TIFFTAG_DOCUMENTNAME 269 /* name of doc. image is from */ +#define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */ +#define TIFFTAG_MAKE 271 /* scanner manufacturer name */ +#define TIFFTAG_MODEL 272 /* scanner model name/number */ +#define TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */ +#define TIFFTAG_ORIENTATION 274 /* +image orientation */ +#define ORIENTATION_TOPLEFT 1 /* row 0 top, col 0 lhs */ +#define ORIENTATION_TOPRIGHT 2 /* row 0 top, col 0 rhs */ +#define ORIENTATION_BOTRIGHT 3 /* row 0 bottom, col 0 rhs */ +#define ORIENTATION_BOTLEFT 4 /* row 0 bottom, col 0 lhs */ +#define ORIENTATION_LEFTTOP 5 /* row 0 lhs, col 0 top */ +#define ORIENTATION_RIGHTTOP 6 /* row 0 rhs, col 0 top */ +#define ORIENTATION_RIGHTBOT 7 /* row 0 rhs, col 0 bottom */ +#define ORIENTATION_LEFTBOT 8 /* row 0 lhs, col 0 bottom */ +#define TIFFTAG_SAMPLESPERPIXEL 277 /* samples per pixel */ +#define TIFFTAG_ROWSPERSTRIP 278 /* rows per strip of data */ +#define TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */ +#define TIFFTAG_MINSAMPLEVALUE 280 /* +minimum sample value */ +#define TIFFTAG_MAXSAMPLEVALUE 281 /* +maximum sample value */ +#define TIFFTAG_XRESOLUTION 282 /* pixels/resolution in x */ +#define TIFFTAG_YRESOLUTION 283 /* pixels/resolution in y */ +#define TIFFTAG_PLANARCONFIG 284 /* storage organization */ +#define PLANARCONFIG_CONTIG 1 /* single image plane */ +#define PLANARCONFIG_SEPARATE 2 /* separate planes of data */ +#define TIFFTAG_PAGENAME 285 /* page name image is from */ +#define TIFFTAG_XPOSITION 286 /* x page offset of image lhs */ +#define TIFFTAG_YPOSITION 287 /* y page offset of image lhs */ +#define TIFFTAG_FREEOFFSETS 288 /* +byte offset to free block */ +#define TIFFTAG_FREEBYTECOUNTS 289 /* +sizes of free blocks */ +#define TIFFTAG_GRAYRESPONSEUNIT 290 /* $gray scale curve accuracy */ +#define GRAYRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define GRAYRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define GRAYRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define GRAYRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define GRAYRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_GRAYRESPONSECURVE 291 /* $gray scale response curve */ +#define TIFFTAG_GROUP3OPTIONS 292 /* 32 flag bits */ +#define TIFFTAG_T4OPTIONS 292 /* TIFF 6.0 proper name alias */ +#define GROUP3OPT_2DENCODING 0x1 /* 2-dimensional coding */ +#define GROUP3OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define GROUP3OPT_FILLBITS 0x4 /* fill to byte boundary */ +#define TIFFTAG_GROUP4OPTIONS 293 /* 32 flag bits */ +#define TIFFTAG_T6OPTIONS 293 /* TIFF 6.0 proper name */ +#define GROUP4OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define TIFFTAG_RESOLUTIONUNIT 296 /* units of resolutions */ +#define RESUNIT_NONE 1 /* no meaningful units */ +#define RESUNIT_INCH 2 /* english */ +#define RESUNIT_CENTIMETER 3 /* metric */ +#define TIFFTAG_PAGENUMBER 297 /* page numbers of multi-page */ +#define TIFFTAG_COLORRESPONSEUNIT 300 /* $color curve accuracy */ +#define COLORRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define COLORRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define COLORRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define COLORRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define COLORRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_TRANSFERFUNCTION 301 /* !colorimetry info */ +#define TIFFTAG_SOFTWARE 305 /* name & release */ +#define TIFFTAG_DATETIME 306 /* creation date and time */ +#define TIFFTAG_ARTIST 315 /* creator of image */ +#define TIFFTAG_HOSTCOMPUTER 316 /* machine where created */ +#define TIFFTAG_PREDICTOR 317 /* prediction scheme w/ LZW */ +#define PREDICTOR_NONE 1 /* no prediction scheme used */ +#define PREDICTOR_HORIZONTAL 2 /* horizontal differencing */ +#define PREDICTOR_FLOATINGPOINT 3 /* floating point predictor */ +#define TIFFTAG_WHITEPOINT 318 /* image white point */ +#define TIFFTAG_PRIMARYCHROMATICITIES 319 /* !primary chromaticities */ +#define TIFFTAG_COLORMAP 320 /* RGB map for pallette image */ +#define TIFFTAG_HALFTONEHINTS 321 /* !highlight+shadow info */ +#define TIFFTAG_TILEWIDTH 322 /* !tile width in pixels */ +#define TIFFTAG_TILELENGTH 323 /* !tile height in pixels */ +#define TIFFTAG_TILEOFFSETS 324 /* !offsets to data tiles */ +#define TIFFTAG_TILEBYTECOUNTS 325 /* !byte counts for tiles */ +#define TIFFTAG_BADFAXLINES 326 /* lines w/ wrong pixel count */ +#define TIFFTAG_CLEANFAXDATA 327 /* regenerated line info */ +#define CLEANFAXDATA_CLEAN 0 /* no errors detected */ +#define CLEANFAXDATA_REGENERATED 1 /* receiver regenerated lines */ +#define CLEANFAXDATA_UNCLEAN 2 /* uncorrected errors exist */ +#define TIFFTAG_CONSECUTIVEBADFAXLINES 328 /* max consecutive bad lines */ +#define TIFFTAG_SUBIFD 330 /* subimage descriptors */ +#define TIFFTAG_INKSET 332 /* !inks in separated image */ +#define INKSET_CMYK 1 /* !cyan-magenta-yellow-black color */ +#define INKSET_MULTIINK 2 /* !multi-ink or hi-fi color */ +#define TIFFTAG_INKNAMES 333 /* !ascii names of inks */ +#define TIFFTAG_NUMBEROFINKS 334 /* !number of inks */ +#define TIFFTAG_DOTRANGE 336 /* !0% and 100% dot codes */ +#define TIFFTAG_TARGETPRINTER 337 /* !separation target */ +#define TIFFTAG_EXTRASAMPLES 338 /* !info about extra samples */ +#define EXTRASAMPLE_UNSPECIFIED 0 /* !unspecified data */ +#define EXTRASAMPLE_ASSOCALPHA 1 /* !associated alpha data */ +#define EXTRASAMPLE_UNASSALPHA 2 /* !unassociated alpha data */ +#define TIFFTAG_SAMPLEFORMAT 339 /* !data sample format */ +#define SAMPLEFORMAT_UINT 1 /* !unsigned integer data */ +#define SAMPLEFORMAT_INT 2 /* !signed integer data */ +#define SAMPLEFORMAT_IEEEFP 3 /* !IEEE floating point data */ +#define SAMPLEFORMAT_VOID 4 /* !untyped data */ +#define SAMPLEFORMAT_COMPLEXINT 5 /* !complex signed int */ +#define SAMPLEFORMAT_COMPLEXIEEEFP 6 /* !complex ieee floating */ +#define TIFFTAG_SMINSAMPLEVALUE 340 /* !variable MinSampleValue */ +#define TIFFTAG_SMAXSAMPLEVALUE 341 /* !variable MaxSampleValue */ +#define TIFFTAG_CLIPPATH 343 /* %ClipPath + [Adobe TIFF technote 2] */ +#define TIFFTAG_XCLIPPATHUNITS 344 /* %XClipPathUnits + [Adobe TIFF technote 2] */ +#define TIFFTAG_YCLIPPATHUNITS 345 /* %YClipPathUnits + [Adobe TIFF technote 2] */ +#define TIFFTAG_INDEXED 346 /* %Indexed + [Adobe TIFF Technote 3] */ +#define TIFFTAG_JPEGTABLES 347 /* %JPEG table stream */ +#define TIFFTAG_OPIPROXY 351 /* %OPI Proxy [Adobe TIFF technote] */ +/* Tags 400-435 are from the TIFF/FX spec */ +#define TIFFTAG_GLOBALPARAMETERSIFD 400 /* ! */ +#define TIFFTAG_PROFILETYPE 401 /* ! */ +#define PROFILETYPE_UNSPECIFIED 0 /* ! */ +#define PROFILETYPE_G3_FAX 1 /* ! */ +#define TIFFTAG_FAXPROFILE 402 /* ! */ +#define FAXPROFILE_S 1 /* !TIFF/FX FAX profile S */ +#define FAXPROFILE_F 2 /* !TIFF/FX FAX profile F */ +#define FAXPROFILE_J 3 /* !TIFF/FX FAX profile J */ +#define FAXPROFILE_C 4 /* !TIFF/FX FAX profile C */ +#define FAXPROFILE_L 5 /* !TIFF/FX FAX profile L */ +#define FAXPROFILE_M 6 /* !TIFF/FX FAX profile LM */ +#define TIFFTAG_CODINGMETHODS 403 /* !TIFF/FX coding methods */ +#define CODINGMETHODS_T4_1D (1 << 1) /* !T.4 1D */ +#define CODINGMETHODS_T4_2D (1 << 2) /* !T.4 2D */ +#define CODINGMETHODS_T6 (1 << 3) /* !T.6 */ +#define CODINGMETHODS_T85 (1 << 4) /* !T.85 JBIG */ +#define CODINGMETHODS_T42 (1 << 5) /* !T.42 JPEG */ +#define CODINGMETHODS_T43 (1 << 6) /* !T.43 colour by layered JBIG */ +#define TIFFTAG_VERSIONYEAR 404 /* !TIFF/FX version year */ +#define TIFFTAG_MODENUMBER 405 /* !TIFF/FX mode number */ +#define TIFFTAG_DECODE 433 /* !TIFF/FX decode */ +#define TIFFTAG_IMAGEBASECOLOR 434 /* !TIFF/FX image base colour */ +#define TIFFTAG_T82OPTIONS 435 /* !TIFF/FX T.82 options */ +/* + * Tags 512-521 are obsoleted by Technical Note #2 which specifies a + * revised JPEG-in-TIFF scheme. + */ +#define TIFFTAG_JPEGPROC 512 /* !JPEG processing algorithm */ +#define JPEGPROC_BASELINE 1 /* !baseline sequential */ +#define JPEGPROC_LOSSLESS 14 /* !Huffman coded lossless */ +#define TIFFTAG_JPEGIFOFFSET 513 /* !pointer to SOI marker */ +#define TIFFTAG_JPEGIFBYTECOUNT 514 /* !JFIF stream length */ +#define TIFFTAG_JPEGRESTARTINTERVAL 515 /* !restart interval length */ +#define TIFFTAG_JPEGLOSSLESSPREDICTORS 517 /* !lossless proc predictor */ +#define TIFFTAG_JPEGPOINTTRANSFORM 518 /* !lossless point transform */ +#define TIFFTAG_JPEGQTABLES 519 /* !Q matrice offsets */ +#define TIFFTAG_JPEGDCTABLES 520 /* !DCT table offsets */ +#define TIFFTAG_JPEGACTABLES 521 /* !AC coefficient offsets */ +#define TIFFTAG_YCBCRCOEFFICIENTS 529 /* !RGB -> YCbCr transform */ +#define TIFFTAG_YCBCRSUBSAMPLING 530 /* !YCbCr subsampling factors */ +#define TIFFTAG_YCBCRPOSITIONING 531 /* !subsample positioning */ +#define YCBCRPOSITION_CENTERED 1 /* !as in PostScript Level 2 */ +#define YCBCRPOSITION_COSITED 2 /* !as in CCIR 601-1 */ +#define TIFFTAG_REFERENCEBLACKWHITE 532 /* !colorimetry info */ +#define TIFFTAG_STRIPROWCOUNTS 559 /* !TIFF/FX strip row counts */ +#define TIFFTAG_XMLPACKET 700 /* %XML packet + [Adobe XMP Specification, + January 2004 */ +#define TIFFTAG_OPIIMAGEID 32781 /* %OPI ImageID + [Adobe TIFF technote] */ +/* tags 32952-32956 are private tags registered to Island Graphics */ +#define TIFFTAG_REFPTS 32953 /* image reference points */ +#define TIFFTAG_REGIONTACKPOINT 32954 /* region-xform tack point */ +#define TIFFTAG_REGIONWARPCORNERS 32955 /* warp quadrilateral */ +#define TIFFTAG_REGIONAFFINE 32956 /* affine transformation mat */ +/* tags 32995-32999 are private tags registered to SGI */ +#define TIFFTAG_MATTEING 32995 /* $use ExtraSamples */ +#define TIFFTAG_DATATYPE 32996 /* $use SampleFormat */ +#define TIFFTAG_IMAGEDEPTH 32997 /* z depth of image */ +#define TIFFTAG_TILEDEPTH 32998 /* z depth/data tile */ +/* tags 33300-33309 are private tags registered to Pixar */ +/* + * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH + * are set when an image has been cropped out of a larger image. + * They reflect the size of the original uncropped image. + * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used + * to determine the position of the smaller image in the larger one. + */ +#define TIFFTAG_PIXAR_IMAGEFULLWIDTH 33300 /* full image size in x */ +#define TIFFTAG_PIXAR_IMAGEFULLLENGTH 33301 /* full image size in y */ + /* Tags 33302-33306 are used to identify special image modes and data + * used by Pixar's texture formats. + */ +#define TIFFTAG_PIXAR_TEXTUREFORMAT 33302 /* texture map format */ +#define TIFFTAG_PIXAR_WRAPMODES 33303 /* s & t wrap modes */ +#define TIFFTAG_PIXAR_FOVCOT 33304 /* cotan(fov) for env. maps */ +#define TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN 33305 +#define TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA 33306 +/* tag 33405 is a private tag registered to Eastman Kodak */ +#define TIFFTAG_WRITERSERIALNUMBER 33405 /* device serial number */ +/* tag 33432 is listed in the 6.0 spec w/ unknown ownership */ +#define TIFFTAG_COPYRIGHT 33432 /* copyright string */ +/* IPTC TAG from RichTIFF specifications */ +#define TIFFTAG_RICHTIFFIPTC 33723 +/* 34016-34029 are reserved for ANSI IT8 TIFF/IT */ +#define TIFFTAG_STONITS 37439 /* Sample value to Nits */ +/* tag 34929 is a private tag registered to FedEx */ +#define TIFFTAG_FEDEX_EDR 34929 /* unknown use */ +#define TIFFTAG_INTEROPERABILITYIFD 40965 /* Pointer to Interoperability private directory */ +/* Adobe Digital Negative (DNG) format tags */ +#define TIFFTAG_DNGVERSION 50706 /* &DNG version number */ +#define TIFFTAG_DNGBACKWARDVERSION 50707 /* &DNG compatibility version */ +#define TIFFTAG_UNIQUECAMERAMODEL 50708 /* &name for the camera model */ +#define TIFFTAG_LOCALIZEDCAMERAMODEL 50709 /* &localized camera model + name */ +#define TIFFTAG_CFAPLANECOLOR 50710 /* &CFAPattern->LinearRaw space + mapping */ +#define TIFFTAG_CFALAYOUT 50711 /* &spatial layout of the CFA */ +#define TIFFTAG_LINEARIZATIONTABLE 50712 /* &lookup table description */ +#define TIFFTAG_BLACKLEVELREPEATDIM 50713 /* &repeat pattern size for + the BlackLevel tag */ +#define TIFFTAG_BLACKLEVEL 50714 /* &zero light encoding level */ +#define TIFFTAG_BLACKLEVELDELTAH 50715 /* &zero light encoding level + differences (columns) */ +#define TIFFTAG_BLACKLEVELDELTAV 50716 /* &zero light encoding level + differences (rows) */ +#define TIFFTAG_WHITELEVEL 50717 /* &fully saturated encoding + level */ +#define TIFFTAG_DEFAULTSCALE 50718 /* &default scale factors */ +#define TIFFTAG_DEFAULTCROPORIGIN 50719 /* &origin of the final image + area */ +#define TIFFTAG_DEFAULTCROPSIZE 50720 /* &size of the final image + area */ +#define TIFFTAG_COLORMATRIX1 50721 /* &XYZ->reference color space + transformation matrix 1 */ +#define TIFFTAG_COLORMATRIX2 50722 /* &XYZ->reference color space + transformation matrix 2 */ +#define TIFFTAG_CAMERACALIBRATION1 50723 /* &calibration matrix 1 */ +#define TIFFTAG_CAMERACALIBRATION2 50724 /* &calibration matrix 2 */ +#define TIFFTAG_REDUCTIONMATRIX1 50725 /* &dimensionality reduction + matrix 1 */ +#define TIFFTAG_REDUCTIONMATRIX2 50726 /* &dimensionality reduction + matrix 2 */ +#define TIFFTAG_ANALOGBALANCE 50727 /* &gain applied the stored raw + values*/ +#define TIFFTAG_ASSHOTNEUTRAL 50728 /* &selected white balance in + linear reference space */ +#define TIFFTAG_ASSHOTWHITEXY 50729 /* &selected white balance in + x-y chromaticity + coordinates */ +#define TIFFTAG_BASELINEEXPOSURE 50730 /* &how much to move the zero + point */ +#define TIFFTAG_BASELINENOISE 50731 /* &relative noise level */ +#define TIFFTAG_BASELINESHARPNESS 50732 /* &relative amount of + sharpening */ +#define TIFFTAG_BAYERGREENSPLIT 50733 /* &how closely the values of + the green pixels in the + blue/green rows track the + values of the green pixels + in the red/green rows */ +#define TIFFTAG_LINEARRESPONSELIMIT 50734 /* &non-linear encoding range */ +#define TIFFTAG_CAMERASERIALNUMBER 50735 /* &camera's serial number */ +#define TIFFTAG_LENSINFO 50736 /* info about the lens */ +#define TIFFTAG_CHROMABLURRADIUS 50737 /* &chroma blur radius */ +#define TIFFTAG_ANTIALIASSTRENGTH 50738 /* &relative strength of the + camera's anti-alias filter */ +#define TIFFTAG_SHADOWSCALE 50739 /* &used by Adobe Camera Raw */ +#define TIFFTAG_DNGPRIVATEDATA 50740 /* &manufacturer's private data */ +#define TIFFTAG_MAKERNOTESAFETY 50741 /* &whether the EXIF MakerNote + tag is safe to preserve + along with the rest of the + EXIF data */ +#define TIFFTAG_CALIBRATIONILLUMINANT1 50778 /* &illuminant 1 */ +#define TIFFTAG_CALIBRATIONILLUMINANT2 50779 /* &illuminant 2 */ +#define TIFFTAG_BESTQUALITYSCALE 50780 /* &best quality multiplier */ +#define TIFFTAG_RAWDATAUNIQUEID 50781 /* &unique identifier for + the raw image data */ +#define TIFFTAG_ORIGINALRAWFILENAME 50827 /* &file name of the original + raw file */ +#define TIFFTAG_ORIGINALRAWFILEDATA 50828 /* &contents of the original + raw file */ +#define TIFFTAG_ACTIVEAREA 50829 /* &active (non-masked) pixels + of the sensor */ +#define TIFFTAG_MASKEDAREAS 50830 /* &list of coordinates + of fully masked pixels */ +#define TIFFTAG_ASSHOTICCPROFILE 50831 /* &these two tags used to */ +#define TIFFTAG_ASSHOTPREPROFILEMATRIX 50832 /* map cameras's color space + into ICC profile space */ +#define TIFFTAG_CURRENTICCPROFILE 50833 /* & */ +#define TIFFTAG_CURRENTPREPROFILEMATRIX 50834 /* & */ +/* tag 65535 is an undefined tag used by Eastman Kodak */ +#define TIFFTAG_DCSHUESHIFTVALUES 65535 /* hue shift correction data */ + +/* + * The following are ``pseudo tags'' that can be used to control + * codec-specific functionality. These tags are not written to file. + * Note that these values start at 0xffff+1 so that they'll never + * collide with Aldus-assigned tags. + * + * If you want your private pseudo tags ``registered'' (i.e. added to + * this file), please post a bug report via the tracking system at + * http://www.remotesensing.org/libtiff/bugs.html with the appropriate + * C definitions to add. + */ +#define TIFFTAG_FAXMODE 65536 /* Group 3/4 format control */ +#define FAXMODE_CLASSIC 0x0000 /* default, include RTC */ +#define FAXMODE_NORTC 0x0001 /* no RTC at end of data */ +#define FAXMODE_NOEOL 0x0002 /* no EOL code at end of row */ +#define FAXMODE_BYTEALIGN 0x0004 /* byte align row */ +#define FAXMODE_WORDALIGN 0x0008 /* word align row */ +#define FAXMODE_CLASSF FAXMODE_NORTC /* TIFF Class F */ +#define TIFFTAG_JPEGQUALITY 65537 /* Compression quality level */ +/* Note: quality level is on the IJG 0-100 scale. Default value is 75 */ +#define TIFFTAG_JPEGCOLORMODE 65538 /* Auto RGB<=>YCbCr convert? */ +#define JPEGCOLORMODE_RAW 0x0000 /* no conversion (default) */ +#define JPEGCOLORMODE_RGB 0x0001 /* do auto conversion */ +#define TIFFTAG_JPEGTABLESMODE 65539 /* What to put in JPEGTables */ +#define JPEGTABLESMODE_QUANT 0x0001 /* include quantization tbls */ +#define JPEGTABLESMODE_HUFF 0x0002 /* include Huffman tbls */ +/* Note: default is JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF */ +#define TIFFTAG_FAXFILLFUNC 65540 /* G3/G4 fill function */ +#define TIFFTAG_PIXARLOGDATAFMT 65549 /* PixarLogCodec I/O data sz */ +#define PIXARLOGDATAFMT_8BIT 0 /* regular u_char samples */ +#define PIXARLOGDATAFMT_8BITABGR 1 /* ABGR-order u_chars */ +#define PIXARLOGDATAFMT_11BITLOG 2 /* 11-bit log-encoded (raw) */ +#define PIXARLOGDATAFMT_12BITPICIO 3 /* as per PICIO (1.0==2048) */ +#define PIXARLOGDATAFMT_16BIT 4 /* signed short samples */ +#define PIXARLOGDATAFMT_FLOAT 5 /* IEEE float samples */ +/* 65550-65556 are allocated to Oceana Matrix */ +#define TIFFTAG_DCSIMAGERTYPE 65550 /* imager model & filter */ +#define DCSIMAGERMODEL_M3 0 /* M3 chip (1280 x 1024) */ +#define DCSIMAGERMODEL_M5 1 /* M5 chip (1536 x 1024) */ +#define DCSIMAGERMODEL_M6 2 /* M6 chip (3072 x 2048) */ +#define DCSIMAGERFILTER_IR 0 /* infrared filter */ +#define DCSIMAGERFILTER_MONO 1 /* monochrome filter */ +#define DCSIMAGERFILTER_CFA 2 /* color filter array */ +#define DCSIMAGERFILTER_OTHER 3 /* other filter */ +#define TIFFTAG_DCSINTERPMODE 65551 /* interpolation mode */ +#define DCSINTERPMODE_NORMAL 0x0 /* whole image, default */ +#define DCSINTERPMODE_PREVIEW 0x1 /* preview of image (384x256) */ +#define TIFFTAG_DCSBALANCEARRAY 65552 /* color balance values */ +#define TIFFTAG_DCSCORRECTMATRIX 65553 /* color correction values */ +#define TIFFTAG_DCSGAMMA 65554 /* gamma value */ +#define TIFFTAG_DCSTOESHOULDERPTS 65555 /* toe & shoulder points */ +#define TIFFTAG_DCSCALIBRATIONFD 65556 /* calibration file desc */ +/* Note: quality level is on the ZLIB 1-9 scale. Default value is -1 */ +#define TIFFTAG_ZIPQUALITY 65557 /* compression quality level */ +#define TIFFTAG_PIXARLOGQUALITY 65558 /* PixarLog uses same scale */ +/* 65559 is allocated to Oceana Matrix */ +#define TIFFTAG_DCSCLIPRECTANGLE 65559 /* area of image to acquire */ +#define TIFFTAG_SGILOGDATAFMT 65560 /* SGILog user data format */ +#define SGILOGDATAFMT_FLOAT 0 /* IEEE float samples */ +#define SGILOGDATAFMT_16BIT 1 /* 16-bit samples */ +#define SGILOGDATAFMT_RAW 2 /* uninterpreted data */ +#define SGILOGDATAFMT_8BIT 3 /* 8-bit RGB monitor values */ +#define TIFFTAG_SGILOGENCODE 65561 /* SGILog data encoding control*/ +#define SGILOGENCODE_NODITHER 0 /* do not dither encoded values*/ +#define SGILOGENCODE_RANDITHER 1 /* randomly dither encd values */ +#define TIFFTAG_LZMAPRESET 65562 /* LZMA2 preset (compression level) */ +#define TIFFTAG_PERSAMPLE 65563 /* interface for per sample tags */ +#define PERSAMPLE_MERGED 0 /* present as a single value */ +#define PERSAMPLE_MULTI 1 /* present as multiple values */ + +/* + * EXIF tags + */ +#define EXIFTAG_EXPOSURETIME 33434 /* Exposure time */ +#define EXIFTAG_FNUMBER 33437 /* F number */ +#define EXIFTAG_EXPOSUREPROGRAM 34850 /* Exposure program */ +#define EXIFTAG_SPECTRALSENSITIVITY 34852 /* Spectral sensitivity */ +#define EXIFTAG_ISOSPEEDRATINGS 34855 /* ISO speed rating */ +#define EXIFTAG_OECF 34856 /* Optoelectric conversion + factor */ +#define EXIFTAG_EXIFVERSION 36864 /* Exif version */ +#define EXIFTAG_DATETIMEORIGINAL 36867 /* Date and time of original + data generation */ +#define EXIFTAG_DATETIMEDIGITIZED 36868 /* Date and time of digital + data generation */ +#define EXIFTAG_COMPONENTSCONFIGURATION 37121 /* Meaning of each component */ +#define EXIFTAG_COMPRESSEDBITSPERPIXEL 37122 /* Image compression mode */ +#define EXIFTAG_SHUTTERSPEEDVALUE 37377 /* Shutter speed */ +#define EXIFTAG_APERTUREVALUE 37378 /* Aperture */ +#define EXIFTAG_BRIGHTNESSVALUE 37379 /* Brightness */ +#define EXIFTAG_EXPOSUREBIASVALUE 37380 /* Exposure bias */ +#define EXIFTAG_MAXAPERTUREVALUE 37381 /* Maximum lens aperture */ +#define EXIFTAG_SUBJECTDISTANCE 37382 /* Subject distance */ +#define EXIFTAG_METERINGMODE 37383 /* Metering mode */ +#define EXIFTAG_LIGHTSOURCE 37384 /* Light source */ +#define EXIFTAG_FLASH 37385 /* Flash */ +#define EXIFTAG_FOCALLENGTH 37386 /* Lens focal length */ +#define EXIFTAG_SUBJECTAREA 37396 /* Subject area */ +#define EXIFTAG_MAKERNOTE 37500 /* Manufacturer notes */ +#define EXIFTAG_USERCOMMENT 37510 /* User comments */ +#define EXIFTAG_SUBSECTIME 37520 /* DateTime subseconds */ +#define EXIFTAG_SUBSECTIMEORIGINAL 37521 /* DateTimeOriginal subseconds */ +#define EXIFTAG_SUBSECTIMEDIGITIZED 37522 /* DateTimeDigitized subseconds */ +#define EXIFTAG_FLASHPIXVERSION 40960 /* Supported Flashpix version */ +#define EXIFTAG_COLORSPACE 40961 /* Color space information */ +#define EXIFTAG_PIXELXDIMENSION 40962 /* Valid image width */ +#define EXIFTAG_PIXELYDIMENSION 40963 /* Valid image height */ +#define EXIFTAG_RELATEDSOUNDFILE 40964 /* Related audio file */ +#define EXIFTAG_FLASHENERGY 41483 /* Flash energy */ +#define EXIFTAG_SPATIALFREQUENCYRESPONSE 41484 /* Spatial frequency response */ +#define EXIFTAG_FOCALPLANEXRESOLUTION 41486 /* Focal plane X resolution */ +#define EXIFTAG_FOCALPLANEYRESOLUTION 41487 /* Focal plane Y resolution */ +#define EXIFTAG_FOCALPLANERESOLUTIONUNIT 41488 /* Focal plane resolution unit */ +#define EXIFTAG_SUBJECTLOCATION 41492 /* Subject location */ +#define EXIFTAG_EXPOSUREINDEX 41493 /* Exposure index */ +#define EXIFTAG_SENSINGMETHOD 41495 /* Sensing method */ +#define EXIFTAG_FILESOURCE 41728 /* File source */ +#define EXIFTAG_SCENETYPE 41729 /* Scene type */ +#define EXIFTAG_CFAPATTERN 41730 /* CFA pattern */ +#define EXIFTAG_CUSTOMRENDERED 41985 /* Custom image processing */ +#define EXIFTAG_EXPOSUREMODE 41986 /* Exposure mode */ +#define EXIFTAG_WHITEBALANCE 41987 /* White balance */ +#define EXIFTAG_DIGITALZOOMRATIO 41988 /* Digital zoom ratio */ +#define EXIFTAG_FOCALLENGTHIN35MMFILM 41989 /* Focal length in 35 mm film */ +#define EXIFTAG_SCENECAPTURETYPE 41990 /* Scene capture type */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_CONTRAST 41992 /* Contrast */ +#define EXIFTAG_SATURATION 41993 /* Saturation */ +#define EXIFTAG_SHARPNESS 41994 /* Sharpness */ +#define EXIFTAG_DEVICESETTINGDESCRIPTION 41995 /* Device settings description */ +#define EXIFTAG_SUBJECTDISTANCERANGE 41996 /* Subject distance range */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_IMAGEUNIQUEID 42016 /* Unique image ID */ + +#endif /* _TIFF_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tiffconf.h b/core/src/fxcodec/fx_tiff/tiff_v403/tiffconf.h new file mode 100644 index 0000000000..3ca425c712 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tiffconf.h @@ -0,0 +1,250 @@ +/* libtiff/tiffconf.h. Generated by configure. */ +/* + Configuration defines for installed libtiff. + This file maintained for backward compatibility. Do not use definitions + from this file in your programs. +*/ +#ifndef _TIFFCONF_ +#define _TIFFCONF_ + +#ifndef _FX_SYSTEM_H_ +# include "../../../../include/fxcrt/fx_system.h" +#endif + +//NOTE: The tiff codec requires an ANSI C compiler environment for building and +// presumes an ANSI C environment for use. + +/* Define to 1 if you have the header file. */ +/* Define to 1 if you have the header file. */ +#if _FX_OS_ == _FX_WIN32_MOBILE_ +# define O_RDONLY 0x0000 /* open for reading only */ +# define O_WRONLY 0x0001 /* open for writing only */ +# define O_RDWR 0x0002 /* open for reading and writing */ +# define O_CREAT 0x0100 /* create and open file */ +# define O_TRUNC 0x0200 /* open and truncate */ +#else +# define HAVE_SYS_TYPES_H 1 +# define HAVE_FCNTL_H 1 +#endif + +/* Compatibility stuff. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define as 0 or 1 according to the floating point format suported by the + machine */ +#define HAVE_IEEEFP 1 + +/* Define to 1 if you have the header file. */ +//#define HAVE_STRING_H 1 +//fx_system.h already include the string.h in ANSIC + +/* Define to 1 if you have the header file. */ +/*#define HAVE_SEARCH_H 1 */ + +/* The size of a `int', as computed by sizeof. */ +/* According typedef int FX_INT32; in the fx_system.h*/ +#define SIZEOF_INT 4 + +/* Sunliang.Liu 20110325. We should config the correct long size for tif + fax4decode optimize in tif_fax3.c -- Linux64 decode issue. + TESTDOC: Bug #23661 - z1.tif. */ +#if _FX_CPU_ == _FX_WIN64_ || _FX_CPU_ == _FX_X64_ || _FX_CPU_ == _FX_IA64_ +/* The size of `unsigned long', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_LONG 8 +#else +#define SIZEOF_UNSIGNED_LONG 4 +#endif + +/* Signed 8-bit type */ +#define TIFF_INT8_T signed char + +/* Unsigned 8-bit type */ +#define TIFF_UINT8_T unsigned char + +/* Signed 16-bit type */ +#define TIFF_INT16_T signed short + +/* Unsigned 16-bit type */ +#define TIFF_UINT16_T unsigned short + +/* Signed 32-bit type */ +#define TIFF_INT32_T signed int + +/* Unsigned 32-bit type */ +#define TIFF_UINT32_T unsigned int + +/* Signed 32-bit type formatter */ +#define TIFF_INT32_FORMAT "%d" + +/* Unsigned 32-bit type formatter */ +#define TIFF_UINT32_FORMAT "%u" + +#ifdef _MSC_VER // windows + +/* Signed 64-bit type formatter */ +#define TIFF_INT64_FORMAT "%I64d" + +/* Unsigned 64-bit type formatter */ +#define TIFF_UINT64_FORMAT "%I64u" + +/* Signed 64-bit type */ +#define TIFF_INT64_T signed __int64 + +/* Unsigned 64-bit type */ +#define TIFF_UINT64_T unsigned __int64 + +#else // linux/unix + +#if 0 //_FX_CPU_ == _FX_X64_ // linux/unix 64 + +/* Signed 64-bit type formatter */ +#define TIFF_INT64_FORMAT "%ld" + +/* Unsigned 64-bit type formatter */ +#define TIFF_UINT64_FORMAT "%lu" + +/* Signed 64-bit type */ +#define TIFF_INT64_T signed long + +#else // linux/unix 32 + +/* Signed 64-bit type formatter */ +#define TIFF_INT64_FORMAT "%lld" + +/* Unsigned 64-bit type formatter */ +#define TIFF_UINT64_FORMAT "%llu" + +/* Signed 64-bit type */ +#define TIFF_INT64_T signed long long + +#endif // end _FX_CPU_ + +/* Unsigned 64-bit type */ +#define TIFF_UINT64_T unsigned long long + +#endif + + +/* Signed size type */ +#ifdef _MSC_VER + +#if defined(_WIN64) +#define TIFF_SSIZE_T signed __int64 +#else +#define TIFF_SSIZE_T signed int +#endif + +#else + +#define TIFF_SSIZE_T signed long + +#endif + +/* Signed size type formatter */ +#if defined(_WIN64) +#define TIFF_SSIZE_FORMAT "%I64d" +#else +#define TIFF_SSIZE_FORMAT "%ld" +#endif + +/* Pointer difference type */ +#ifdef _MSC_VER +#define TIFF_PTRDIFF_T long +#else +#define TIFF_PTRDIFF_T ptrdiff_t +#endif + +/* Signed 64-bit type */ +/*#define TIFF_INT64_T signed __int64*/ + +/* Unsigned 64-bit type */ +/*#define TIFF_UINT64_T unsigned __int64*/ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +# ifndef inline +# define inline __inline +# endif +#endif + +#define lfind _lfind + +#define BSDTYPES + +/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */ +#define HOST_FILLORDER FILLORDER_LSB2MSB + +/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian + (Intel) */ +#if _FX_ENDIAN_ == _FX_BIG_ENDIAN_ +# define HOST_BIGENDIAN 1 +#else +# define HOST_BIGENDIAN 0 +#endif + +/* Support CCITT Group 3 & 4 algorithms */ +#define CCITT_SUPPORT 1 + +/* Support JPEG compression (requires IJG JPEG library) */ +#define JPEG_SUPPORT 1 + +/* Support LogLuv high dynamic range encoding */ +#define LOGLUV_SUPPORT 1 + +/* Support LZW algorithm */ +#define LZW_SUPPORT 1 + +/* Support NeXT 2-bit RLE algorithm */ +#define NEXT_SUPPORT 1 + +/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation + fails with unpatched IJG JPEG library) */ +#define OJPEG_SUPPORT 1 + +/* Support Macintosh PackBits algorithm */ +#define PACKBITS_SUPPORT 1 + +/* Support Pixar log-format algorithm (requires Zlib) */ +#define PIXARLOG_SUPPORT 1 + +/* Support ThunderScan 4-bit RLE algorithm */ +#define THUNDER_SUPPORT 1 + +/* Support Deflate compression */ +#define ZIP_SUPPORT 1 + +/* Support strip chopping (whether or not to convert single-strip uncompressed + images to mutiple strips of ~8Kb to reduce memory usage) */ +#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP + +/* Enable SubIFD tag (330) support */ +#define SUBIFD_SUPPORT 1 + +/* Treat extra sample as alpha (default enabled). The RGBA interface will + treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many + packages produce RGBA files but don't mark the alpha properly. */ +#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1 + +/* Pick up YCbCr subsampling info from the JPEG data stream to support files + lacking the tag (default enabled). */ +#define CHECK_JPEG_YCBCR_SUBSAMPLING 1 + +/* Support MS MDI magic number files as TIFF */ +#define MDI_SUPPORT 1 + +/* + * Feature support definitions. + * XXX: These macros are obsoleted. Don't use them in your apps! + * Macros stays here for backward compatibility and should be always defined. + */ +#define COLORIMETRY_SUPPORT +#define YCBCR_SUPPORT +#define CMYK_SUPPORT +#define ICC_SUPPORT +#define PHOTOSHOP_SUPPORT +#define IPTC_SUPPORT + +#endif /* _TIFFCONF_ */ diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tiffio.h b/core/src/fxcodec/fx_tiff/tiff_v403/tiffio.h new file mode 100644 index 0000000000..4c749edc9e --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tiffio.h @@ -0,0 +1,559 @@ +/* $Id: tiffio.h,v 1.91 2012-07-29 15:45:29 tgl Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIO_ +#define _TIFFIO_ + +/* + * TIFF I/O Library Definitions. + */ +#include "tiff.h" +#include "tiffvers.h" + +/* + * TIFF is defined as an incomplete type to hide the + * library's internal data structures from clients. + */ +typedef struct tiff TIFF; + +/* + * The following typedefs define the intrinsic size of + * data types used in the *exported* interfaces. These + * definitions depend on the proper definition of types + * in tiff.h. Note also that the varargs interface used + * to pass tag types and values uses the types defined in + * tiff.h directly. + * + * NB: ttag_t is unsigned int and not unsigned short because + * ANSI C requires that the type before the ellipsis be a + * promoted type (i.e. one of int, unsigned int, pointer, + * or double) and because we defined pseudo-tags that are + * outside the range of legal Aldus-assigned tags. + * NB: tsize_t is int32 and not uint32 because some functions + * return -1. + * NB: toff_t is not off_t for many reasons; TIFFs max out at + * 32-bit file offsets, and BigTIFF maxes out at 64-bit + * offsets being the most important, and to ensure use of + * a consistently unsigned type across architectures. + * Prior to libtiff 4.0, this was an unsigned 32 bit type. + */ +/* + * this is the machine addressing size type, only it's signed, so make it + * int32 on 32bit machines, int64 on 64bit machines + */ +typedef TIFF_SSIZE_T tmsize_t; +typedef uint64 toff_t; /* file offset */ +/* the following are deprecated and should be replaced by their defining + counterparts */ +typedef uint32 ttag_t; /* directory tag */ +typedef uint16 tdir_t; /* directory index */ +typedef uint16 tsample_t; /* sample number */ +typedef uint32 tstrile_t; /* strip or tile number */ +typedef tstrile_t tstrip_t; /* strip number */ +typedef tstrile_t ttile_t; /* tile number */ +typedef tmsize_t tsize_t; /* i/o size in bytes */ +typedef void* tdata_t; /* image data ref */ + +#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32)) +#define __WIN32__ +#endif + +/* + * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c + * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c). + * + * By default tif_unix.c is assumed. + */ + +#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows) +# if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && !defined(USE_WIN32_FILEIO) +# define AVOID_WIN32_FILEIO +# endif +#endif + +#if defined(USE_WIN32_FILEIO) +# define VC_EXTRALEAN +# include +# ifdef __WIN32__ +DECLARE_HANDLE(thandle_t); /* Win32 file handle */ +# else +typedef HFILE thandle_t; /* client data handle */ +# endif /* __WIN32__ */ +#else +typedef void* thandle_t; /* client data handle */ +#endif /* USE_WIN32_FILEIO */ + +/* + * Flags to pass to TIFFPrintDirectory to control + * printing of data structures that are potentially + * very large. Bit-or these flags to enable printing + * multiple items. + */ +#define TIFFPRINT_NONE 0x0 /* no extra info */ +#define TIFFPRINT_STRIPS 0x1 /* strips/tiles info */ +#define TIFFPRINT_CURVES 0x2 /* color/gray response curves */ +#define TIFFPRINT_COLORMAP 0x4 /* colormap */ +#define TIFFPRINT_JPEGQTABLES 0x100 /* JPEG Q matrices */ +#define TIFFPRINT_JPEGACTABLES 0x200 /* JPEG AC tables */ +#define TIFFPRINT_JPEGDCTABLES 0x200 /* JPEG DC tables */ + +/* + * Colour conversion stuff + */ + +/* reference white */ +#define D65_X0 (95.0470F) +#define D65_Y0 (100.0F) +#define D65_Z0 (108.8827F) + +#define D50_X0 (96.4250F) +#define D50_Y0 (100.0F) +#define D50_Z0 (82.4680F) + +/* Structure for holding information about a display device. */ + +typedef unsigned char TIFFRGBValue; /* 8-bit samples */ + +typedef struct { + float d_mat[3][3]; /* XYZ -> luminance matrix */ + float d_YCR; /* Light o/p for reference white */ + float d_YCG; + float d_YCB; + uint32 d_Vrwr; /* Pixel values for ref. white */ + uint32 d_Vrwg; + uint32 d_Vrwb; + float d_Y0R; /* Residual light for black pixel */ + float d_Y0G; + float d_Y0B; + float d_gammaR; /* Gamma values for the three guns */ + float d_gammaG; + float d_gammaB; +} TIFFDisplay; + +typedef struct { /* YCbCr->RGB support */ + TIFFRGBValue* clamptab; /* range clamping table */ + int* Cr_r_tab; + int* Cb_b_tab; + int32* Cr_g_tab; + int32* Cb_g_tab; + int32* Y_tab; +} TIFFYCbCrToRGB; + +typedef struct { /* CIE Lab 1976->RGB support */ + int range; /* Size of conversion table */ +#define CIELABTORGB_TABLE_RANGE 1500 + float rstep, gstep, bstep; + float X0, Y0, Z0; /* Reference white point */ + TIFFDisplay display; + float Yr2r[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yr to r */ + float Yg2g[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yg to g */ + float Yb2b[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yb to b */ +} TIFFCIELabToRGB; + +/* + * RGBA-style image support. + */ +typedef struct _TIFFRGBAImage TIFFRGBAImage; +/* + * The image reading and conversion routines invoke + * ``put routines'' to copy/image/whatever tiles of + * raw image data. A default set of routines are + * provided to convert/copy raw image data to 8-bit + * packed ABGR format rasters. Applications can supply + * alternate routines that unpack the data into a + * different format or, for example, unpack the data + * and draw the unpacked raster on the display. + */ +typedef void (*tileContigRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*); +typedef void (*tileSeparateRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*, unsigned char*, unsigned char*, unsigned char*); +/* + * RGBA-reader state. + */ +struct _TIFFRGBAImage { + TIFF* tif; /* image handle */ + int stoponerr; /* stop on read error */ + int isContig; /* data is packed/separate */ + int alpha; /* type of alpha data present */ + uint32 width; /* image width */ + uint32 height; /* image height */ + uint16 bitspersample; /* image bits/sample */ + uint16 samplesperpixel; /* image samples/pixel */ + uint16 orientation; /* image orientation */ + uint16 req_orientation; /* requested orientation */ + uint16 photometric; /* image photometric interp */ + uint16* redcmap; /* colormap pallete */ + uint16* greencmap; + uint16* bluecmap; + /* get image data routine */ + int (*get)(TIFFRGBAImage*, uint32*, uint32, uint32); + /* put decoded strip/tile */ + union { + void (*any)(TIFFRGBAImage*); + tileContigRoutine contig; + tileSeparateRoutine separate; + } put; + TIFFRGBValue* Map; /* sample mapping array */ + uint32** BWmap; /* black&white map */ + uint32** PALmap; /* palette image map */ + TIFFYCbCrToRGB* ycbcr; /* YCbCr conversion state */ + TIFFCIELabToRGB* cielab; /* CIE L*a*b conversion state */ + + uint8* UaToAa; /* Unassociated alpha to associated alpha convertion LUT */ + uint8* Bitdepth16To8; /* LUT for conversion from 16bit to 8bit values */ + + int row_offset; + int col_offset; +}; + +/* + * Macros for extracting components from the + * packed ABGR form returned by TIFFReadRGBAImage. + */ +#define TIFFGetR(abgr) ((abgr) & 0xff) +#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff) +#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff) +#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff) + +/* + * A CODEC is a software package that implements decoding, + * encoding, or decoding+encoding of a compression algorithm. + * The library provides a collection of builtin codecs. + * More codecs may be registered through calls to the library + * and/or the builtin implementations may be overridden. + */ +typedef int (*TIFFInitMethod)(TIFF*, int); +typedef struct { + char* name; + uint16 scheme; + TIFFInitMethod init; +} TIFFCodec; + +#include +#include + +/* share internal LogLuv conversion routines? */ +#ifndef LOGLUV_PUBLIC +#define LOGLUV_PUBLIC 1 +#endif + +#if !defined(__GNUC__) && !defined(__attribute__) +# define __attribute__(x) /*nothing*/ +#endif + +#if defined(c_plusplus) || defined(__cplusplus) +extern "C" { +#endif +typedef void (*TIFFErrorHandler)(const char*, const char*, va_list); +typedef void (*TIFFErrorHandlerExt)(thandle_t, const char*, const char*, va_list); +typedef tmsize_t (*TIFFReadWriteProc)(thandle_t, void*, tmsize_t); +typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int); +typedef int (*TIFFCloseProc)(thandle_t); +typedef toff_t (*TIFFSizeProc)(thandle_t); +typedef int (*TIFFMapFileProc)(thandle_t, void** base, toff_t* size); +typedef void (*TIFFUnmapFileProc)(thandle_t, void* base, toff_t size); +typedef void (*TIFFExtendProc)(TIFF*); + +extern const char* TIFFGetVersion(void); + +extern const TIFFCodec* TIFFFindCODEC(uint16); +extern TIFFCodec* TIFFRegisterCODEC(uint16, const char*, TIFFInitMethod); +extern void TIFFUnRegisterCODEC(TIFFCodec*); +extern int TIFFIsCODECConfigured(uint16); +extern TIFFCodec* TIFFGetConfiguredCODECs(void); + +/* + * Auxiliary functions. + */ + +extern void* _TIFFmalloc(tmsize_t s); +extern void* _TIFFrealloc(void* p, tmsize_t s); +extern void _TIFFmemset(void* p, int v, tmsize_t c); +extern void _TIFFmemcpy(void* d, const void* s, tmsize_t c); +extern int _TIFFmemcmp(const void* p1, const void* p2, tmsize_t c); +extern void _TIFFfree(void* p); +/* Do cmyk to rgb convert, add by Sunliang.Liu 20090723. */ +extern int TIFFCmyk2Rgb(thandle_t context, uint8 c, uint8 m, uint8 y, uint8 k, uint8* r, uint8* g, uint8* b); + +/* +** Stuff, related to tag handling and creating custom tags. +*/ +extern int TIFFGetTagListCount( TIFF * ); +extern uint32 TIFFGetTagListEntry( TIFF *, int tag_index ); + +#define TIFF_ANY TIFF_NOTYPE /* for field descriptor searching */ +#define TIFF_VARIABLE -1 /* marker for variable length tags */ +#define TIFF_SPP -2 /* marker for SamplesPerPixel tags */ +#define TIFF_VARIABLE2 -3 /* marker for uint32 var-length tags */ + +#define FIELD_CUSTOM 65 + +typedef struct _TIFFField TIFFField; +typedef struct _TIFFFieldArray TIFFFieldArray; + +extern const TIFFField* TIFFFindField(TIFF *, uint32, TIFFDataType); +extern const TIFFField* TIFFFieldWithTag(TIFF*, uint32); +extern const TIFFField* TIFFFieldWithName(TIFF*, const char *); + +extern uint32 TIFFFieldTag(const TIFFField*); +extern const char* TIFFFieldName(const TIFFField*); +extern TIFFDataType TIFFFieldDataType(const TIFFField*); +extern int TIFFFieldPassCount(const TIFFField*); +extern int TIFFFieldReadCount(const TIFFField*); +extern int TIFFFieldWriteCount(const TIFFField*); + +typedef int (*TIFFVSetMethod)(TIFF*, uint32, va_list); +typedef int (*TIFFVGetMethod)(TIFF*, uint32, va_list); +typedef void (*TIFFPrintMethod)(TIFF*, FILE*, long); + +typedef struct { + TIFFVSetMethod vsetfield; /* tag set routine */ + TIFFVGetMethod vgetfield; /* tag get routine */ + TIFFPrintMethod printdir; /* directory print routine */ +} TIFFTagMethods; + +extern TIFFTagMethods *TIFFAccessTagMethods(TIFF *); +extern void *TIFFGetClientInfo(TIFF *, const char *); +extern void TIFFSetClientInfo(TIFF *, void *, const char *); + +extern void TIFFCleanup(TIFF* tif); +extern void TIFFClose(TIFF* tif); +extern int TIFFFlush(TIFF* tif); +extern int TIFFFlushData(TIFF* tif); +extern int TIFFGetField(TIFF* tif, uint32 tag, ...); +extern int TIFFVGetField(TIFF* tif, uint32 tag, va_list ap); +extern int TIFFGetFieldDefaulted(TIFF* tif, uint32 tag, ...); +extern int TIFFVGetFieldDefaulted(TIFF* tif, uint32 tag, va_list ap); +extern int TIFFReadDirectory(TIFF* tif); +extern int TIFFReadCustomDirectory(TIFF* tif, toff_t diroff, const TIFFFieldArray* infoarray); +extern int TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff); +extern uint64 TIFFScanlineSize64(TIFF* tif); +extern tmsize_t TIFFScanlineSize(TIFF* tif); +extern uint64 TIFFRasterScanlineSize64(TIFF* tif); +extern tmsize_t TIFFRasterScanlineSize(TIFF* tif); +extern uint64 TIFFStripSize64(TIFF* tif); +extern tmsize_t TIFFStripSize(TIFF* tif); +extern uint64 TIFFRawStripSize64(TIFF* tif, uint32 strip); +extern tmsize_t TIFFRawStripSize(TIFF* tif, uint32 strip); +extern uint64 TIFFVStripSize64(TIFF* tif, uint32 nrows); +extern tmsize_t TIFFVStripSize(TIFF* tif, uint32 nrows); +extern uint64 TIFFTileRowSize64(TIFF* tif); +extern tmsize_t TIFFTileRowSize(TIFF* tif); +extern uint64 TIFFTileSize64(TIFF* tif); +extern tmsize_t TIFFTileSize(TIFF* tif); +extern uint64 TIFFVTileSize64(TIFF* tif, uint32 nrows); +extern tmsize_t TIFFVTileSize(TIFF* tif, uint32 nrows); +extern uint32 TIFFDefaultStripSize(TIFF* tif, uint32 request); +extern void TIFFDefaultTileSize(TIFF*, uint32*, uint32*); +extern int TIFFFileno(TIFF*); +extern int TIFFSetFileno(TIFF*, int); +extern thandle_t TIFFClientdata(TIFF*); +extern thandle_t TIFFSetClientdata(TIFF*, thandle_t); +extern int TIFFGetMode(TIFF*); +extern int TIFFSetMode(TIFF*, int); +extern int TIFFIsTiled(TIFF*); +extern int TIFFIsByteSwapped(TIFF*); +extern int TIFFIsUpSampled(TIFF*); +extern int TIFFIsMSB2LSB(TIFF*); +extern int TIFFIsBigEndian(TIFF*); +extern TIFFReadWriteProc TIFFGetReadProc(TIFF*); +extern TIFFReadWriteProc TIFFGetWriteProc(TIFF*); +extern TIFFSeekProc TIFFGetSeekProc(TIFF*); +extern TIFFCloseProc TIFFGetCloseProc(TIFF*); +extern TIFFSizeProc TIFFGetSizeProc(TIFF*); +extern TIFFMapFileProc TIFFGetMapFileProc(TIFF*); +extern TIFFUnmapFileProc TIFFGetUnmapFileProc(TIFF*); +extern uint32 TIFFCurrentRow(TIFF*); +extern uint16 TIFFCurrentDirectory(TIFF*); +extern uint16 TIFFNumberOfDirectories(TIFF*); +extern uint64 TIFFCurrentDirOffset(TIFF*); +extern uint32 TIFFCurrentStrip(TIFF*); +extern uint32 TIFFCurrentTile(TIFF* tif); +extern int TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size); +extern int TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size); +extern int TIFFSetupStrips(TIFF *); +extern int TIFFWriteCheck(TIFF*, int, const char *); +extern void TIFFFreeDirectory(TIFF*); +extern int TIFFCreateDirectory(TIFF*); +extern int TIFFCreateCustomDirectory(TIFF*,const TIFFFieldArray*); +extern int TIFFCreateEXIFDirectory(TIFF*); +extern int TIFFLastDirectory(TIFF*); +extern int TIFFSetDirectory(TIFF*, uint16); +extern int TIFFSetSubDirectory(TIFF*, uint64); +extern int TIFFUnlinkDirectory(TIFF*, uint16); +extern int TIFFSetField(TIFF*, uint32, ...); +extern int TIFFVSetField(TIFF*, uint32, va_list); +extern int TIFFUnsetField(TIFF*, uint32); +extern int TIFFWriteDirectory(TIFF *); +extern int TIFFWriteCustomDirectory(TIFF *, uint64 *); +extern int TIFFCheckpointDirectory(TIFF *); +extern int TIFFRewriteDirectory(TIFF *); + +#if defined(c_plusplus) || defined(__cplusplus) +extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0); +extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0); +extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int = 0); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, + int = ORIENTATION_BOTLEFT, int = 0); +#else +extern void TIFFPrintDirectory(TIFF*, FILE*, long); +extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample); +extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, int, int); +#endif + +extern int TIFFReadRGBAStrip(TIFF*, uint32, uint32 * ); +extern int TIFFReadRGBATile(TIFF*, uint32, uint32, uint32 * ); +extern int TIFFRGBAImageOK(TIFF*, char [1024]); +extern int TIFFRGBAImageBegin(TIFFRGBAImage*, TIFF*, int, char [1024]); +extern int TIFFRGBAImageGet(TIFFRGBAImage*, uint32*, uint32, uint32); +extern void TIFFRGBAImageEnd(TIFFRGBAImage*); +extern TIFF* TIFFOpen(const char*, const char*); +# ifdef __WIN32__ +extern TIFF* TIFFOpenW(const wchar_t*, const char*); +# endif /* __WIN32__ */ +extern TIFF* TIFFFdOpen(int, const char*, const char*); +extern TIFF* TIFFClientOpen(const char*, const char*, + thandle_t, + TIFFReadWriteProc, TIFFReadWriteProc, + TIFFSeekProc, TIFFCloseProc, + TIFFSizeProc, + TIFFMapFileProc, TIFFUnmapFileProc); +extern const char* TIFFFileName(TIFF*); +extern const char* TIFFSetFileName(TIFF*, const char *); +extern void TIFFError(const char*, const char*, ...) __attribute__((__format__ (__printf__,2,3))); +extern void TIFFErrorExt(thandle_t, const char*, const char*, ...) __attribute__((__format__ (__printf__,3,4))); +extern void TIFFWarning(const char*, const char*, ...) __attribute__((__format__ (__printf__,2,3))); +extern void TIFFWarningExt(thandle_t, const char*, const char*, ...) __attribute__((__format__ (__printf__,3,4))); +extern TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetErrorHandlerExt(TIFFErrorHandlerExt); +extern TIFFErrorHandler TIFFSetWarningHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetWarningHandlerExt(TIFFErrorHandlerExt); +extern TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc); +extern uint32 TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s); +extern int TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s); +extern uint32 TIFFNumberOfTiles(TIFF*); +extern tmsize_t TIFFReadTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s); +extern tmsize_t TIFFWriteTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s); +extern uint32 TIFFComputeStrip(TIFF*, uint32, uint16); +extern uint32 TIFFNumberOfStrips(TIFF*); +extern tmsize_t TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size); +extern tmsize_t TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size); +extern tmsize_t TIFFReadEncodedTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size); +extern tmsize_t TIFFReadRawTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size); +extern tmsize_t TIFFWriteEncodedStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteRawStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteEncodedTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteRawTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc); +extern int TIFFDataWidth(TIFFDataType); /* table of tag datatype widths */ +extern void TIFFSetWriteOffset(TIFF* tif, toff_t off); +extern void TIFFSwabShort(uint16*); +extern void TIFFSwabLong(uint32*); +extern void TIFFSwabLong8(uint64*); +extern void TIFFSwabFloat(float*); +extern void TIFFSwabDouble(double*); +extern void TIFFSwabArrayOfShort(uint16* wp, tmsize_t n); +extern void TIFFSwabArrayOfTriples(uint8* tp, tmsize_t n); +extern void TIFFSwabArrayOfLong(uint32* lp, tmsize_t n); +extern void TIFFSwabArrayOfLong8(uint64* lp, tmsize_t n); +extern void TIFFSwabArrayOfFloat(float* fp, tmsize_t n); +extern void TIFFSwabArrayOfDouble(double* dp, tmsize_t n); +extern void TIFFReverseBits(uint8* cp, tmsize_t n); +extern const unsigned char* TIFFGetBitRevTable(int); + +#ifdef LOGLUV_PUBLIC +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 +#define UVSCALE 410. +extern double LogL16toY(int); +extern double LogL10toY(int); +extern void XYZtoRGB24(float*, uint8*); +extern int uv_decode(double*, double*, int); +extern void LogLuv24toXYZ(uint32, float*); +extern void LogLuv32toXYZ(uint32, float*); +#if defined(c_plusplus) || defined(__cplusplus) +extern int LogL16fromY(double, int = SGILOGENCODE_NODITHER); +extern int LogL10fromY(double, int = SGILOGENCODE_NODITHER); +extern int uv_encode(double, double, int = SGILOGENCODE_NODITHER); +extern uint32 LogLuv24fromXYZ(float*, int = SGILOGENCODE_NODITHER); +extern uint32 LogLuv32fromXYZ(float*, int = SGILOGENCODE_NODITHER); +#else +extern int LogL16fromY(double, int); +extern int LogL10fromY(double, int); +extern int uv_encode(double, double, int); +extern uint32 LogLuv24fromXYZ(float*, int); +extern uint32 LogLuv32fromXYZ(float*, int); +#endif +#endif /* LOGLUV_PUBLIC */ + +extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB*, const TIFFDisplay *, float*); +extern void TIFFCIELabToXYZ(TIFFCIELabToRGB *, uint32, int32, int32, + float *, float *, float *); +extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float, + uint32 *, uint32 *, uint32 *); + +extern int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB*, float*, float*); +extern void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *, uint32, int32, int32, + uint32 *, uint32 *, uint32 *); + +/**************************************************************************** + * O B S O L E T E D I N T E R F A C E S + * + * Don't use this stuff in your applications, it may be removed in the future + * libtiff versions. + ****************************************************************************/ +typedef struct { + ttag_t field_tag; /* field's tag */ + short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ + short field_writecount; /* write count/TIFF_VARIABLE */ + TIFFDataType field_type; /* type of associated data */ + unsigned short field_bit; /* bit in fieldsset bit vector */ + unsigned char field_oktochange; /* if true, can change while writing */ + unsigned char field_passcount; /* if true, pass dir count on set */ + char *field_name; /* ASCII name */ +} TIFFFieldInfo; + +extern int TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], uint32); + +#if defined(c_plusplus) || defined(__cplusplus) +} +#endif + +#endif /* _TIFFIO_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tiffiop.h b/core/src/fxcodec/fx_tiff/tiff_v403/tiffiop.h new file mode 100644 index 0000000000..c5ddc3c173 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tiffiop.h @@ -0,0 +1,367 @@ +/* $Id: tiffiop.h,v 1.84 2012-05-30 01:50:17 fwarmerdam Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIOP_ +#define _TIFFIOP_ +/* + * ``Library-private'' definitions. + */ + +#include "tiffconf.h" + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_STRING_H +# include +#endif + +#ifdef HAVE_ASSERT_H +# include +#else +# define assert(x) +#endif + +#ifdef HAVE_SEARCH_H +# include +#else +extern void *lfind(const void *, const void *, size_t *, size_t, + int (*)(const void *, const void *)); +#endif + +#include "tiffio.h" + +#include "tif_dir.h" + +#ifndef STRIP_SIZE_DEFAULT +# define STRIP_SIZE_DEFAULT 8192 +#endif + +#define streq(a,b) (strcmp(a,b) == 0) + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +typedef struct client_info { + struct client_info *next; + void *data; + char *name; +} TIFFClientInfoLink; + +/* + * Typedefs for ``method pointers'' used internally. + * these are depriciated and provided only for backwards compatibility + */ +typedef unsigned char tidataval_t; /* internal image data value type */ +typedef tidataval_t* tidata_t; /* reference to internal image data */ + +typedef void (*TIFFVoidMethod)(TIFF*); +typedef int (*TIFFBoolMethod)(TIFF*); +typedef int (*TIFFPreMethod)(TIFF*, uint16); +typedef int (*TIFFCodeMethod)(TIFF* tif, uint8* buf, tmsize_t size, uint16 sample); +typedef int (*TIFFSeekMethod)(TIFF*, uint32); +typedef void (*TIFFPostMethod)(TIFF* tif, uint8* buf, tmsize_t size); +typedef uint32 (*TIFFStripMethod)(TIFF*, uint32); +typedef void (*TIFFTileMethod)(TIFF*, uint32*, uint32*); + +struct tiff { + char* tif_name; /* name of open file */ + int tif_fd; /* open file descriptor */ + int tif_mode; /* open mode (O_*) */ + uint32 tif_flags; + #define TIFF_FILLORDER 0x00003 /* natural bit fill order for machine */ + #define TIFF_DIRTYHEADER 0x00004 /* header must be written on close */ + #define TIFF_DIRTYDIRECT 0x00008 /* current directory must be written */ + #define TIFF_BUFFERSETUP 0x00010 /* data buffers setup */ + #define TIFF_CODERSETUP 0x00020 /* encoder/decoder setup done */ + #define TIFF_BEENWRITING 0x00040 /* written 1+ scanlines to file */ + #define TIFF_SWAB 0x00080 /* byte swap file information */ + #define TIFF_NOBITREV 0x00100 /* inhibit bit reversal logic */ + #define TIFF_MYBUFFER 0x00200 /* my raw data buffer; free on close */ + #define TIFF_ISTILED 0x00400 /* file is tile, not strip- based */ + #define TIFF_MAPPED 0x00800 /* file is mapped into memory */ + #define TIFF_POSTENCODE 0x01000 /* need call to postencode routine */ + #define TIFF_INSUBIFD 0x02000 /* currently writing a subifd */ + #define TIFF_UPSAMPLED 0x04000 /* library is doing data up-sampling */ + #define TIFF_STRIPCHOP 0x08000 /* enable strip chopping support */ + #define TIFF_HEADERONLY 0x10000 /* read header only, do not process the first directory */ + #define TIFF_NOREADRAW 0x20000 /* skip reading of raw uncompressed image data */ + #define TIFF_INCUSTOMIFD 0x40000 /* currently writing a custom IFD */ + #define TIFF_BIGTIFF 0x80000 /* read/write bigtiff */ + #define TIFF_BUF4WRITE 0x100000 /* rawcc bytes are for writing */ + #define TIFF_DIRTYSTRIP 0x200000 /* stripoffsets/stripbytecount dirty*/ + #define TIFF_PERSAMPLE 0x400000 /* get/set per sample tags as arrays */ + #define TIFF_BUFFERMMAP 0x800000 /* read buffer (tif_rawdata) points into mmap() memory */ + uint64 tif_diroff; /* file offset of current directory */ + uint64 tif_nextdiroff; /* file offset of following directory */ + uint64* tif_dirlist; /* list of offsets to already seen directories to prevent IFD looping */ + uint16 tif_dirlistsize; /* number of entires in offset list */ + uint16 tif_dirnumber; /* number of already seen directories */ + TIFFDirectory tif_dir; /* internal rep of current directory */ + TIFFDirectory tif_customdir; /* custom IFDs are separated from the main ones */ + union { + TIFFHeaderCommon common; + TIFFHeaderClassic classic; + TIFFHeaderBig big; + } tif_header; + uint16 tif_header_size; /* file's header block and its length */ + uint32 tif_row; /* current scanline */ + uint16 tif_curdir; /* current directory (index) */ + uint32 tif_curstrip; /* current strip for read/write */ + uint64 tif_curoff; /* current offset for read/write */ + uint64 tif_dataoff; /* current offset for writing dir */ + /* SubIFD support */ + uint16 tif_nsubifd; /* remaining subifds to write */ + uint64 tif_subifdoff; /* offset for patching SubIFD link */ + /* tiling support */ + uint32 tif_col; /* current column (offset by row too) */ + uint32 tif_curtile; /* current tile for read/write */ + tmsize_t tif_tilesize; /* # of bytes in a tile */ + /* compression scheme hooks */ + int tif_decodestatus; + TIFFBoolMethod tif_fixuptags; /* called in TIFFReadDirectory */ + TIFFBoolMethod tif_setupdecode; /* called once before predecode */ + TIFFPreMethod tif_predecode; /* pre- row/strip/tile decoding */ + TIFFBoolMethod tif_setupencode; /* called once before preencode */ + int tif_encodestatus; + TIFFPreMethod tif_preencode; /* pre- row/strip/tile encoding */ + TIFFBoolMethod tif_postencode; /* post- row/strip/tile encoding */ + TIFFCodeMethod tif_decoderow; /* scanline decoding routine */ + TIFFCodeMethod tif_encoderow; /* scanline encoding routine */ + TIFFCodeMethod tif_decodestrip; /* strip decoding routine */ + TIFFCodeMethod tif_encodestrip; /* strip encoding routine */ + TIFFCodeMethod tif_decodetile; /* tile decoding routine */ + TIFFCodeMethod tif_encodetile; /* tile encoding routine */ + TIFFVoidMethod tif_close; /* cleanup-on-close routine */ + TIFFSeekMethod tif_seek; /* position within a strip routine */ + TIFFVoidMethod tif_cleanup; /* cleanup state routine */ + TIFFStripMethod tif_defstripsize; /* calculate/constrain strip size */ + TIFFTileMethod tif_deftilesize; /* calculate/constrain tile size */ + uint8* tif_data; /* compression scheme private data */ + /* input/output buffering */ + tmsize_t tif_scanlinesize; /* # of bytes in a scanline */ + tmsize_t tif_scanlineskew; /* scanline skew for reading strips */ + uint8* tif_rawdata; /* raw data buffer */ + tmsize_t tif_rawdatasize; /* # of bytes in raw data buffer */ + tmsize_t tif_rawdataoff; /* rawdata offset within strip */ + tmsize_t tif_rawdataloaded;/* amount of data in rawdata */ + uint8* tif_rawcp; /* current spot in raw buffer */ + tmsize_t tif_rawcc; /* bytes unread from raw buffer */ + /* memory-mapped file support */ + uint8* tif_base; /* base of mapped file */ + tmsize_t tif_size; /* size of mapped file region (bytes, thus tmsize_t) */ + TIFFMapFileProc tif_mapproc; /* map file method */ + TIFFUnmapFileProc tif_unmapproc; /* unmap file method */ + /* input/output callback methods */ + thandle_t tif_clientdata; /* callback parameter */ + TIFFReadWriteProc tif_readproc; /* read method */ + TIFFReadWriteProc tif_writeproc; /* write method */ + TIFFSeekProc tif_seekproc; /* lseek method */ + TIFFCloseProc tif_closeproc; /* close method */ + TIFFSizeProc tif_sizeproc; /* filesize method */ + /* post-decoding support */ + TIFFPostMethod tif_postdecode; /* post decoding routine */ + /* tag support */ + TIFFField** tif_fields; /* sorted table of registered tags */ + size_t tif_nfields; /* # entries in registered tag table */ + const TIFFField* tif_foundfield; /* cached pointer to already found tag */ + TIFFTagMethods tif_tagmethods; /* tag get/set/print routines */ + TIFFClientInfoLink* tif_clientinfo; /* extra client information. */ + /* Backward compatibility stuff. We need these two fields for + * setting up an old tag extension scheme. */ + TIFFFieldArray* tif_fieldscompat; + size_t tif_nfieldscompat; +}; + +#define isPseudoTag(t) (t > 0xffff) /* is tag value normal or pseudo */ + +#define isTiled(tif) (((tif)->tif_flags & TIFF_ISTILED) != 0) +#define isMapped(tif) (((tif)->tif_flags & TIFF_MAPPED) != 0) +#define isFillOrder(tif, o) (((tif)->tif_flags & (o)) != 0) +#define isUpSampled(tif) (((tif)->tif_flags & TIFF_UPSAMPLED) != 0) +#define TIFFReadFile(tif, buf, size) \ + ((*(tif)->tif_readproc)((tif)->tif_clientdata,(buf),(size))) +#define TIFFWriteFile(tif, buf, size) \ + ((*(tif)->tif_writeproc)((tif)->tif_clientdata,(buf),(size))) +#define TIFFSeekFile(tif, off, whence) \ + ((*(tif)->tif_seekproc)((tif)->tif_clientdata,(off),(whence))) +#define TIFFCloseFile(tif) \ + ((*(tif)->tif_closeproc)((tif)->tif_clientdata)) +#define TIFFGetFileSize(tif) \ + ((*(tif)->tif_sizeproc)((tif)->tif_clientdata)) +#define TIFFMapFileContents(tif, paddr, psize) \ + ((*(tif)->tif_mapproc)((tif)->tif_clientdata,(paddr),(psize))) +#define TIFFUnmapFileContents(tif, addr, size) \ + ((*(tif)->tif_unmapproc)((tif)->tif_clientdata,(addr),(size))) + +/* + * Default Read/Seek/Write definitions. + */ +#ifndef ReadOK +#define ReadOK(tif, buf, size) \ + (TIFFReadFile((tif),(buf),(size))==(size)) +#endif +#ifndef SeekOK +#define SeekOK(tif, off) \ + (TIFFSeekFile((tif),(off),SEEK_SET)==(off)) +#endif +#ifndef WriteOK +#define WriteOK(tif, buf, size) \ + (TIFFWriteFile((tif),(buf),(size))==(size)) +#endif + +/* NB: the uint32 casts are to silence certain ANSI-C compilers */ +#define TIFFhowmany_32(x, y) (((uint32)x < (0xffffffff - (uint32)(y-1))) ? \ + ((((uint32)(x))+(((uint32)(y))-1))/((uint32)(y))) : \ + 0U) +#define TIFFhowmany8_32(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3) +#define TIFFroundup_32(x, y) (TIFFhowmany_32(x,y)*(y)) +#define TIFFhowmany_64(x, y) ((((uint64)(x))+(((uint64)(y))-1))/((uint64)(y))) +#define TIFFhowmany8_64(x) (((x)&0x07)?((uint64)(x)>>3)+1:(uint64)(x)>>3) +#define TIFFroundup_64(x, y) (TIFFhowmany_64(x,y)*(y)) + +/* Safe multiply which returns zero if there is an integer overflow */ +#define TIFFSafeMultiply(t,v,m) ((((t)(m) != (t)0) && (((t)(((v)*(m))/(m))) == (t)(v))) ? (t)((v)*(m)) : (t)0) + +#define TIFFmax(A,B) ((A)>(B)?(A):(B)) +#define TIFFmin(A,B) ((A)<(B)?(A):(B)) + +#define TIFFArrayCount(a) (sizeof (a) / sizeof ((a)[0])) + +#if defined(__cplusplus) +extern "C" { +#endif +extern int _TIFFgetMode(const char* mode, const char* module); +extern int _TIFFNoRowEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s); +extern int _TIFFNoStripEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s); +extern int _TIFFNoTileEncode(TIFF*, uint8* pp, tmsize_t cc, uint16 s); +extern int _TIFFNoRowDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s); +extern int _TIFFNoStripDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s); +extern int _TIFFNoTileDecode(TIFF*, uint8* pp, tmsize_t cc, uint16 s); +extern void _TIFFNoPostDecode(TIFF* tif, uint8* buf, tmsize_t cc); +extern int _TIFFNoPreCode(TIFF* tif, uint16 s); +extern int _TIFFNoSeek(TIFF* tif, uint32 off); +extern void _TIFFSwab16BitData(TIFF* tif, uint8* buf, tmsize_t cc); +extern void _TIFFSwab24BitData(TIFF* tif, uint8* buf, tmsize_t cc); +extern void _TIFFSwab32BitData(TIFF* tif, uint8* buf, tmsize_t cc); +extern void _TIFFSwab64BitData(TIFF* tif, uint8* buf, tmsize_t cc); +extern int TIFFFlushData1(TIFF* tif); +extern int TIFFDefaultDirectory(TIFF* tif); +extern void _TIFFSetDefaultCompressionState(TIFF* tif); +extern int _TIFFRewriteField(TIFF *, uint16, TIFFDataType, tmsize_t, void *); +extern int TIFFSetCompressionScheme(TIFF* tif, int scheme); +extern int TIFFSetDefaultCompressionState(TIFF* tif); +extern uint32 _TIFFDefaultStripSize(TIFF* tif, uint32 s); +extern void _TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th); +extern int _TIFFDataSize(TIFFDataType type); + +extern void _TIFFsetByteArray(void**, void*, uint32); +extern void _TIFFsetString(char**, char*); +extern void _TIFFsetShortArray(uint16**, uint16*, uint32); +extern void _TIFFsetLongArray(uint32**, uint32*, uint32); +extern void _TIFFsetFloatArray(float**, float*, uint32); +extern void _TIFFsetDoubleArray(double**, double*, uint32); + +extern void _TIFFprintAscii(FILE*, const char*); +extern void _TIFFprintAsciiTag(FILE*, const char*, const char*); + +extern TIFFErrorHandler _TIFFwarningHandler; +extern TIFFErrorHandler _TIFFerrorHandler; +extern TIFFErrorHandlerExt _TIFFwarningHandlerExt; +extern TIFFErrorHandlerExt _TIFFerrorHandlerExt; + +extern uint32 _TIFFMultiply32(TIFF*, uint32, uint32, const char*); +extern uint64 _TIFFMultiply64(TIFF*, uint64, uint64, const char*); +extern void* _TIFFCheckMalloc(TIFF*, tmsize_t, tmsize_t, const char*); +extern void* _TIFFCheckRealloc(TIFF*, void*, tmsize_t, tmsize_t, const char*); + +extern double _TIFFUInt64ToDouble(uint64); +extern float _TIFFUInt64ToFloat(uint64); + +extern int TIFFInitDumpMode(TIFF*, int); +#ifdef PACKBITS_SUPPORT +extern int TIFFInitPackBits(TIFF*, int); +#endif +#ifdef CCITT_SUPPORT +extern int TIFFInitCCITTRLE(TIFF*, int), TIFFInitCCITTRLEW(TIFF*, int); +extern int TIFFInitCCITTFax3(TIFF*, int), TIFFInitCCITTFax4(TIFF*, int); +#endif +#ifdef THUNDER_SUPPORT +extern int TIFFInitThunderScan(TIFF*, int); +#endif +#ifdef NEXT_SUPPORT +extern int TIFFInitNeXT(TIFF*, int); +#endif +#ifdef LZW_SUPPORT +extern int TIFFInitLZW(TIFF*, int); +#endif +#ifdef OJPEG_SUPPORT +extern int TIFFInitOJPEG(TIFF*, int); +#endif +#ifdef JPEG_SUPPORT +extern int TIFFInitJPEG(TIFF*, int); +#endif +#ifdef JBIG_SUPPORT +extern int TIFFInitJBIG(TIFF*, int); +#endif +#ifdef ZIP_SUPPORT +extern int TIFFInitZIP(TIFF*, int); +#endif +#ifdef PIXARLOG_SUPPORT +extern int TIFFInitPixarLog(TIFF*, int); +#endif +#ifdef LOGLUV_SUPPORT +extern int TIFFInitSGILog(TIFF*, int); +#endif +#ifdef LZMA_SUPPORT +extern int TIFFInitLZMA(TIFF*, int); +#endif +#ifdef VMS +extern const TIFFCodec _TIFFBuiltinCODECS[]; +#else +extern TIFFCodec _TIFFBuiltinCODECS[]; +#endif + +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFIOP_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/tiffvers.h b/core/src/fxcodec/fx_tiff/tiff_v403/tiffvers.h new file mode 100644 index 0000000000..40edc813d5 --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/tiffvers.h @@ -0,0 +1,9 @@ +#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.0.3\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." +/* + * This define can be used in code that requires + * compilation-related definitions specific to a + * version or versions of the library. Runtime + * version checking should be done based on the + * string returned by TIFFGetVersion. + */ +#define TIFFLIB_VERSION 20120922 diff --git a/core/src/fxcodec/fx_tiff/tiff_v403/uvcode.h b/core/src/fxcodec/fx_tiff/tiff_v403/uvcode.h new file mode 100644 index 0000000000..50f11d7e0a --- /dev/null +++ b/core/src/fxcodec/fx_tiff/tiff_v403/uvcode.h @@ -0,0 +1,180 @@ +/* Version 1.0 generated April 7, 1997 by Greg Ward Larson, SGI */ +#define UV_SQSIZ (float)0.003500 +#define UV_NDIVS 16289 +#define UV_VSTART (float)0.016940 +#define UV_NVS 163 +static struct { + float ustart; + short nus, ncum; +} uv_row[UV_NVS] = { + { (float)0.247663, 4, 0 }, + { (float)0.243779, 6, 4 }, + { (float)0.241684, 7, 10 }, + { (float)0.237874, 9, 17 }, + { (float)0.235906, 10, 26 }, + { (float)0.232153, 12, 36 }, + { (float)0.228352, 14, 48 }, + { (float)0.226259, 15, 62 }, + { (float)0.222371, 17, 77 }, + { (float)0.220410, 18, 94 }, + { (float)0.214710, 21, 112 }, + { (float)0.212714, 22, 133 }, + { (float)0.210721, 23, 155 }, + { (float)0.204976, 26, 178 }, + { (float)0.202986, 27, 204 }, + { (float)0.199245, 29, 231 }, + { (float)0.195525, 31, 260 }, + { (float)0.193560, 32, 291 }, + { (float)0.189878, 34, 323 }, + { (float)0.186216, 36, 357 }, + { (float)0.186216, 36, 393 }, + { (float)0.182592, 38, 429 }, + { (float)0.179003, 40, 467 }, + { (float)0.175466, 42, 507 }, + { (float)0.172001, 44, 549 }, + { (float)0.172001, 44, 593 }, + { (float)0.168612, 46, 637 }, + { (float)0.168612, 46, 683 }, + { (float)0.163575, 49, 729 }, + { (float)0.158642, 52, 778 }, + { (float)0.158642, 52, 830 }, + { (float)0.158642, 52, 882 }, + { (float)0.153815, 55, 934 }, + { (float)0.153815, 55, 989 }, + { (float)0.149097, 58, 1044 }, + { (float)0.149097, 58, 1102 }, + { (float)0.142746, 62, 1160 }, + { (float)0.142746, 62, 1222 }, + { (float)0.142746, 62, 1284 }, + { (float)0.138270, 65, 1346 }, + { (float)0.138270, 65, 1411 }, + { (float)0.138270, 65, 1476 }, + { (float)0.132166, 69, 1541 }, + { (float)0.132166, 69, 1610 }, + { (float)0.126204, 73, 1679 }, + { (float)0.126204, 73, 1752 }, + { (float)0.126204, 73, 1825 }, + { (float)0.120381, 77, 1898 }, + { (float)0.120381, 77, 1975 }, + { (float)0.120381, 77, 2052 }, + { (float)0.120381, 77, 2129 }, + { (float)0.112962, 82, 2206 }, + { (float)0.112962, 82, 2288 }, + { (float)0.112962, 82, 2370 }, + { (float)0.107450, 86, 2452 }, + { (float)0.107450, 86, 2538 }, + { (float)0.107450, 86, 2624 }, + { (float)0.107450, 86, 2710 }, + { (float)0.100343, 91, 2796 }, + { (float)0.100343, 91, 2887 }, + { (float)0.100343, 91, 2978 }, + { (float)0.095126, 95, 3069 }, + { (float)0.095126, 95, 3164 }, + { (float)0.095126, 95, 3259 }, + { (float)0.095126, 95, 3354 }, + { (float)0.088276, 100, 3449 }, + { (float)0.088276, 100, 3549 }, + { (float)0.088276, 100, 3649 }, + { (float)0.088276, 100, 3749 }, + { (float)0.081523, 105, 3849 }, + { (float)0.081523, 105, 3954 }, + { (float)0.081523, 105, 4059 }, + { (float)0.081523, 105, 4164 }, + { (float)0.074861, 110, 4269 }, + { (float)0.074861, 110, 4379 }, + { (float)0.074861, 110, 4489 }, + { (float)0.074861, 110, 4599 }, + { (float)0.068290, 115, 4709 }, + { (float)0.068290, 115, 4824 }, + { (float)0.068290, 115, 4939 }, + { (float)0.068290, 115, 5054 }, + { (float)0.063573, 119, 5169 }, + { (float)0.063573, 119, 5288 }, + { (float)0.063573, 119, 5407 }, + { (float)0.063573, 119, 5526 }, + { (float)0.057219, 124, 5645 }, + { (float)0.057219, 124, 5769 }, + { (float)0.057219, 124, 5893 }, + { (float)0.057219, 124, 6017 }, + { (float)0.050985, 129, 6141 }, + { (float)0.050985, 129, 6270 }, + { (float)0.050985, 129, 6399 }, + { (float)0.050985, 129, 6528 }, + { (float)0.050985, 129, 6657 }, + { (float)0.044859, 134, 6786 }, + { (float)0.044859, 134, 6920 }, + { (float)0.044859, 134, 7054 }, + { (float)0.044859, 134, 7188 }, + { (float)0.040571, 138, 7322 }, + { (float)0.040571, 138, 7460 }, + { (float)0.040571, 138, 7598 }, + { (float)0.040571, 138, 7736 }, + { (float)0.036339, 142, 7874 }, + { (float)0.036339, 142, 8016 }, + { (float)0.036339, 142, 8158 }, + { (float)0.036339, 142, 8300 }, + { (float)0.032139, 146, 8442 }, + { (float)0.032139, 146, 8588 }, + { (float)0.032139, 146, 8734 }, + { (float)0.032139, 146, 8880 }, + { (float)0.027947, 150, 9026 }, + { (float)0.027947, 150, 9176 }, + { (float)0.027947, 150, 9326 }, + { (float)0.023739, 154, 9476 }, + { (float)0.023739, 154, 9630 }, + { (float)0.023739, 154, 9784 }, + { (float)0.023739, 154, 9938 }, + { (float)0.019504, 158, 10092 }, + { (float)0.019504, 158, 10250 }, + { (float)0.019504, 158, 10408 }, + { (float)0.016976, 161, 10566 }, + { (float)0.016976, 161, 10727 }, + { (float)0.016976, 161, 10888 }, + { (float)0.016976, 161, 11049 }, + { (float)0.012639, 165, 11210 }, + { (float)0.012639, 165, 11375 }, + { (float)0.012639, 165, 11540 }, + { (float)0.009991, 168, 11705 }, + { (float)0.009991, 168, 11873 }, + { (float)0.009991, 168, 12041 }, + { (float)0.009016, 170, 12209 }, + { (float)0.009016, 170, 12379 }, + { (float)0.009016, 170, 12549 }, + { (float)0.006217, 173, 12719 }, + { (float)0.006217, 173, 12892 }, + { (float)0.005097, 175, 13065 }, + { (float)0.005097, 175, 13240 }, + { (float)0.005097, 175, 13415 }, + { (float)0.003909, 177, 13590 }, + { (float)0.003909, 177, 13767 }, + { (float)0.002340, 177, 13944 }, + { (float)0.002389, 170, 14121 }, + { (float)0.001068, 164, 14291 }, + { (float)0.001653, 157, 14455 }, + { (float)0.000717, 150, 14612 }, + { (float)0.001614, 143, 14762 }, + { (float)0.000270, 136, 14905 }, + { (float)0.000484, 129, 15041 }, + { (float)0.001103, 123, 15170 }, + { (float)0.001242, 115, 15293 }, + { (float)0.001188, 109, 15408 }, + { (float)0.001011, 103, 15517 }, + { (float)0.000709, 97, 15620 }, + { (float)0.000301, 89, 15717 }, + { (float)0.002416, 82, 15806 }, + { (float)0.003251, 76, 15888 }, + { (float)0.003246, 69, 15964 }, + { (float)0.004141, 62, 16033 }, + { (float)0.005963, 55, 16095 }, + { (float)0.008839, 47, 16150 }, + { (float)0.010490, 40, 16197 }, + { (float)0.016994, 31, 16237 }, + { (float)0.023659, 21, 16268 }, +}; +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/core/src/fxcodec/lbmp/fx_bmp.cpp b/core/src/fxcodec/lbmp/fx_bmp.cpp new file mode 100644 index 0000000000..4c6eb61757 --- /dev/null +++ b/core/src/fxcodec/lbmp/fx_bmp.cpp @@ -0,0 +1,917 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fx_bmp.h" +FX_DWORD _GetDWord_LSBFirst(FX_LPBYTE p) +{ + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} +FX_WORD _GetWord_LSBFirst(FX_LPBYTE p) +{ + return p[0] | (p[1] << 8); +} +void _SetDWord_LSBFirst(FX_LPBYTE p, FX_DWORD v) +{ + p[0] = (FX_BYTE)v; + p[1] = (FX_BYTE)(v >> 8); + p[2] = (FX_BYTE)(v >> 16); + p[3] = (FX_BYTE)(v >> 24); +} +void _SetWord_LSBFirst(FX_LPBYTE p, FX_WORD v) +{ + p[0] = (FX_BYTE)v; + p[1] = (FX_BYTE)(v >> 8); +} +void _bmp_error(bmp_decompress_struct_p bmp_ptr, FX_LPCSTR err_msg) +{ + if(bmp_ptr != NULL && bmp_ptr->_bmp_error_fn != NULL) { + bmp_ptr->_bmp_error_fn(bmp_ptr, err_msg); + } +} +bmp_decompress_struct_p _bmp_create_decompress() +{ + bmp_decompress_struct_p bmp_ptr = FX_Alloc(bmp_decompress_struct, 1); + if(bmp_ptr == NULL) { + return NULL; + } + FXSYS_memset32(bmp_ptr, 0, sizeof(bmp_decompress_struct)); + bmp_ptr->decode_status = BMP_D_STATUS_HEADER; + bmp_ptr->bmp_header_ptr = FX_Alloc(BmpFileHeader, 1); + return bmp_ptr; +} +void _bmp_destroy_decompress(bmp_decompress_struct_pp bmp_ptr_ptr) +{ + if(bmp_ptr_ptr == NULL || *bmp_ptr_ptr == NULL) { + return; + } + bmp_decompress_struct_p bmp_ptr = *bmp_ptr_ptr; + *bmp_ptr_ptr = NULL; + if(bmp_ptr->out_row_buffer != NULL) { + FX_Free(bmp_ptr->out_row_buffer); + } + if(bmp_ptr->pal_ptr != NULL) { + FX_Free(bmp_ptr->pal_ptr); + } + if(bmp_ptr->bmp_header_ptr != NULL) { + FX_Free(bmp_ptr->bmp_header_ptr); + } + FX_Free(bmp_ptr); +} +FX_INT32 _bmp_read_header(bmp_decompress_struct_p bmp_ptr) +{ + if(bmp_ptr == NULL) { + return 0; + } + FX_DWORD skip_size_org = bmp_ptr->skip_size; + if(bmp_ptr->decode_status == BMP_D_STATUS_HEADER) { + ASSERT(sizeof(BmpFileHeader) == 14); + BmpFileHeader* bmp_header_ptr = NULL; + if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&bmp_header_ptr, 14) == NULL) { + return 2; + } + bmp_ptr->bmp_header_ptr->bfType = _GetWord_LSBFirst((FX_LPBYTE)&bmp_header_ptr->bfType); + bmp_ptr->bmp_header_ptr->bfOffBits = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_header_ptr->bfOffBits); + bmp_ptr->data_size = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_header_ptr->bfSize); + if(bmp_ptr->bmp_header_ptr->bfType != BMP_SIGNATURE) { + _bmp_error(bmp_ptr, "Not A Bmp Image"); + return 0; + } + if(bmp_ptr->avail_in < sizeof(FX_DWORD)) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + bmp_ptr->img_ifh_size = _GetDWord_LSBFirst(bmp_ptr->next_in + bmp_ptr->skip_size); + bmp_ptr->pal_type = 0; + ASSERT(sizeof(BmpCoreHeader) == 12); + ASSERT(sizeof(BmpInfoHeader) == 40); + switch(bmp_ptr->img_ifh_size) { + case FX_MIN(12, sizeof(BmpCoreHeader)): { + bmp_ptr->pal_type = 1; + BmpCoreHeaderPtr bmp_core_header_ptr = NULL; + if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&bmp_core_header_ptr, bmp_ptr->img_ifh_size) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + bmp_ptr->width = (FX_DWORD)_GetWord_LSBFirst((FX_LPBYTE)&bmp_core_header_ptr->bcWidth); + bmp_ptr->height = (FX_DWORD)_GetWord_LSBFirst((FX_LPBYTE)&bmp_core_header_ptr->bcHeight); + bmp_ptr->bitCounts = _GetWord_LSBFirst((FX_LPBYTE)&bmp_core_header_ptr->bcBitCount); + bmp_ptr->compress_flag = BMP_RGB; + bmp_ptr->imgTB_flag = FALSE; + } + break; + case FX_MIN(40, sizeof(BmpInfoHeader)): { + BmpInfoHeaderPtr bmp_info_header_ptr = NULL; + if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&bmp_info_header_ptr, bmp_ptr->img_ifh_size) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + bmp_ptr->width = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biWidth); + bmp_ptr->height = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biHeight); + bmp_ptr->bitCounts = _GetWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biBitCount); + bmp_ptr->compress_flag = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biCompression); + bmp_ptr->color_used = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biClrUsed); + bmp_ptr->dpi_x = (FX_INT32)_GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biXPelsPerMeter); + bmp_ptr->dpi_y = (FX_INT32)_GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biYPelsPerMeter); + if(bmp_ptr->height < 0) { + bmp_ptr->height = -bmp_ptr->height; + bmp_ptr->imgTB_flag = TRUE; + } + } + break; + default: { + if(bmp_ptr->img_ifh_size > FX_MIN(40, sizeof(BmpInfoHeader))) { + BmpInfoHeaderPtr bmp_info_header_ptr = NULL; + if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&bmp_info_header_ptr, bmp_ptr->img_ifh_size) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + FX_WORD biPlanes; + bmp_ptr->width = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biWidth); + bmp_ptr->height = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biHeight); + bmp_ptr->bitCounts = _GetWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biBitCount); + bmp_ptr->compress_flag = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biCompression); + bmp_ptr->color_used = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biClrUsed); + biPlanes = _GetWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biPlanes); + bmp_ptr->dpi_x = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biXPelsPerMeter); + bmp_ptr->dpi_y = _GetDWord_LSBFirst((FX_LPBYTE)&bmp_info_header_ptr->biYPelsPerMeter); + if(bmp_ptr->height < 0) { + bmp_ptr->height = -bmp_ptr->height; + bmp_ptr->imgTB_flag = TRUE; + } + if(bmp_ptr->compress_flag == BMP_RGB && + biPlanes == 1 && + bmp_ptr->color_used == 0) { + break; + } + } + _bmp_error(bmp_ptr, "Unsupported Bmp File"); + return 0; + } + } + ASSERT(bmp_ptr->width > 0); + ASSERT(bmp_ptr->compress_flag <= BMP_BITFIELDS); + switch(bmp_ptr->bitCounts) { + case 1: + case 4: + case 8: + case 16: + case 24: { + if(bmp_ptr->color_used > ((FX_DWORD)1) << bmp_ptr->bitCounts) { + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); + return 0; + } + } + case 32: { + if(bmp_ptr->width <= 0 || bmp_ptr->compress_flag > BMP_BITFIELDS) { + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); + return 0; + } + } + break; + default: + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); + return 0; + } + bmp_ptr->src_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, bmp_ptr->bitCounts); + switch(bmp_ptr->bitCounts) { + case 1: + case 4: + case 8: + bmp_ptr->out_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, 8); + bmp_ptr->components = 1; + break; + case 16: + case 24: + bmp_ptr->out_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, 24); + bmp_ptr->components = 3; + break; + case 32: + bmp_ptr->out_row_bytes = bmp_ptr->src_row_bytes; + bmp_ptr->components = 4; + break; + } + if(bmp_ptr->out_row_buffer != NULL) { + FX_Free(bmp_ptr->out_row_buffer); + bmp_ptr->out_row_buffer = NULL; + } + bmp_ptr->out_row_buffer = FX_Alloc(FX_BYTE, bmp_ptr->out_row_bytes); + BMP_PTR_NOT_NULL(bmp_ptr->out_row_buffer, bmp_ptr); + FXSYS_memset32(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes); + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_PAL); + } + if (bmp_ptr->decode_status == BMP_D_STATUS_PAL) { + skip_size_org = bmp_ptr->skip_size; +#ifdef BMP_SUPPORT_BITFIELD + if(bmp_ptr->compress_flag == BMP_BITFIELDS) { + if(bmp_ptr->bitCounts != 16 && bmp_ptr->bitCounts != 32) { + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); + return 0; + } + FX_DWORD* mask; + if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&mask, 3 * sizeof(FX_DWORD)) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + bmp_ptr->mask_red = _GetDWord_LSBFirst((FX_LPBYTE)&mask[0]); + bmp_ptr->mask_green = _GetDWord_LSBFirst((FX_LPBYTE)&mask[1]); + bmp_ptr->mask_blue = _GetDWord_LSBFirst((FX_LPBYTE)&mask[2]); + if(bmp_ptr->mask_red & bmp_ptr->mask_green || + bmp_ptr->mask_red & bmp_ptr->mask_blue || + bmp_ptr->mask_green & bmp_ptr->mask_blue) { + _bmp_error(bmp_ptr, "The Bitfield Bmp File Is Corrupt"); + return 0; + } + if(bmp_ptr->bmp_header_ptr->bfOffBits < 26 + bmp_ptr->img_ifh_size) { + bmp_ptr->bmp_header_ptr->bfOffBits = 26 + bmp_ptr->img_ifh_size; + } + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA_PRE); + return 1; + } else if(bmp_ptr->bitCounts == 16) { + bmp_ptr->mask_red = 0x7C00; + bmp_ptr->mask_green = 0x03E0; + bmp_ptr->mask_blue = 0x001F; + } +#else + if(bmp_ptr->compress_flag == BMP_BITFIELDS || bmp_ptr->bitCounts == 16) { + _bmp_error(bmp_ptr, "Unsupported Bitfield Bmp File"); + return 0; + } +#endif + bmp_ptr->pal_num = 0; + if(bmp_ptr->bitCounts < 16) { + bmp_ptr->pal_num = 1 << bmp_ptr->bitCounts; + if(bmp_ptr->color_used != 0) { + bmp_ptr->pal_num = bmp_ptr->color_used; + } + FX_LPBYTE src_pal_ptr = NULL; + FX_DWORD src_pal_size = bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4); + if(_bmp_read_data(bmp_ptr, (FX_LPBYTE*)&src_pal_ptr, src_pal_size) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + if(bmp_ptr->pal_ptr != NULL) { + FX_Free(bmp_ptr->pal_ptr); + bmp_ptr->pal_ptr = NULL; + } + bmp_ptr->pal_ptr = FX_Alloc(FX_DWORD, bmp_ptr->pal_num); + BMP_PTR_NOT_NULL(bmp_ptr->pal_ptr, bmp_ptr); + FX_INT32 src_pal_index = 0; + if(bmp_ptr->pal_type == BMP_PAL_OLD) { + while(src_pal_index < bmp_ptr->pal_num) { + bmp_ptr->pal_ptr[src_pal_index++] = BMP_PAL_ENCODE(0x00, src_pal_ptr[2], src_pal_ptr[1], src_pal_ptr[0]); + src_pal_ptr += 3; + } + } else { + while(src_pal_index < bmp_ptr->pal_num) { + bmp_ptr->pal_ptr[src_pal_index++] = BMP_PAL_ENCODE(src_pal_ptr[3], src_pal_ptr[2], src_pal_ptr[1], src_pal_ptr[0]); + src_pal_ptr += 4; + } + } + } + if(bmp_ptr->bmp_header_ptr->bfOffBits < 14 + bmp_ptr->img_ifh_size + bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4)) { + bmp_ptr->bmp_header_ptr->bfOffBits = 14 + bmp_ptr->img_ifh_size + bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4); + } + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA_PRE); + } + return 1; +} +FX_INT32 _bmp_decode_image(bmp_decompress_struct_p bmp_ptr) +{ + if(bmp_ptr->decode_status == BMP_D_STATUS_DATA_PRE) { + bmp_ptr->avail_in = 0; + if(!bmp_ptr->_bmp_get_data_position_fn(bmp_ptr, bmp_ptr->bmp_header_ptr->bfOffBits)) { + bmp_ptr->decode_status = BMP_D_STATUS_TAIL; + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt, Unexpected Stream Offset"); + return 0; + } + bmp_ptr->row_num = 0; + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA); + } + if(bmp_ptr->decode_status == BMP_D_STATUS_DATA) { + switch(bmp_ptr->compress_flag) { + case BMP_RGB: + case BMP_BITFIELDS: + return _bmp_decode_rgb(bmp_ptr); + case BMP_RLE8: + return _bmp_decode_rle8(bmp_ptr); + case BMP_RLE4: + return _bmp_decode_rle4(bmp_ptr); + } + } + _bmp_error(bmp_ptr, "Any Uncontrol Error"); + return 0; +} +FX_INT32 _bmp_decode_rgb(bmp_decompress_struct_p bmp_ptr) +{ + FX_LPBYTE row_buf = bmp_ptr->out_row_buffer; + FX_LPBYTE des_buf = NULL; + while (bmp_ptr->row_num < bmp_ptr->height) { + if(_bmp_read_data(bmp_ptr, &des_buf, bmp_ptr->src_row_bytes) == NULL) { + return 2; + } + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA); + switch(bmp_ptr->bitCounts) { + case 1: { + for (FX_INT32 col = 0; col < bmp_ptr->width; col++) { + *row_buf++ = des_buf[col >> 3] & (0x80 >> (col % 8)) ? 0x01 : 0x00; + } + } + break; + case 4: { + for (FX_INT32 col = 0; col < bmp_ptr->width; col++) { + *row_buf++ = (col & 0x01) ? + (des_buf[col >> 1] & 0x0F) : + ((des_buf[col >> 1] & 0xF0) >> 4); + } + } + break; +#ifdef BMP_SUPPORT_BITFIELD + case 16: { + FX_WORD* buf = (FX_WORD*)des_buf; + FX_BYTE blue_bits = 0; + FX_BYTE green_bits = 0; + FX_BYTE red_bits = 0; + for(FX_INT32 i = 0; i < 16; i++) { + if((bmp_ptr->mask_blue >> i) & 0x01) { + blue_bits++; + } + if((bmp_ptr->mask_green >> i) & 0x01) { + green_bits++; + } + if((bmp_ptr->mask_red >> i) & 0x01) { + red_bits++; + } + } + green_bits += blue_bits; + red_bits += green_bits; + blue_bits = 8 - blue_bits; + green_bits -= 8; + red_bits -= 8; + for (FX_INT32 col = 0; col < bmp_ptr->width; col++) { + *buf = _GetWord_LSBFirst((FX_LPBYTE)buf); + *row_buf++ = (FX_BYTE)((*buf & bmp_ptr->mask_blue) << blue_bits); + *row_buf++ = (FX_BYTE)((*buf & bmp_ptr->mask_green) >> green_bits); + *row_buf++ = (FX_BYTE)((*buf++ & bmp_ptr->mask_red) >> red_bits); + } + } + break; +#endif + case 8: + case 24: + case 32: + FXSYS_memcpy32(bmp_ptr->out_row_buffer, des_buf, bmp_ptr->src_row_bytes); + break; + } + row_buf = bmp_ptr->out_row_buffer; + bmp_ptr->_bmp_get_row_fn(bmp_ptr, + bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++), + bmp_ptr->out_row_buffer); + } + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL); + return 1; +} +FX_INT32 _bmp_decode_rle8(bmp_decompress_struct_p bmp_ptr) +{ + FX_LPBYTE first_byte_ptr = NULL; + FX_LPBYTE second_byte_ptr = NULL; + bmp_ptr->col_num = 0; + while(TRUE) { + FX_DWORD skip_size_org = bmp_ptr->skip_size; + if(_bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) { + return 2; + } + switch(*first_byte_ptr) { + case RLE_MARKER: { + if(_bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + switch(*first_byte_ptr) { + case RLE_EOL: { + if(bmp_ptr->row_num >= bmp_ptr->height) { + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL); + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); + return 0; + } + bmp_ptr->_bmp_get_row_fn(bmp_ptr, + bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++), + bmp_ptr->out_row_buffer); + bmp_ptr->col_num = 0; + FXSYS_memset32(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes); + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA); + continue; + } + case RLE_EOI: { + if(bmp_ptr->row_num < bmp_ptr->height) { + bmp_ptr->_bmp_get_row_fn(bmp_ptr, + bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++), + bmp_ptr->out_row_buffer); + } + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL); + return 1; + } + case RLE_DELTA: { + FX_LPBYTE delta_ptr; + if(_bmp_read_data(bmp_ptr, &delta_ptr, 2) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + bmp_ptr->col_num += (FX_INT32)delta_ptr[0]; + FX_INT32 bmp_row_num_next = bmp_ptr->row_num + (FX_INT32)delta_ptr[1]; + if(bmp_ptr->col_num >= bmp_ptr->out_row_bytes || bmp_row_num_next >= bmp_ptr->height) { + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt Or Not Supported"); + return 0; + } + while(bmp_ptr->row_num < bmp_row_num_next) { + FXSYS_memset32(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes); + bmp_ptr->_bmp_get_row_fn(bmp_ptr, + bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++), + bmp_ptr->out_row_buffer); + } + } + break; + default: { + if((FX_INT32)(*first_byte_ptr) > bmp_ptr->src_row_bytes - bmp_ptr->col_num) { + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); + return 0; + } + if(_bmp_read_data(bmp_ptr, &second_byte_ptr, + *first_byte_ptr & 1 ? *first_byte_ptr + 1 : *first_byte_ptr) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + FXSYS_memcpy32(bmp_ptr->out_row_buffer + bmp_ptr->col_num, second_byte_ptr, *first_byte_ptr); + bmp_ptr->col_num += (FX_INT32)(*first_byte_ptr); + } + } + } + break; + default: { + if(_bmp_read_data(bmp_ptr, &second_byte_ptr, 1) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + if((FX_INT32)(*first_byte_ptr) > bmp_ptr->src_row_bytes - bmp_ptr->col_num) { + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); + return 0; + } + FXSYS_memset8(bmp_ptr->out_row_buffer + bmp_ptr->col_num, *second_byte_ptr, *first_byte_ptr); + bmp_ptr->col_num += (FX_INT32)(*first_byte_ptr); + } + } + } + _bmp_error(bmp_ptr, "Any Uncontrol Error"); + return 0; +} +FX_INT32 _bmp_decode_rle4(bmp_decompress_struct_p bmp_ptr) +{ + FX_LPBYTE first_byte_ptr = NULL; + FX_LPBYTE second_byte_ptr = NULL; + bmp_ptr->col_num = 0; + while (TRUE) { + FX_DWORD skip_size_org = bmp_ptr->skip_size; + if(_bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) { + return 2; + } + switch(*first_byte_ptr) { + case RLE_MARKER: { + if(_bmp_read_data(bmp_ptr, &first_byte_ptr, 1) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + switch(*first_byte_ptr) { + case RLE_EOL: { + if(bmp_ptr->row_num >= bmp_ptr->height) { + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL); + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); + return 0; + } + bmp_ptr->_bmp_get_row_fn(bmp_ptr, + bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++), + bmp_ptr->out_row_buffer); + bmp_ptr->col_num = 0; + FXSYS_memset32(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes); + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA); + continue; + } + case RLE_EOI: { + if(bmp_ptr->row_num < bmp_ptr->height) { + bmp_ptr->_bmp_get_row_fn(bmp_ptr, + bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++), + bmp_ptr->out_row_buffer); + } + _bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL); + return 1; + } + case RLE_DELTA: { + FX_LPBYTE delta_ptr; + if(_bmp_read_data(bmp_ptr, &delta_ptr, 2) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + bmp_ptr->col_num += (FX_INT32)delta_ptr[0]; + FX_INT32 bmp_row_num_next = bmp_ptr->row_num + (FX_INT32)delta_ptr[1]; + if(bmp_ptr->col_num >= bmp_ptr->out_row_bytes || bmp_row_num_next >= bmp_ptr->height) { + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt Or Not Supported"); + return 0; + } + while(bmp_ptr->row_num < bmp_row_num_next) { + FXSYS_memset32(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes); + bmp_ptr->_bmp_get_row_fn(bmp_ptr, + bmp_ptr->imgTB_flag ? bmp_ptr->row_num++ : (bmp_ptr->height - 1 - bmp_ptr->row_num++), + bmp_ptr->out_row_buffer); + } + } + break; + default: { + FX_BYTE size = (FX_BYTE)(((FX_WORD)(*first_byte_ptr) + 1) >> 1); + if((FX_INT32)*first_byte_ptr >= bmp_ptr->out_row_bytes - bmp_ptr->col_num) { + if(size + (bmp_ptr->col_num >> 1) > bmp_ptr->src_row_bytes) { + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); + return 0; + } + *first_byte_ptr = bmp_ptr->out_row_bytes - bmp_ptr->col_num - 1; + } + if(_bmp_read_data(bmp_ptr, &second_byte_ptr, size & 1 ? size + 1 : size) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + for (FX_BYTE i = 0; i < *first_byte_ptr; i++) { + if(i & 0x01) { + *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = (*second_byte_ptr++ & 0x0F); + } else { + *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = ((*second_byte_ptr & 0xF0) >> 4); + } + } + } + } + } + break; + default: { + if(_bmp_read_data(bmp_ptr, &second_byte_ptr, 1) == NULL) { + bmp_ptr->skip_size = skip_size_org; + return 2; + } + if((FX_INT32)*first_byte_ptr > bmp_ptr->out_row_bytes - bmp_ptr->col_num) { + FX_BYTE size = (FX_BYTE)(((FX_WORD)(*first_byte_ptr) + 1) >> 1); + if(size + (bmp_ptr->col_num >> 1) > bmp_ptr->src_row_bytes) { + _bmp_error(bmp_ptr, "The Bmp File Is Corrupt"); + return 0; + } + *first_byte_ptr = bmp_ptr->out_row_bytes - bmp_ptr->col_num - 1; + } + for (FX_BYTE i = 0; i < *first_byte_ptr; i++) { + if(i & 0x01) { + *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = (*second_byte_ptr & 0x0F); + } else { + *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) = ((*second_byte_ptr & 0xF0) >> 4); + } + } + } + } + } + _bmp_error(bmp_ptr, "Any Uncontrol Error"); + return 0; +} +FX_LPBYTE _bmp_read_data(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE* des_buf_pp, FX_DWORD data_size) +{ + if(bmp_ptr == NULL || + bmp_ptr->avail_in < bmp_ptr->skip_size + data_size) { + return NULL; + } + *des_buf_pp = bmp_ptr->next_in + bmp_ptr->skip_size; + bmp_ptr->skip_size += data_size; + return *des_buf_pp; +} +void _bmp_save_decoding_status(bmp_decompress_struct_p bmp_ptr, FX_INT32 status) +{ + bmp_ptr->decode_status = status; + bmp_ptr->next_in += bmp_ptr->skip_size; + bmp_ptr->avail_in -= bmp_ptr->skip_size; + bmp_ptr->skip_size = 0; +} +void _bmp_input_buffer(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE src_buf, FX_DWORD src_size) +{ + bmp_ptr->next_in = src_buf; + bmp_ptr->avail_in = src_size; + bmp_ptr->skip_size = 0; +} +FX_DWORD _bmp_get_avail_input(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE* avial_buf_ptr) +{ + if(avial_buf_ptr != NULL) { + *avial_buf_ptr = NULL; + if(bmp_ptr->avail_in > 0) { + *avial_buf_ptr = bmp_ptr->next_in; + } + } + return bmp_ptr->avail_in; +} +bmp_compress_struct_p _bmp_create_compress() +{ + bmp_compress_struct_p bmp_ptr; + bmp_ptr = FX_Alloc(bmp_compress_struct, 1); + if (bmp_ptr) { + FXSYS_memset32(bmp_ptr, 0, sizeof(bmp_compress_struct)); + } + return bmp_ptr; +} +void _bmp_destroy_compress(bmp_compress_struct_p bmp_ptr) +{ + if (bmp_ptr) { + if (bmp_ptr->src_free && bmp_ptr->src_buf) { + FX_Free(bmp_ptr->src_buf); + } + FX_Free(bmp_ptr); + } +} +static void WriteFileHeader(BmpFileHeaderPtr head_ptr, FX_LPBYTE dst_buf) +{ + FX_DWORD offset; + offset = 0; + _SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfType); + offset += 2; + _SetDWord_LSBFirst(&dst_buf[offset], head_ptr->bfSize); + offset += 4; + _SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfReserved1); + offset += 2; + _SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfReserved2); + offset += 2; + _SetDWord_LSBFirst(&dst_buf[offset], head_ptr->bfOffBits); + offset += 4; +} +static void WriteInfoHeader(BmpInfoHeaderPtr info_head_ptr, FX_LPBYTE dst_buf) +{ + FX_DWORD offset; + offset = sizeof(BmpFileHeader); + _SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biSize); + offset += 4; + _SetDWord_LSBFirst(&dst_buf[offset], (FX_DWORD)info_head_ptr->biWidth); + offset += 4; + _SetDWord_LSBFirst(&dst_buf[offset], (FX_DWORD)info_head_ptr->biHeight); + offset += 4; + _SetWord_LSBFirst(&dst_buf[offset], info_head_ptr->biPlanes); + offset += 2; + _SetWord_LSBFirst(&dst_buf[offset], info_head_ptr->biBitCount); + offset += 2; + _SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biCompression); + offset += 4; + _SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biSizeImage); + offset += 4; + _SetDWord_LSBFirst(&dst_buf[offset], (FX_DWORD)info_head_ptr->biXPelsPerMeter); + offset += 4; + _SetDWord_LSBFirst(&dst_buf[offset], (FX_DWORD)info_head_ptr->biYPelsPerMeter); + offset += 4; + _SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biClrUsed); + offset += 4; + _SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biClrImportant); + offset += 4; +} +#ifdef BMP_SUPPORT_BITFIELD +static void _bmp_encode_bitfields(bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size) +{ + if (bmp_ptr->info_header.biBitCount != 16 && bmp_ptr->info_header.biBitCount != 32) { + return; + } + FX_DWORD size, dst_pos, i; + size = bmp_ptr->src_pitch * bmp_ptr->src_row * bmp_ptr->info_header.biBitCount / 16; + dst_pos = bmp_ptr->file_header.bfOffBits; + dst_size += size; + dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_size); + if (dst_buf == NULL) { + return; + } + FXSYS_memset32(&dst_buf[dst_pos], 0, size); + FX_DWORD mask_red; + FX_DWORD mask_green; + FX_DWORD mask_blue; + mask_red = 0x7C00; + mask_green = 0x03E0; + mask_blue = 0x001F; + if (bmp_ptr->info_header.biCompression == BMP_BITFIELDS) { + if (bmp_ptr->bit_type == BMP_BIT_565) { + mask_red = 0xF800; + mask_green = 0x07E0; + mask_blue = 0x001F; + } + if (bmp_ptr->info_header.biBitCount == 32) { + mask_red = 0xFF0000; + mask_green = 0x00FF00; + mask_blue = 0x0000FF; + } + _SetDWord_LSBFirst(&dst_buf[dst_pos], mask_red); + dst_pos += 4; + _SetDWord_LSBFirst(&dst_buf[dst_pos], mask_green); + dst_pos += 4; + _SetDWord_LSBFirst(&dst_buf[dst_pos], mask_blue); + dst_pos += 4; + bmp_ptr->file_header.bfOffBits = dst_pos; + } + FX_BYTE blue_bits = 0; + FX_BYTE green_bits = 0; + FX_BYTE red_bits = 0; + for(i = 0; i < bmp_ptr->info_header.biBitCount; i++) { + if((mask_blue >> i) & 0x01) { + blue_bits++; + } + if((mask_green >> i) & 0x01) { + green_bits++; + } + if((mask_red >> i) & 0x01) { + red_bits++; + } + } + green_bits += blue_bits; + red_bits += green_bits; + blue_bits = 8 - blue_bits; + green_bits -= 8; + red_bits -= 8; + i = 0; + for (FX_INT32 row_num = bmp_ptr->src_row - 1; row_num > -1; row_num--, i = 0) { + while (i < bmp_ptr->src_width * bmp_ptr->src_bpp / 8) { + FX_BYTE b = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++]; + FX_BYTE g = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++]; + FX_BYTE r = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++]; + if (bmp_ptr->src_bpp == 32) { + i++; + } + FX_DWORD pix_val = 0; + pix_val |= (b >> blue_bits) & mask_blue; + pix_val |= (g << green_bits) & mask_green; + pix_val |= (r << red_bits) & mask_red; + if (bmp_ptr->info_header.biBitCount == 16) { + _SetWord_LSBFirst(&dst_buf[dst_pos], (FX_WORD)pix_val); + dst_pos += 2; + } else { + _SetDWord_LSBFirst(&dst_buf[dst_pos], pix_val); + dst_pos += 4; + } + } + } + dst_size = dst_pos; +} +#endif +static void _bmp_encode_rgb(bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size) +{ + if (bmp_ptr->info_header.biBitCount == 16) { +#ifdef BMP_SUPPORT_BITFIELD + _bmp_encode_bitfields(bmp_ptr, dst_buf, dst_size); +#endif + return; + } + FX_DWORD size, dst_pos; + FX_DWORD dst_pitch = (bmp_ptr->src_width * bmp_ptr->info_header.biBitCount + 31) / 32 * 4; + size = dst_pitch * bmp_ptr->src_row; + dst_pos = bmp_ptr->file_header.bfOffBits; + dst_size += size; + dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_size); + if (dst_buf == NULL) { + return; + } + FXSYS_memset32(&dst_buf[dst_pos], 0, size); + for (FX_INT32 row_num = bmp_ptr->src_row - 1; row_num > -1; row_num--) { + FXSYS_memcpy32(&dst_buf[dst_pos], &bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch], bmp_ptr->src_pitch); + dst_pos += dst_pitch; + } + dst_size = dst_pos; +} +static FX_BYTE _bmp_rle8_search(FX_LPCBYTE buf, FX_INT32 len) +{ + FX_BYTE num; + num = 1; + while (num < len) { + if (buf[num - 1] != buf[num] || num == 0xFF) { + break; + } + num++; + } + return num; +} +static void _bmp_encode_rle8(bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size) +{ + FX_DWORD size, dst_pos, index; + FX_BYTE rle[2] = {0}; + size = bmp_ptr->src_pitch * bmp_ptr->src_row * 2; + dst_pos = bmp_ptr->file_header.bfOffBits; + dst_size += size; + dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_size); + if (dst_buf == NULL) { + return; + } + FXSYS_memset32(&dst_buf[dst_pos], 0, size); + for (FX_INT32 row_num = bmp_ptr->src_row - 1, i = 0; row_num > -1; ) { + index = row_num * bmp_ptr->src_pitch; + rle[0] = _bmp_rle8_search(&bmp_ptr->src_buf[index + i], size - index - i); + rle[1] = bmp_ptr->src_buf[index + i]; + if (i + rle[0] >= (FX_INT32)bmp_ptr->src_pitch) { + rle[0] = FX_BYTE(bmp_ptr->src_pitch - i); + if (rle[0]) { + dst_buf[dst_pos++] = rle[0]; + dst_buf[dst_pos++] = rle[1]; + } + dst_buf[dst_pos++] = RLE_MARKER; + dst_buf[dst_pos++] = RLE_EOL; + i = 0; + row_num--; + } else { + i += rle[0]; + dst_buf[dst_pos++] = rle[0]; + dst_buf[dst_pos++] = rle[1]; + } + } + dst_buf[dst_pos++] = RLE_MARKER; + dst_buf[dst_pos++] = RLE_EOI; + dst_size = dst_pos; +} +static FX_BYTE _bmp_rle4_search(FX_LPCBYTE buf, FX_INT32 len) +{ + FX_BYTE num; + num = 2; + while (num < len) { + if (buf[num - 2] != buf[num] || num == 0xFF) { + break; + } + num++; + } + return num; +} +static void _bmp_encode_rle4(bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size) +{ + FX_DWORD size, dst_pos, index; + FX_BYTE rle[2] = {0}; + size = bmp_ptr->src_pitch * bmp_ptr->src_row; + dst_pos = bmp_ptr->file_header.bfOffBits; + dst_size += size; + dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_size); + if (dst_buf == NULL) { + return; + } + FXSYS_memset32(&dst_buf[dst_pos], 0, size); + for (FX_INT32 row_num = bmp_ptr->src_row - 1, i = 0; row_num > -1; rle[1] = 0) { + index = row_num * bmp_ptr->src_pitch; + rle[0] = _bmp_rle4_search(&bmp_ptr->src_buf[index + i], size - index - i); + rle[1] |= (bmp_ptr->src_buf[index + i] & 0x0f) << 4; + rle[1] |= bmp_ptr->src_buf[index + i + 1] & 0x0f; + if (i + rle[0] >= (FX_INT32)bmp_ptr->src_pitch) { + rle[0] = FX_BYTE(bmp_ptr->src_pitch - i); + if (rle[0]) { + dst_buf[dst_pos++] = rle[0]; + dst_buf[dst_pos++] = rle[1]; + } + dst_buf[dst_pos++] = RLE_MARKER; + dst_buf[dst_pos++] = RLE_EOL; + i = 0; + row_num--; + } else { + i += rle[0]; + dst_buf[dst_pos++] = rle[0]; + dst_buf[dst_pos++] = rle[1]; + } + } + dst_buf[dst_pos++] = RLE_MARKER; + dst_buf[dst_pos++] = RLE_EOI; + dst_size = dst_pos; +} +FX_BOOL _bmp_encode_image( bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size ) +{ + FX_DWORD head_size = sizeof(BmpFileHeader) + sizeof(BmpInfoHeader); + FX_DWORD pal_size = sizeof(FX_DWORD) * bmp_ptr->pal_num; + if (bmp_ptr->info_header.biClrUsed > 0 && bmp_ptr->info_header.biClrUsed < bmp_ptr->pal_num) { + pal_size = sizeof(FX_DWORD) * bmp_ptr->info_header.biClrUsed; + } + dst_size = head_size + sizeof(FX_DWORD) * bmp_ptr->pal_num; + dst_buf = FX_AllocNL(FX_BYTE, dst_size); + if (dst_buf == NULL) { + return FALSE; + } + FXSYS_memset32(dst_buf, 0, dst_size); + bmp_ptr->file_header.bfOffBits = head_size; + if (bmp_ptr->pal_ptr && pal_size) { + FXSYS_memcpy32(&dst_buf[head_size], bmp_ptr->pal_ptr, pal_size); + bmp_ptr->file_header.bfOffBits += pal_size; + } + WriteInfoHeader(&bmp_ptr->info_header, dst_buf); + switch(bmp_ptr->info_header.biCompression) { + case BMP_RGB: + _bmp_encode_rgb(bmp_ptr, dst_buf, dst_size); + break; + case BMP_BITFIELDS: +#ifdef BMP_SUPPORT_BITFIELD + _bmp_encode_bitfields(bmp_ptr, dst_buf, dst_size); +#endif + break; + case BMP_RLE8: + _bmp_encode_rle8(bmp_ptr, dst_buf, dst_size); + break; + case BMP_RLE4: + _bmp_encode_rle4(bmp_ptr, dst_buf, dst_size); + break; + default: + ; + } + bmp_ptr->file_header.bfSize = dst_size; + WriteFileHeader(&bmp_ptr->file_header, dst_buf); + return TRUE; +} diff --git a/core/src/fxcodec/lbmp/fx_bmp.h b/core/src/fxcodec/lbmp/fx_bmp.h new file mode 100644 index 0000000000..1603770eb4 --- /dev/null +++ b/core/src/fxcodec/lbmp/fx_bmp.h @@ -0,0 +1,142 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef _FX_BASIC_H_ +#include "../../../include/fxcrt/fx_basic.h" +#endif +#define BMP_SUPPORT_BITFIELD +#define BMP_WIDTHBYTES(width,bitCount) ((width*bitCount) + 31)/32*4 +#define BMP_PAL_ENCODE(a,r,g,b) (((FX_DWORD)(a) << 24) | ((r) << 16) | ((g) << 8) | (b)) +#define BMP_D_STATUS_HEADER 0x01 +#define BMP_D_STATUS_PAL 0x02 +#define BMP_D_STATUS_DATA_PRE 0x03 +#define BMP_D_STATUS_DATA 0x04 +#define BMP_D_STATUS_TAIL 0x00 +#define BMP_SIGNATURE 0x4D42 +#define BMP_PAL_NEW 0 +#define BMP_PAL_OLD 1 +#define RLE_MARKER 0 +#define RLE_EOL 0 +#define RLE_EOI 1 +#define RLE_DELTA 2 +#define BMP_RGB 0L +#define BMP_RLE8 1L +#define BMP_RLE4 2L +#define BMP_BITFIELDS 3L +#define BMP_BIT_555 0 +#define BMP_BIT_565 1 +#define BMP_MAX_ERROR_SIZE 256 +#pragma pack(1) +typedef struct tagBmpFileHeader { + FX_WORD bfType; + FX_DWORD bfSize; + FX_WORD bfReserved1; + FX_WORD bfReserved2; + FX_DWORD bfOffBits; +} BmpFileHeader, *BmpFileHeaderPtr; +typedef struct tagBmpCoreHeader { + FX_DWORD bcSize; + FX_WORD bcWidth; + FX_WORD bcHeight; + FX_WORD bcPlanes; + FX_WORD bcBitCount; +} BmpCoreHeader, *BmpCoreHeaderPtr; +typedef struct tagBmpInfoHeader { + FX_DWORD biSize; + FX_INT32 biWidth; + FX_INT32 biHeight; + FX_WORD biPlanes; + FX_WORD biBitCount; + FX_DWORD biCompression; + FX_DWORD biSizeImage; + FX_INT32 biXPelsPerMeter; + FX_INT32 biYPelsPerMeter; + FX_DWORD biClrUsed; + FX_DWORD biClrImportant; +} BmpInfoHeader, *BmpInfoHeaderPtr; +#pragma pack() +typedef struct tag_bmp_decompress_struct bmp_decompress_struct; +typedef bmp_decompress_struct *bmp_decompress_struct_p; +typedef bmp_decompress_struct_p *bmp_decompress_struct_pp; +struct tag_bmp_decompress_struct { + jmp_buf jmpbuf; + FX_LPSTR err_ptr; + void (*_bmp_error_fn)(bmp_decompress_struct_p gif_ptr, FX_LPCSTR err_msg); + + void* context_ptr; + + BmpFileHeaderPtr bmp_header_ptr; + BmpInfoHeaderPtr bmp_infoheader_ptr; + FX_INT32 width; + FX_INT32 height; + FX_DWORD compress_flag; + FX_INT32 components; + FX_INT32 src_row_bytes; + FX_INT32 out_row_bytes; + FX_LPBYTE out_row_buffer; + FX_WORD bitCounts; + FX_DWORD color_used; + FX_BOOL imgTB_flag; + FX_INT32 pal_num; + FX_INT32 pal_type; + FX_DWORD* pal_ptr; + FX_DWORD data_size; + FX_DWORD img_data_offset; + FX_DWORD img_ifh_size; + FX_INT32 row_num; + FX_INT32 col_num; + FX_INT32 dpi_x; + FX_INT32 dpi_y; +#ifdef BMP_SUPPORT_BITFIELD + FX_DWORD mask_red; + FX_DWORD mask_green; + FX_DWORD mask_blue; +#endif + + FX_BOOL (*_bmp_get_data_position_fn)(bmp_decompress_struct_p bmp_ptr, FX_DWORD cur_pos); + void (*_bmp_get_row_fn)(bmp_decompress_struct_p bmp_ptr, FX_INT32 row_num, FX_LPBYTE row_buf); + FX_LPBYTE next_in; + FX_DWORD avail_in; + FX_DWORD skip_size; + FX_INT32 decode_status; +}; +void _bmp_error(bmp_decompress_struct_p bmp_ptr, FX_LPCSTR err_msg); +bmp_decompress_struct_p _bmp_create_decompress(); +void _bmp_destroy_decompress(bmp_decompress_struct_pp bmp_ptr_ptr); +FX_INT32 _bmp_read_header(bmp_decompress_struct_p bmp_ptr); +FX_INT32 _bmp_decode_image(bmp_decompress_struct_p bmp_ptr); +FX_INT32 _bmp_decode_rgb(bmp_decompress_struct_p bmp_ptr); +FX_INT32 _bmp_decode_rle8(bmp_decompress_struct_p bmp_ptr); +FX_INT32 _bmp_decode_rle4(bmp_decompress_struct_p bmp_ptr); +FX_LPBYTE _bmp_read_data(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE* des_buf_pp, FX_DWORD data_size); +void _bmp_save_decoding_status(bmp_decompress_struct_p bmp_ptr, FX_INT32 status); +void _bmp_input_buffer(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE src_buf, FX_DWORD src_size); +FX_DWORD _bmp_get_avail_input(bmp_decompress_struct_p bmp_ptr, FX_LPBYTE* avial_buf_ptr); +#define BMP_PTR_NOT_NULL(ptr,bmp_ptr) if(ptr == NULL){ \ + _bmp_error(bmp_ptr,"Out Of Memory");\ + return 0; \ + } +typedef struct tag_bmp_compress_struct bmp_compress_struct; +typedef bmp_compress_struct *bmp_compress_struct_p; +typedef bmp_compress_struct_p *bmp_compress_struct_pp; +struct tag_bmp_compress_struct { + BmpFileHeader file_header; + BmpInfoHeader info_header; + FX_LPBYTE src_buf; + FX_DWORD src_pitch; + FX_DWORD src_row; + FX_BYTE src_bpp; + FX_DWORD src_width; + FX_BOOL src_free; + FX_DWORD* pal_ptr; + FX_WORD pal_num; +#ifdef BMP_SUPPORT_BITFIELD + FX_BYTE bit_type; +#endif +}; +bmp_compress_struct_p _bmp_create_compress(); +void _bmp_destroy_compress(bmp_compress_struct_p bmp_ptr); +FX_BOOL _bmp_encode_image(bmp_compress_struct_p bmp_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_size); diff --git a/core/src/fxcodec/lgif/fx_gif.cpp b/core/src/fxcodec/lgif/fx_gif.cpp new file mode 100644 index 0000000000..8f5794e786 --- /dev/null +++ b/core/src/fxcodec/lgif/fx_gif.cpp @@ -0,0 +1,1368 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fx_gif.h" +void CGifLZWDecoder::Input(FX_LPBYTE src_buf, FX_DWORD src_size) +{ + next_in = src_buf; + avail_in = src_size; +} +FX_DWORD CGifLZWDecoder::GetAvailInput() +{ + return avail_in; +} +void CGifLZWDecoder::InitTable(FX_BYTE code_len) +{ + code_size = code_len; + code_clear = 1 << code_size; + code_end = code_clear + 1; + bits_left = 0; + code_store = 0; + next_in = NULL; + avail_in = 0; + stack_size = 0; + code_first = 0; + ClearTable(); +} +void CGifLZWDecoder::ClearTable() +{ + code_size_cur = code_size + 1; + code_next = code_end + 1; + code_old = (FX_WORD) - 1; + FXSYS_memset32(code_table, 0, sizeof(tag_Table)*GIF_MAX_LZW_CODE); + FXSYS_memset32(stack, 0, GIF_MAX_LZW_CODE); + for (FX_WORD i = 0; i < code_clear; i++) { + code_table[i].suffix = (FX_BYTE)i; + } +} +void CGifLZWDecoder::DecodeString(FX_WORD code) +{ + stack_size = 0; + while (TRUE) { + ASSERT(code <= code_next); + if(code < code_clear || code > code_next) { + break; + } + stack[GIF_MAX_LZW_CODE - 1 - stack_size++] = code_table[code].suffix; + code = code_table[code].prefix; + } + stack[GIF_MAX_LZW_CODE - 1 - stack_size++] = (FX_BYTE)code; + code_first = (FX_BYTE)code; +} +void CGifLZWDecoder::AddCode(FX_WORD prefix_code, FX_BYTE append_char) +{ + if(code_next == GIF_MAX_LZW_CODE) { + return; + } + code_table[code_next].prefix = prefix_code; + code_table[code_next].suffix = append_char; + if(++code_next < GIF_MAX_LZW_CODE) { + if(code_next >> code_size_cur) { + code_size_cur++; + } + } +} +FX_INT32 CGifLZWDecoder::Decode(FX_LPBYTE des_buf, FX_DWORD& des_size) +{ + if(des_size == 0) { + return 3; + } + FX_DWORD i = 0; + if(stack_size != 0) { + if(des_size < stack_size) { + FXSYS_memcpy32(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], des_size); + stack_size -= (FX_WORD)des_size; + return 3; + } + FXSYS_memcpy32(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], stack_size); + des_buf += stack_size; + i += stack_size; + stack_size = 0; + } + FX_WORD code = 0; + while(i <= des_size && (avail_in > 0 || bits_left >= code_size_cur)) { + if(code_size_cur > 12) { + if(err_msg_ptr) { + FXSYS_strncpy(err_msg_ptr, "Code Length Out Of Range", GIF_MAX_ERROR_SIZE - 1); + } + return 0; + } + if (avail_in > 0) { + code_store |= (*next_in++) << bits_left; + avail_in--; + bits_left += 8; + } + while (bits_left >= code_size_cur) { + code = (FX_WORD)code_store & ((1 << code_size_cur) - 1); + code_store >>= code_size_cur; + bits_left -= code_size_cur; + if(code == code_clear) { + ClearTable(); + continue; + } else if (code == code_end) { + des_size = i; + return 1; + } else { + if(code_old != (FX_WORD) - 1) { + if(code_next < GIF_MAX_LZW_CODE) { + if(code == code_next) { + AddCode(code_old, code_first); + DecodeString(code); + } else if(code > code_next) { + if(err_msg_ptr) { + FXSYS_strncpy(err_msg_ptr, "Decode Error, Out Of Range", GIF_MAX_ERROR_SIZE - 1); + } + return 0; + } else { + DecodeString(code); + FX_BYTE append_char = stack[GIF_MAX_LZW_CODE - stack_size]; + AddCode(code_old, append_char); + } + } + } else { + DecodeString(code); + } + code_old = code; + if(i + stack_size > des_size) { + FXSYS_memcpy32(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], des_size - i); + stack_size -= (FX_WORD)(des_size - i); + return 3; + } + FXSYS_memcpy32(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], stack_size); + des_buf += stack_size; + i += stack_size; + stack_size = 0; + } + } + } + if(avail_in == 0) { + des_size = i; + return 2; + } + return 0; +} +static FX_BOOL _gif_grow_buf(FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD size) +{ + if (dst_len < size) { + FX_DWORD len_org = dst_len; + while (dst_buf && dst_len < size) { + dst_len <<= 1; + dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_len); + } + if (dst_buf == NULL) { + dst_len = size; + dst_buf = FX_Realloc(FX_BYTE, dst_buf, dst_len); + if (dst_buf == NULL) { + return FALSE; + } + } + FXSYS_memset32(dst_buf + len_org, 0, dst_len - len_org); + return dst_buf != NULL; + } + return TRUE; +} +static inline void _gif_cut_index(FX_BYTE& val, FX_DWORD index, FX_BYTE index_bit, FX_BYTE index_bit_use, FX_BYTE bit_use) +{ + FX_DWORD cut = ((1 << (index_bit - index_bit_use)) - 1) << index_bit_use; + val |= ((index & cut) >> index_bit_use) << bit_use; +} +static inline FX_BYTE _gif_cut_buf(FX_LPCBYTE buf, FX_DWORD& offset, FX_BYTE bit_cut, FX_BYTE& bit_offset, FX_DWORD& bit_num) +{ + if (bit_cut != 8) { + FX_WORD index = 0; + index |= ((1 << bit_cut) - 1) << (7 - bit_offset); + FX_BYTE ret = ((index & buf[offset]) >> (7 - bit_offset)); + bit_offset += bit_cut; + if (bit_offset >= 8) { + if (bit_offset > 8) { + ret |= ((index & (buf[offset + 1] << 8)) >> 8); + } + bit_offset -= 8; + offset ++; + } + bit_num += bit_cut; + return ret; + } + bit_num += bit_cut; + return buf[offset++]; +} +CGifLZWEncoder::CGifLZWEncoder() +{ + FXSYS_memset32(this, 0, sizeof(CGifLZWEncoder)); +} +CGifLZWEncoder::~CGifLZWEncoder() +{ +} +void CGifLZWEncoder::ClearTable() +{ + index_bit_cur = code_size + 1; + index_num = code_end + 1; + table_cur = code_end + 1; + for (FX_WORD i = 0; i < GIF_MAX_LZW_CODE; i++) { + code_table[i].prefix = 0; + code_table[i].suffix = 0; + } +} +void CGifLZWEncoder::Start( FX_BYTE code_len, FX_LPCBYTE src_buf, FX_LPBYTE& dst_buf, FX_DWORD& offset) +{ + code_size = code_len + 1; + src_bit_cut = code_size; + if (code_len == 0) { + src_bit_cut = 1; + code_size = 2; + } + code_clear = 1 << code_size; + code_end = code_clear + 1; + dst_buf[offset++] = code_size; + bit_offset = 0; + ClearTable(); + src_offset = 0; + src_bit_offset = 0; + src_bit_num = 0; + code_table[index_num].prefix = _gif_cut_buf(src_buf, src_offset, src_bit_cut, src_bit_offset, src_bit_num); + code_table[index_num].suffix = _gif_cut_buf(src_buf, src_offset, src_bit_cut, src_bit_offset, src_bit_num); +} +void CGifLZWEncoder::WriteBlock(FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset) +{ + if (!_gif_grow_buf(dst_buf, dst_len, offset + GIF_DATA_BLOCK + 1)) { + longjmp(jmp, 1); + } + dst_buf[offset++] = index_buf_len; + FXSYS_memcpy32(&dst_buf[offset], index_buf, index_buf_len); + offset += index_buf_len; + FXSYS_memset32(index_buf, 0, GIF_DATA_BLOCK); + index_buf_len = 0; +} +void CGifLZWEncoder::EncodeString( FX_DWORD index, FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset ) +{ + FX_BYTE index_bit_use; + index_bit_use = 0; + if (index_buf_len == GIF_DATA_BLOCK) { + WriteBlock(dst_buf, dst_len, offset); + } + _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur, index_bit_use, bit_offset); + if (index_bit_cur <= (8 - bit_offset)) { + bit_offset += index_bit_cur; + } else if (index_bit_cur <= (16 - bit_offset)) { + index_bit_use += (8 - bit_offset); + bit_offset = 0; + index_buf_len++; + if (index_buf_len == GIF_DATA_BLOCK) { + WriteBlock(dst_buf, dst_len, offset); + } + _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur, index_bit_use, bit_offset); + bit_offset = index_bit_cur - index_bit_use; + } else { + index_bit_use += (8 - bit_offset); + bit_offset = 0; + index_buf_len++; + if (index_buf_len == GIF_DATA_BLOCK) { + WriteBlock(dst_buf, dst_len, offset); + } + _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur, index_bit_use, bit_offset); + index_bit_use += 8; + bit_offset = 0; + index_buf_len++; + if (index_buf_len == GIF_DATA_BLOCK) { + WriteBlock(dst_buf, dst_len, offset); + } + _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur, index_bit_use, bit_offset); + bit_offset = index_bit_cur - index_bit_use; + } + if (bit_offset == 8) { + bit_offset = 0; + index_buf_len++; + if (index_buf_len == GIF_DATA_BLOCK) { + WriteBlock(dst_buf, dst_len, offset); + } + } + if (index == code_end) { + index_buf_len++; + WriteBlock(dst_buf, dst_len, offset); + } + if (index_num++ >> index_bit_cur) { + index_bit_cur++; + } +} +FX_BOOL CGifLZWEncoder::Encode( FX_LPCBYTE src_buf, FX_DWORD src_len, FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset ) +{ + FX_BYTE suffix; + if (setjmp(jmp)) { + return FALSE; + } + while(src_bit_num < src_len) { + if (!LookUpInTable(src_buf, src_offset, src_bit_offset)) { + EncodeString(code_table[index_num].prefix, dst_buf, dst_len, offset); + if (index_num == GIF_MAX_LZW_CODE) { + suffix = code_table[index_num - 1].suffix; + EncodeString(code_clear, dst_buf, dst_len, offset); + ClearTable(); + code_table[index_num].prefix = suffix; + code_table[index_num].suffix = _gif_cut_buf(src_buf, src_offset, src_bit_cut, src_bit_offset, src_bit_num); + } else { + code_table[index_num].prefix = code_table[index_num - 1].suffix; + code_table[index_num].suffix = _gif_cut_buf(src_buf, src_offset, src_bit_cut, src_bit_offset, src_bit_num); + } + } + } + src_offset = 0; + src_bit_offset = 0; + src_bit_num = 0; + return TRUE; +} +FX_BOOL CGifLZWEncoder::LookUpInTable( FX_LPCBYTE buf, FX_DWORD& offset, FX_BYTE& bit_offset ) +{ + for (FX_WORD i = table_cur; i < index_num; i++) { + if (code_table[i].prefix == code_table[index_num].prefix && + code_table[i].suffix == code_table[index_num].suffix) { + code_table[index_num].prefix = i; + code_table[index_num].suffix = _gif_cut_buf(buf, offset, src_bit_cut, bit_offset, src_bit_num); + table_cur = i; + return TRUE; + } + } + table_cur = code_end + 1; + return FALSE; +} +void CGifLZWEncoder::Finish(FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset) +{ + EncodeString(code_table[index_num].prefix, dst_buf, dst_len, offset); + EncodeString(code_end, dst_buf, dst_len, offset); + bit_offset = 0; + ClearTable(); +} +gif_decompress_struct_p _gif_create_decompress() +{ + gif_decompress_struct_p gif_ptr = (gif_decompress_struct*)FX_Alloc(FX_BYTE, sizeof(gif_decompress_struct)); + if(gif_ptr == NULL) { + return NULL; + } + FXSYS_memset32(gif_ptr, 0, sizeof(gif_decompress_struct)); + gif_ptr->decode_status = GIF_D_STATUS_SIG; + gif_ptr->img_ptr_arr_ptr = FX_NEW CFX_ArrayTemplate; + if(gif_ptr->img_ptr_arr_ptr == NULL) { + FX_Free(gif_ptr); + return NULL; + } +#ifdef GIF_SUPPORT_COMMENT_EXTENSION + gif_ptr->cmt_data_ptr = FX_NEW CFX_ByteString; + if(gif_ptr->cmt_data_ptr == NULL) { + delete gif_ptr->img_ptr_arr_ptr; + FX_Free(gif_ptr); + return NULL; + } +#endif +#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION + gif_ptr->pt_ptr_arr_ptr = FX_NEW CFX_ArrayTemplate; + if(gif_ptr->pt_ptr_arr_ptr == NULL) { + delete(gif_ptr->cmt_data_ptr); + delete gif_ptr->img_ptr_arr_ptr; + FX_Free(gif_ptr); + return NULL; + } +#endif + return gif_ptr; +} +void _gif_destroy_decompress(gif_decompress_struct_pp gif_ptr_ptr) +{ + if(gif_ptr_ptr == NULL || *gif_ptr_ptr == NULL) { + return; + } + gif_decompress_struct_p gif_ptr = *gif_ptr_ptr; + *gif_ptr_ptr = NULL; + if(gif_ptr->global_pal_ptr != NULL) { + FX_Free(gif_ptr->global_pal_ptr); + } + if(gif_ptr->img_decoder_ptr != NULL) { + delete gif_ptr->img_decoder_ptr; + } + if(gif_ptr->img_ptr_arr_ptr != NULL) { + FX_INT32 size_img_arr = gif_ptr->img_ptr_arr_ptr->GetSize(); + for (FX_INT32 i = 0; i < size_img_arr; i++) { + GifImage* p = gif_ptr->img_ptr_arr_ptr->GetAt(i); + if(p->image_info_ptr != NULL) { + FX_Free(p->image_info_ptr); + } + if(p->image_gce_ptr != NULL) { + FX_Free(p->image_gce_ptr); + } + if(p->image_row_buf != NULL) { + FX_Free(p->image_row_buf); + } + if(p->local_pal_ptr != NULL && p->local_pal_ptr != gif_ptr->global_pal_ptr) { + FX_Free(p->local_pal_ptr); + } + FX_Free(p); + } + gif_ptr->img_ptr_arr_ptr->RemoveAll(); + delete gif_ptr->img_ptr_arr_ptr; + } +#ifdef GIF_SUPPORT_APPLICATION_EXTENSION + if(gif_ptr->app_data != NULL) { + FX_Free(gif_ptr->app_data); + } +#endif +#ifdef GIF_SUPPORT_COMMENT_EXTENSION + if(gif_ptr->cmt_data_ptr != NULL) { + delete gif_ptr->cmt_data_ptr; + } +#endif +#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION + if(gif_ptr->gce_ptr != NULL) { + FX_Free(gif_ptr->gce_ptr); + } +#endif +#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION + if(gif_ptr->pt_ptr_arr_ptr != NULL) { + FX_INT32 size_pt_arr = gif_ptr->pt_ptr_arr_ptr->GetSize(); + for (FX_INT32 i = 0; i < size_pt_arr; i++) { + GifPlainText* p = gif_ptr->pt_ptr_arr_ptr->GetAt(i); + if(p->gce_ptr != NULL) { + FX_Free(p->gce_ptr); + } + if(p->pte_ptr != NULL) { + FX_Free(p->pte_ptr); + } + if(p->string_ptr != NULL) { + delete p->string_ptr; + } + } + gif_ptr->pt_ptr_arr_ptr->RemoveAll(); + delete gif_ptr->pt_ptr_arr_ptr; + } +#endif + FX_Free(gif_ptr); +} +gif_compress_struct_p _gif_create_compress() +{ + gif_compress_struct_p gif_ptr = (gif_compress_struct*)FX_Alloc(FX_BYTE, sizeof(gif_compress_struct)); + if (gif_ptr == NULL) { + return NULL; + } + FXSYS_memset32(gif_ptr, 0, sizeof(gif_compress_struct)); + gif_ptr->img_encoder_ptr = FX_NEW CGifLZWEncoder; + if (gif_ptr->img_encoder_ptr == NULL) { + FX_Free(gif_ptr); + return NULL; + } + gif_ptr->header_ptr = (GifHeader*)FX_Alloc(FX_BYTE, sizeof(GifHeader)); + if (gif_ptr->header_ptr == NULL) { + delete(gif_ptr->img_encoder_ptr); + FX_Free(gif_ptr); + return NULL; + } + FXSYS_memcpy32(gif_ptr->header_ptr->signature, GIF_SIGNATURE, 3); + FXSYS_memcpy32(gif_ptr->header_ptr->version, "89a", 3); + gif_ptr->lsd_ptr = (GifLSD*)FX_Alloc(FX_BYTE, sizeof(GifLSD)); + if (gif_ptr->lsd_ptr == NULL) { + FX_Free(gif_ptr->header_ptr); + delete(gif_ptr->img_encoder_ptr); + FX_Free(gif_ptr); + return NULL; + } + FXSYS_memset32(gif_ptr->lsd_ptr, 0, sizeof(GifLSD)); + gif_ptr->image_info_ptr = (GifImageInfo*)FX_Alloc(FX_BYTE, sizeof(GifImageInfo)); + if (gif_ptr->image_info_ptr == NULL) { + FX_Free(gif_ptr->lsd_ptr); + FX_Free(gif_ptr->header_ptr); + delete(gif_ptr->img_encoder_ptr); + FX_Free(gif_ptr); + return NULL; + } + FXSYS_memset32(gif_ptr->image_info_ptr, 0, sizeof(GifImageInfo)); +#ifdef GIF_SUPPORT_APPLICATION_EXTENSION + FXSYS_memcpy32(gif_ptr->app_identify, "netscape", 8); + FXSYS_memcpy32(gif_ptr->app_authentication, "2.0", 3); +#endif +#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION + gif_ptr->gce_ptr = (GifGCE*)FX_Alloc(FX_BYTE, sizeof(GifGCE)); + if (gif_ptr->gce_ptr == NULL) { + FX_Free(gif_ptr->image_info_ptr); + FX_Free(gif_ptr->lsd_ptr); + FX_Free(gif_ptr->header_ptr); + delete(gif_ptr->img_encoder_ptr); + FX_Free(gif_ptr); + return NULL; + } +#endif +#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION + gif_ptr->pte_ptr = (GifPTE*)FX_Alloc(FX_BYTE, sizeof(GifPTE)); + if (gif_ptr->pte_ptr == NULL) { + FX_Free(gif_ptr->gce_ptr); + FX_Free(gif_ptr->image_info_ptr); + FX_Free(gif_ptr->lsd_ptr); + FX_Free(gif_ptr->header_ptr); + delete(gif_ptr->img_encoder_ptr); + FX_Free(gif_ptr); + return NULL; + } + FXSYS_memset32(gif_ptr->pte_ptr, 0, sizeof(GifPTE)); + gif_ptr->pte_ptr->block_size = 12; +#endif + return gif_ptr; +} +void _gif_destroy_compress(gif_compress_struct_pp gif_ptr_ptr) +{ + if(gif_ptr_ptr == NULL || *gif_ptr_ptr == NULL) { + return; + } + gif_compress_struct_p gif_ptr = *gif_ptr_ptr; + *gif_ptr_ptr = NULL; + if(gif_ptr->header_ptr != NULL) { + FX_Free(gif_ptr->header_ptr); + } + if(gif_ptr->lsd_ptr != NULL) { + FX_Free(gif_ptr->lsd_ptr); + } + if(gif_ptr->global_pal != NULL) { + FX_Free(gif_ptr->global_pal); + } + if(gif_ptr->image_info_ptr != NULL) { + FX_Free(gif_ptr->image_info_ptr); + } + if(gif_ptr->local_pal != NULL) { + FX_Free(gif_ptr->local_pal); + } + if(gif_ptr->img_encoder_ptr != NULL) { + delete gif_ptr->img_encoder_ptr; + } +#ifdef GIF_SUPPORT_APPLICATION_EXTENSION + if(gif_ptr->app_data != NULL) { + FX_Free(gif_ptr->app_data); + } +#endif +#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION + if(gif_ptr->gce_ptr != NULL) { + FX_Free(gif_ptr->gce_ptr); + } +#endif +#ifdef GIF_SUPPORT_COMMENT_EXTENSION + if(gif_ptr->cmt_data_ptr != NULL) { + FX_Free(gif_ptr->cmt_data_ptr); + } +#endif +#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION + if(gif_ptr->pte_ptr != NULL) { + FX_Free(gif_ptr->pte_ptr); + } +#endif + FX_Free(gif_ptr); +} +void _gif_error(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg) +{ + if(gif_ptr != NULL && gif_ptr->_gif_error_fn != NULL) { + gif_ptr->_gif_error_fn(gif_ptr, err_msg); + } +} +void _gif_warn(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg) {} +FX_INT32 _gif_read_header(gif_decompress_struct_p gif_ptr) +{ + if(gif_ptr == NULL) { + return 0; + } + FX_DWORD skip_size_org = gif_ptr->skip_size; + ASSERT(sizeof(GifHeader) == 6); + GifHeader* gif_header_ptr = NULL; + if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_header_ptr, 6) == NULL) { + return 2; + } + if(FXSYS_strncmp(gif_header_ptr->signature, GIF_SIGNATURE, 3) != 0 || + gif_header_ptr->version[0] != '8' || + gif_header_ptr->version[2] != 'a') { + _gif_error(gif_ptr, "Not A Gif Image"); + return 0; + } + ASSERT(sizeof(GifLSD) == 7); + GifLSD* gif_lsd_ptr = NULL; + if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_lsd_ptr, 7) == NULL) { + gif_ptr->skip_size = skip_size_org; + return 2; + } + if(((GifGF*)&gif_lsd_ptr->global_flag)->global_pal) { + gif_ptr->global_pal_num = 2 << ((GifGF*)&gif_lsd_ptr->global_flag)->pal_bits; + ASSERT(sizeof(GifPalette) == 3); + FX_INT32 global_pal_size = gif_ptr->global_pal_num * 3; + FX_LPBYTE global_pal_ptr = NULL; + if (_gif_read_data(gif_ptr, &global_pal_ptr, global_pal_size) == NULL) { + gif_ptr->skip_size = skip_size_org; + return 2; + } + gif_ptr->global_sort_flag = ((GifGF*)&gif_lsd_ptr->global_flag)->sort_flag; + gif_ptr->global_color_resolution = ((GifGF*)&gif_lsd_ptr->global_flag)->color_resolution; + if(gif_ptr->global_pal_ptr != NULL) { + FX_Free(gif_ptr->global_pal_ptr); + } + gif_ptr->global_pal_ptr = NULL; + gif_ptr->global_pal_ptr = (GifPalette*)FX_Alloc(FX_BYTE, global_pal_size); + GIF_PTR_NOT_NULL(gif_ptr->global_pal_ptr, gif_ptr); + FXSYS_memcpy32(gif_ptr->global_pal_ptr, global_pal_ptr, global_pal_size); + } + gif_ptr->width = (int)_GetWord_LSBFirst((FX_LPBYTE)&gif_lsd_ptr->width); + gif_ptr->height = (int)_GetWord_LSBFirst((FX_LPBYTE)&gif_lsd_ptr->height); + gif_ptr->bc_index = gif_lsd_ptr->bc_index; + gif_ptr->pixel_aspect = gif_lsd_ptr->pixel_aspect; + return 1; +} +FX_INT32 _gif_get_frame(gif_decompress_struct_p gif_ptr) +{ + if(gif_ptr == NULL) { + return 0; + } + FX_INT32 ret = 1; + while (TRUE) { + switch(gif_ptr->decode_status) { + case GIF_D_STATUS_TAIL: + return 1; + case GIF_D_STATUS_SIG: { + FX_LPBYTE sig_ptr = NULL; + if(_gif_read_data(gif_ptr, &sig_ptr, 1) == NULL) { + return 2; + } + switch(*sig_ptr) { + case GIF_SIG_EXTENSION: + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT); + continue; + case GIF_SIG_IMAGE: + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_INFO); + continue; + case GIF_SIG_TRAILER: + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL); + return 1; + default: + if (gif_ptr->avail_in) { + _gif_warn(gif_ptr, "The Gif File has non_standard Tag!"); + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_SIG); + continue; + } + _gif_warn(gif_ptr, "The Gif File Doesn't have Trailer Tag!"); + return 1; + } + } + case GIF_D_STATUS_EXT: { + FX_LPBYTE ext_ptr = NULL; + if(_gif_read_data(gif_ptr, &ext_ptr, 1) == NULL) { + return 2; + } + switch(*ext_ptr) { +#ifdef GIF_SUPPORT_APPLICATION_EXTENSION + case GIF_BLOCK_AE: + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_AE); + continue; +#endif +#ifdef GIF_SUPPORT_COMMENT_EXTENSION + case GIF_BLOCK_CE: + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_CE); + continue; +#endif +#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION + case GIF_BLOCK_GCE: + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_GCE); + continue; +#endif +#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION + case GIF_BLOCK_PTE: + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_PTE); + continue; +#endif + default: { + FX_INT32 status = GIF_D_STATUS_EXT_UNE; +#ifndef GIF_SUPPORT_PLAIN_TEXT_EXTENSION + if(*ext_ptr == GIF_BLOCK_PTE) { + status = GIF_D_STATUS_EXT_PTE; + } +#endif + _gif_save_decoding_status(gif_ptr, status); + continue; + } + } + } + case GIF_D_STATUS_IMG_INFO: { + ret = _gif_decode_image_info(gif_ptr); + if(ret != 1) { + return ret; + } + continue; + } + case GIF_D_STATUS_IMG_DATA: { + FX_LPBYTE data_size_ptr = NULL; + FX_LPBYTE data_ptr = NULL; + FX_DWORD skip_size_org = gif_ptr->skip_size; + if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) { + return 2; + } + while(*data_size_ptr != GIF_BLOCK_TERMINAL) { + if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL) { + gif_ptr->skip_size = skip_size_org; + return 2; + } + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA); + skip_size_org = gif_ptr->skip_size; + if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) { + return 2; + } + } + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_SIG); + continue; + } + default: { + ret = _gif_decode_extension(gif_ptr); + if(ret != 1) { + return ret; + } + continue; + } + } + } + return 1; +} +void _gif_takeover_gce_ptr(gif_decompress_struct_p gif_ptr, GifGCE** gce_ptr_ptr) +{ + *gce_ptr_ptr = NULL; +#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION + if(gif_ptr->gce_ptr != NULL && gce_ptr_ptr != NULL) { + *gce_ptr_ptr = gif_ptr->gce_ptr; + gif_ptr->gce_ptr = NULL; + } +#endif +} +FX_INT32 _gif_decode_extension(gif_decompress_struct_p gif_ptr) +{ + FX_LPBYTE data_size_ptr = NULL; + FX_LPBYTE data_ptr = NULL; + FX_DWORD skip_size_org = gif_ptr->skip_size; + switch(gif_ptr->decode_status) { +#ifdef GIF_SUPPORT_APPLICATION_EXTENSION + case GIF_D_STATUS_EXT_AE: { + ASSERT(sizeof(GifAE) == 12); + GifAE* gif_ae_ptr = NULL; + if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_ae_ptr, 12) == NULL) { + return 2; + } + CFX_ByteString gif_ae_data_str; + if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) { + gif_ptr->skip_size = skip_size_org; + return 2; + } + while(*data_size_ptr != GIF_BLOCK_TERMINAL) { + FX_BYTE data_size = *data_size_ptr; + if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL || + _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) { + gif_ptr->skip_size = skip_size_org; + return 2; + } + gif_ae_data_str += CFX_ByteString((FX_LPCBYTE)data_ptr, data_size); + } + FXSYS_memcpy32(gif_ptr->app_identify, gif_ae_ptr->app_identify, 8); + FXSYS_memcpy32(gif_ptr->app_authentication, gif_ae_ptr->app_authentication, 3); + gif_ptr->app_data_size = gif_ae_data_str.GetLength(); + if(gif_ptr->app_data != NULL) { + FX_Free(gif_ptr->app_data); + gif_ptr->app_data = NULL; + } + gif_ptr->app_data = FX_Alloc(FX_BYTE, gif_ptr->app_data_size); + GIF_PTR_NOT_NULL(gif_ptr->app_data, gif_ptr); + FXSYS_memcpy32(gif_ptr->app_data, FX_LPCBYTE(gif_ae_data_str), gif_ptr->app_data_size); + } + break; +#endif +#ifdef GIF_SUPPORT_COMMENT_EXTENSION + case GIF_D_STATUS_EXT_CE: { + if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) { + gif_ptr->skip_size = skip_size_org; + return 2; + } + gif_ptr->cmt_data_ptr->Empty(); + while(*data_size_ptr != GIF_BLOCK_TERMINAL) { + FX_BYTE data_size = *data_size_ptr; + if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL || + _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) { + gif_ptr->skip_size = skip_size_org; + return 2; + } + *(gif_ptr->cmt_data_ptr) += CFX_ByteString((FX_LPCSTR)data_ptr, data_size); + } + } + break; +#endif +#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION + case GIF_D_STATUS_EXT_PTE: { + ASSERT(sizeof(GifPTE) == 13); + GifPTE* gif_pte_ptr = NULL; + if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_pte_ptr, 13) == NULL) { + return 2; + } + GifPlainText* gif_pt_ptr = FX_Alloc(GifPlainText, 1); + GIF_PTR_NOT_NULL(gif_pt_ptr, gif_ptr); + FXSYS_memset32(gif_pt_ptr, 0, sizeof(GifPlainText)); + _gif_takeover_gce_ptr(gif_ptr, &gif_pt_ptr->gce_ptr); + gif_pt_ptr->pte_ptr = (GifPTE*)FX_Alloc(FX_BYTE, sizeof(GifPTE)); + GIF_PTR_NOT_NULL(gif_pt_ptr->pte_ptr, gif_ptr); + gif_pt_ptr->string_ptr = FX_NEW CFX_ByteString; + GIF_PTR_NOT_NULL(gif_pt_ptr->string_ptr, gif_ptr); + gif_pt_ptr->pte_ptr->block_size = gif_pte_ptr->block_size; + gif_pt_ptr->pte_ptr->grid_left = _GetWord_LSBFirst((FX_LPBYTE)&gif_pte_ptr->grid_left); + gif_pt_ptr->pte_ptr->grid_top = _GetWord_LSBFirst((FX_LPBYTE)&gif_pte_ptr->grid_top); + gif_pt_ptr->pte_ptr->grid_width = _GetWord_LSBFirst((FX_LPBYTE)&gif_pte_ptr->grid_width); + gif_pt_ptr->pte_ptr->grid_height = _GetWord_LSBFirst((FX_LPBYTE)&gif_pte_ptr->grid_height); + gif_pt_ptr->pte_ptr->char_width = gif_pte_ptr->char_width; + gif_pt_ptr->pte_ptr->char_height = gif_pte_ptr->char_height; + gif_pt_ptr->pte_ptr->fc_index = gif_pte_ptr->fc_index; + gif_pt_ptr->pte_ptr->bc_index = gif_pte_ptr->bc_index; + if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) { + gif_ptr->skip_size = skip_size_org; + if(gif_pt_ptr != NULL) { + if(gif_pt_ptr->gce_ptr != NULL) { + FX_Free(gif_pt_ptr->gce_ptr); + } + if(gif_pt_ptr->pte_ptr != NULL) { + FX_Free(gif_pt_ptr->pte_ptr); + } + if(gif_pt_ptr->string_ptr != NULL) { + delete gif_pt_ptr->string_ptr; + } + FX_Free(gif_pt_ptr); + } + return 2; + } + while(*data_size_ptr != GIF_BLOCK_TERMINAL) { + FX_BYTE data_size = *data_size_ptr; + if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL || + _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) { + gif_ptr->skip_size = skip_size_org; + if(gif_pt_ptr != NULL) { + if(gif_pt_ptr->gce_ptr != NULL) { + FX_Free(gif_pt_ptr->gce_ptr); + } + if(gif_pt_ptr->pte_ptr != NULL) { + FX_Free(gif_pt_ptr->pte_ptr); + } + if(gif_pt_ptr->string_ptr != NULL) { + delete gif_pt_ptr->string_ptr; + } + FX_Free(gif_pt_ptr); + } + return 2; + } + *(gif_pt_ptr->string_ptr) += CFX_ByteString((FX_LPCSTR)data_ptr, data_size); + } + gif_ptr->pt_ptr_arr_ptr->Add(gif_pt_ptr); + } + break; +#endif +#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION + case GIF_D_STATUS_EXT_GCE: { + ASSERT(sizeof(GifGCE) == 5); + GifGCE* gif_gce_ptr = NULL; + if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_gce_ptr, 6) == NULL) { + return 2; + } + if(gif_ptr->gce_ptr == NULL) { + gif_ptr->gce_ptr = (GifGCE*)FX_Alloc(FX_BYTE, sizeof(GifGCE)); + GIF_PTR_NOT_NULL(gif_ptr->gce_ptr, gif_ptr); + } + gif_ptr->gce_ptr->block_size = gif_gce_ptr->block_size; + gif_ptr->gce_ptr->gce_flag = gif_gce_ptr->gce_flag; + gif_ptr->gce_ptr->delay_time = _GetWord_LSBFirst((FX_LPBYTE)&gif_gce_ptr->delay_time); + gif_ptr->gce_ptr->trans_index = gif_gce_ptr->trans_index; + } + break; +#endif + default: { +#ifndef GIF_SUPPORT_PLAIN_TEXT_EXTENSION + if(gif_ptr->decode_status == GIF_D_STATUS_EXT_PTE) { +#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION + if(gif_ptr->gce_ptr != NULL) { + FX_Free(gif_ptr->gce_ptr); + gif_ptr->gce_ptr = NULL; + } +#endif + } +#endif + if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) { + return 2; + } + while(*data_size_ptr != GIF_BLOCK_TERMINAL) { + if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL || + _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL ) { + gif_ptr->skip_size = skip_size_org; + return 2; + } + } + } + } + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_SIG); + return 1; +} +FX_INT32 _gif_decode_image_info(gif_decompress_struct_p gif_ptr) +{ + if(gif_ptr->width == 0 || gif_ptr->height == 0) { + _gif_error(gif_ptr, "No Image Header Info"); + return 0; + } + FX_DWORD skip_size_org = gif_ptr->skip_size; + ASSERT(sizeof(GifImageInfo) == 9); + GifImageInfo* gif_img_info_ptr = NULL; + if(_gif_read_data(gif_ptr, (FX_LPBYTE*)&gif_img_info_ptr, 9) == NULL) { + return 2; + } + GifImage* gif_image_ptr = (GifImage*)FX_Alloc(FX_BYTE, sizeof(GifImage)); + GIF_PTR_NOT_NULL(gif_image_ptr, gif_ptr); + FXSYS_memset32(gif_image_ptr, 0, sizeof(GifImage)); + gif_image_ptr->image_info_ptr = (GifImageInfo*)FX_Alloc(FX_BYTE, sizeof(GifImageInfo)); + GIF_PTR_NOT_NULL(gif_image_ptr->image_info_ptr, gif_ptr); + gif_image_ptr->image_info_ptr->left = _GetWord_LSBFirst((FX_LPBYTE)&gif_img_info_ptr->left); + gif_image_ptr->image_info_ptr->top = _GetWord_LSBFirst((FX_LPBYTE)&gif_img_info_ptr->top); + gif_image_ptr->image_info_ptr->width = _GetWord_LSBFirst((FX_LPBYTE)&gif_img_info_ptr->width); + gif_image_ptr->image_info_ptr->height = _GetWord_LSBFirst((FX_LPBYTE)&gif_img_info_ptr->height); + gif_image_ptr->image_info_ptr->local_flag = gif_img_info_ptr->local_flag; + if(gif_image_ptr->image_info_ptr->left + gif_image_ptr->image_info_ptr->width > gif_ptr->width || + gif_image_ptr->image_info_ptr->top + gif_image_ptr->image_info_ptr->height > gif_ptr->height) { + if(gif_image_ptr->image_info_ptr != NULL) { + FX_Free(gif_image_ptr->image_info_ptr); + } + if(gif_image_ptr->image_row_buf != NULL) { + FX_Free(gif_image_ptr->image_row_buf); + } + FX_Free(gif_image_ptr); + _gif_error(gif_ptr, "Image Data Out Of LSD, The File May Be Corrupt"); + return 0; + } + GifLF* gif_img_info_lf_ptr = (GifLF*)&gif_img_info_ptr->local_flag; + if(gif_img_info_lf_ptr->local_pal) { + ASSERT(sizeof(GifPalette) == 3); + FX_INT32 loc_pal_size = (2 << gif_img_info_lf_ptr->pal_bits) * 3; + FX_LPBYTE loc_pal_ptr = NULL; + if(_gif_read_data(gif_ptr, &loc_pal_ptr, loc_pal_size) == NULL) { + gif_ptr->skip_size = skip_size_org; + if(gif_image_ptr->image_info_ptr != NULL) { + FX_Free(gif_image_ptr->image_info_ptr); + } + if(gif_image_ptr->image_row_buf != NULL) { + FX_Free(gif_image_ptr->image_row_buf); + } + FX_Free(gif_image_ptr); + return 2; + } + gif_image_ptr->local_pal_ptr = (GifPalette*)gif_ptr->_gif_ask_buf_for_pal_fn(gif_ptr, loc_pal_size); + if(gif_image_ptr->local_pal_ptr != NULL) { + FXSYS_memcpy32((FX_LPBYTE)gif_image_ptr->local_pal_ptr, loc_pal_ptr, loc_pal_size); + } + } + FX_LPBYTE code_size_ptr = NULL; + if(_gif_read_data(gif_ptr, &code_size_ptr, 1) == NULL) { + gif_ptr->skip_size = skip_size_org; + if(gif_image_ptr->image_info_ptr != NULL) { + FX_Free(gif_image_ptr->image_info_ptr); + } + if(gif_image_ptr->local_pal_ptr != NULL) { + FX_Free(gif_image_ptr->local_pal_ptr); + } + if(gif_image_ptr->image_row_buf != NULL) { + FX_Free(gif_image_ptr->image_row_buf); + } + FX_Free(gif_image_ptr); + return 2; + } + gif_image_ptr->image_code_size = *code_size_ptr; + gif_ptr->_gif_record_current_position_fn(gif_ptr, &gif_image_ptr->image_data_pos); + gif_image_ptr->image_data_pos += gif_ptr->skip_size; + _gif_takeover_gce_ptr(gif_ptr, &gif_image_ptr->image_gce_ptr); + gif_ptr->img_ptr_arr_ptr->Add(gif_image_ptr); + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA); + return 1; +} +FX_INT32 _gif_load_frame(gif_decompress_struct_p gif_ptr, FX_INT32 frame_num) +{ + if(gif_ptr == NULL || + frame_num < 0 || + frame_num >= gif_ptr->img_ptr_arr_ptr->GetSize() + ) { + return 0; + } + FX_LPBYTE data_size_ptr = NULL; + FX_LPBYTE data_ptr = NULL; + FX_DWORD skip_size_org = gif_ptr->skip_size; + GifImage* gif_image_ptr = gif_ptr->img_ptr_arr_ptr->GetAt(frame_num); + FX_DWORD gif_img_row_bytes = gif_image_ptr->image_info_ptr->width; + if(gif_ptr->decode_status == GIF_D_STATUS_TAIL) { + if(gif_image_ptr->image_row_buf) { + FX_Free(gif_image_ptr->image_row_buf); + gif_image_ptr->image_row_buf = NULL; + } + gif_image_ptr->image_row_buf = FX_Alloc(FX_BYTE, gif_img_row_bytes); + GIF_PTR_NOT_NULL(gif_image_ptr->image_row_buf, gif_ptr); + GifGCE* gif_img_gce_ptr = gif_image_ptr->image_gce_ptr; + FX_INT32 loc_pal_num = ((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->local_pal ? + (2 << ((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->pal_bits) : 0; + gif_ptr->avail_in = 0; + if(gif_img_gce_ptr == NULL) { + FX_BOOL bRes = gif_ptr->_gif_get_record_position_fn(gif_ptr, gif_image_ptr->image_data_pos, + gif_image_ptr->image_info_ptr->left, + gif_image_ptr->image_info_ptr->top, + gif_image_ptr->image_info_ptr->width, + gif_image_ptr->image_info_ptr->height, + loc_pal_num, gif_image_ptr->local_pal_ptr, + 0, 0, -1, 0, + (FX_BOOL)((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->interlace + ); + if(!bRes) { + FX_Free(gif_image_ptr->image_row_buf); + gif_image_ptr->image_row_buf = NULL; + _gif_error(gif_ptr, "Error Read Record Position Data"); + return 0; + } + } else { + FX_BOOL bRes = gif_ptr->_gif_get_record_position_fn(gif_ptr, gif_image_ptr->image_data_pos, + gif_image_ptr->image_info_ptr->left, + gif_image_ptr->image_info_ptr->top, + gif_image_ptr->image_info_ptr->width, + gif_image_ptr->image_info_ptr->height, + loc_pal_num, gif_image_ptr->local_pal_ptr, + (FX_INT32)gif_image_ptr->image_gce_ptr->delay_time, + (FX_BOOL)((GifCEF*)&gif_image_ptr->image_gce_ptr->gce_flag)->user_input, + ((GifCEF*)&gif_image_ptr->image_gce_ptr->gce_flag)->transparency ? + (FX_INT32)gif_image_ptr->image_gce_ptr->trans_index : -1, + (FX_INT32)((GifCEF*)&gif_image_ptr->image_gce_ptr->gce_flag)->disposal_method, + (FX_BOOL)((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->interlace + ); + if(!bRes) { + FX_Free(gif_image_ptr->image_row_buf); + gif_image_ptr->image_row_buf = NULL; + _gif_error(gif_ptr, "Error Read Record Position Data"); + return 0; + } + } + if(gif_ptr->img_decoder_ptr == NULL) { + gif_ptr->img_decoder_ptr = FX_NEW CGifLZWDecoder(gif_ptr->err_ptr); + GIF_PTR_NOT_NULL(gif_ptr->img_decoder_ptr, gif_ptr); + } + gif_ptr->img_decoder_ptr->InitTable(gif_image_ptr->image_code_size); + gif_ptr->img_row_offset = 0; + gif_ptr->img_row_avail_size = 0; + gif_ptr->img_pass_num = 0; + gif_image_ptr->image_row_num = 0; + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA); + } + CGifLZWDecoder* img_decoder_ptr = gif_ptr->img_decoder_ptr; + if(gif_ptr->decode_status == GIF_D_STATUS_IMG_DATA) { + if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) { + return 2; + } + if(*data_size_ptr != GIF_BLOCK_TERMINAL) { + if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL) { + gif_ptr->skip_size = skip_size_org; + return 2; + } + img_decoder_ptr->Input(data_ptr, *data_size_ptr); + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA); + gif_ptr->img_row_offset += gif_ptr->img_row_avail_size; + gif_ptr->img_row_avail_size = gif_img_row_bytes - gif_ptr->img_row_offset; + FX_INT32 ret = img_decoder_ptr->Decode(gif_image_ptr->image_row_buf + gif_ptr->img_row_offset, gif_ptr->img_row_avail_size); + if(ret == 0) { + FX_Free(gif_image_ptr->image_row_buf); + gif_image_ptr->image_row_buf = NULL; + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL); + _gif_error(gif_ptr, "Decode Image Data Error"); + return 0; + } + while (ret != 0) { + if(ret == 1) { + gif_ptr->_gif_get_row_fn(gif_ptr, gif_image_ptr->image_row_num, gif_image_ptr->image_row_buf); + FX_Free(gif_image_ptr->image_row_buf); + gif_image_ptr->image_row_buf = NULL; + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL); + return 1; + } + if(ret == 2) { + ASSERT(img_decoder_ptr->GetAvailInput() == 0); + skip_size_org = gif_ptr->skip_size; + if(_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) { + return 2; + } + if (*data_size_ptr != GIF_BLOCK_TERMINAL) { + if(_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL) { + gif_ptr->skip_size = skip_size_org; + return 2; + } + img_decoder_ptr->Input(data_ptr, *data_size_ptr); + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA); + gif_ptr->img_row_offset += gif_ptr->img_row_avail_size; + gif_ptr->img_row_avail_size = gif_img_row_bytes - gif_ptr->img_row_offset; + ret = img_decoder_ptr->Decode(gif_image_ptr->image_row_buf + gif_ptr->img_row_offset, gif_ptr->img_row_avail_size); + } + } + if(ret == 3) { + if(((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->interlace) { + gif_ptr->_gif_get_row_fn(gif_ptr, gif_image_ptr->image_row_num, gif_image_ptr->image_row_buf); + gif_image_ptr->image_row_num += s_gif_interlace_step[gif_ptr->img_pass_num]; + if(gif_image_ptr->image_row_num >= (FX_INT32)gif_image_ptr->image_info_ptr->height) { + gif_ptr->img_pass_num++; + gif_image_ptr->image_row_num = s_gif_interlace_step[gif_ptr->img_pass_num] / 2; + } + } else { + gif_ptr->_gif_get_row_fn(gif_ptr, gif_image_ptr->image_row_num++, gif_image_ptr->image_row_buf); + } + gif_ptr->img_row_offset = 0; + gif_ptr->img_row_avail_size = gif_img_row_bytes; + ret = img_decoder_ptr->Decode(gif_image_ptr->image_row_buf + gif_ptr->img_row_offset, gif_ptr->img_row_avail_size); + } + if(ret == 0) { + FX_Free(gif_image_ptr->image_row_buf); + gif_image_ptr->image_row_buf = NULL; + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL); + _gif_error(gif_ptr, "Decode Image Data Error"); + return 0; + } + } + } + _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL); + } + _gif_error(gif_ptr, "Decode Image Data Error"); + return 0; +} +void _gif_save_decoding_status(gif_decompress_struct_p gif_ptr, FX_INT32 status) +{ + gif_ptr->decode_status = status; + gif_ptr->next_in += gif_ptr->skip_size; + gif_ptr->avail_in -= gif_ptr->skip_size; + gif_ptr->skip_size = 0; +} +FX_LPBYTE _gif_read_data(gif_decompress_struct_p gif_ptr, FX_LPBYTE* des_buf_pp, FX_DWORD data_size) +{ + if(gif_ptr == NULL || + gif_ptr->avail_in < gif_ptr->skip_size + data_size) { + return NULL; + } + *des_buf_pp = gif_ptr->next_in + gif_ptr->skip_size; + gif_ptr->skip_size += data_size; + return *des_buf_pp; +} +void _gif_input_buffer(gif_decompress_struct_p gif_ptr, FX_LPBYTE src_buf, FX_DWORD src_size) +{ + gif_ptr->next_in = src_buf; + gif_ptr->avail_in = src_size; + gif_ptr->skip_size = 0; +} +FX_DWORD _gif_get_avail_input(gif_decompress_struct_p gif_ptr, FX_LPBYTE* avial_buf_ptr) +{ + if(avial_buf_ptr != NULL) { + *avial_buf_ptr = NULL; + if(gif_ptr->avail_in > 0) { + *avial_buf_ptr = gif_ptr->next_in; + } + } + return gif_ptr->avail_in; +} +FX_INT32 _gif_get_frame_num(gif_decompress_struct_p gif_ptr) +{ + return gif_ptr->img_ptr_arr_ptr->GetSize(); +} +static FX_BOOL _gif_write_header( gif_compress_struct_p gif_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_len ) +{ + if (gif_ptr->cur_offset) { + return TRUE; + } + dst_len = sizeof(GifHeader) + sizeof(GifLSD) + sizeof(GifGF); + dst_buf = FX_AllocNL(FX_BYTE, dst_len); + if (dst_buf == NULL) { + return FALSE; + } + FXSYS_memset32(dst_buf, 0, dst_len); + FXSYS_memcpy32(dst_buf, gif_ptr->header_ptr, sizeof(GifHeader)); + gif_ptr->cur_offset += sizeof(GifHeader); + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->lsd_ptr->width); + gif_ptr->cur_offset += 2; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->lsd_ptr->height); + gif_ptr->cur_offset += 2; + dst_buf[gif_ptr->cur_offset++] = gif_ptr->lsd_ptr->global_flag; + dst_buf[gif_ptr->cur_offset++] = gif_ptr->lsd_ptr->bc_index; + dst_buf[gif_ptr->cur_offset++] = gif_ptr->lsd_ptr->pixel_aspect; + if (gif_ptr->global_pal) { + FX_WORD size = sizeof(GifPalette) * gif_ptr->gpal_num; + if (!_gif_grow_buf(dst_buf, dst_len, gif_ptr->cur_offset + size)) { + return FALSE; + } + FXSYS_memcpy32(&dst_buf[gif_ptr->cur_offset], gif_ptr->global_pal, size); + gif_ptr->cur_offset += size; + } + return TRUE; +} +void interlace_buf(FX_LPCBYTE buf, FX_DWORD pitch, FX_DWORD height) +{ + CFX_ArrayTemplate pass[4]; + int i, j; + FX_DWORD row; + row = 0; + FX_LPBYTE temp; + while (row < height) { + if (row % 8 == 0) { + j = 0; + } else if (row % 4 == 0) { + j = 1; + } else if (row % 2 == 0) { + j = 2; + } else { + j = 3; + } + temp = FX_Alloc(FX_BYTE, pitch); + if (temp == NULL) { + return; + } + FXSYS_memcpy32(temp, &buf[pitch * row], pitch); + pass[j].Add(temp); + row ++; + } + for (i = 0, row = 0; i < 4; i++) { + for (j = 0; j < pass[i].GetSize(); j++, row++) { + FXSYS_memcpy32((FX_LPBYTE)&buf[pitch * row], pass[i].GetAt(j), pitch); + FX_Free(pass[i].GetAt(j)); + } + } +} +static void _gif_write_block_data(FX_LPCBYTE src_buf, FX_DWORD src_len, FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& dst_offset) +{ + FX_DWORD src_offset = 0; + while (src_len > GIF_DATA_BLOCK) { + dst_buf[dst_offset++] = GIF_DATA_BLOCK; + FXSYS_memcpy32(&dst_buf[dst_offset], &src_buf[src_offset], GIF_DATA_BLOCK); + dst_offset += GIF_DATA_BLOCK; + src_offset += GIF_DATA_BLOCK; + src_len -= GIF_DATA_BLOCK; + } + dst_buf[dst_offset++] = (FX_BYTE)src_len; + FXSYS_memcpy32(&dst_buf[dst_offset], &src_buf[src_offset], src_len); + dst_offset += src_len; +} +static FX_BOOL _gif_write_data( gif_compress_struct_p gif_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_len ) +{ + if (!_gif_grow_buf(dst_buf, dst_len, gif_ptr->cur_offset + GIF_DATA_BLOCK)) { + return FALSE; + } +#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION + if (FXSYS_memcmp32(gif_ptr->header_ptr->version, "89a", 3) == 0) { + dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION; + dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_GCE; + gif_ptr->gce_ptr->block_size = 4; + dst_buf[gif_ptr->cur_offset++] = gif_ptr->gce_ptr->block_size; + gif_ptr->gce_ptr->gce_flag = 0; + dst_buf[gif_ptr->cur_offset++] = gif_ptr->gce_ptr->gce_flag; + gif_ptr->gce_ptr->delay_time = 10; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->gce_ptr->delay_time); + gif_ptr->cur_offset += 2; + gif_ptr->gce_ptr->trans_index = 0; + dst_buf[gif_ptr->cur_offset++] = gif_ptr->gce_ptr->trans_index; + dst_buf[gif_ptr->cur_offset++] = 0; + } +#endif + dst_buf[gif_ptr->cur_offset++] = GIF_SIG_IMAGE; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->image_info_ptr->left); + gif_ptr->cur_offset += 2; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->image_info_ptr->top); + gif_ptr->cur_offset += 2; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->image_info_ptr->width); + gif_ptr->cur_offset += 2; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->image_info_ptr->height); + gif_ptr->cur_offset += 2; + GifLF& lf = (GifLF&)gif_ptr->image_info_ptr->local_flag; + dst_buf[gif_ptr->cur_offset++] = gif_ptr->image_info_ptr->local_flag; + if (gif_ptr->local_pal) { + FX_DWORD pal_size = sizeof(GifPalette) * gif_ptr->lpal_num; + if (!_gif_grow_buf(dst_buf, dst_len, pal_size + gif_ptr->cur_offset)) { + return FALSE; + } + FXSYS_memcpy32(&dst_buf[gif_ptr->cur_offset], gif_ptr->local_pal, pal_size); + gif_ptr->cur_offset += pal_size; + } + if (lf.interlace) { + interlace_buf(gif_ptr->src_buf, gif_ptr->src_pitch, gif_ptr->image_info_ptr->height); + } + FX_BYTE code_bit = lf.pal_bits; + if (lf.local_pal == 0) { + GifGF& gf = (GifGF&)gif_ptr->lsd_ptr->global_flag; + code_bit = gf.pal_bits; + } + gif_ptr->img_encoder_ptr->Start(code_bit, gif_ptr->src_buf, dst_buf, gif_ptr->cur_offset); + FX_DWORD i; + for (i = 0; i < gif_ptr->src_row; i++) { + if (!gif_ptr->img_encoder_ptr->Encode(&gif_ptr->src_buf[i * gif_ptr->src_pitch], gif_ptr->src_width * (code_bit + 1), + dst_buf, dst_len, gif_ptr->cur_offset)) { + return FALSE; + } + } + gif_ptr->img_encoder_ptr->Finish(dst_buf, dst_len, gif_ptr->cur_offset); + dst_buf[gif_ptr->cur_offset++] = 0; +#ifdef GIF_SUPPORT_COMMENT_EXTENSION + if (FXSYS_memcmp32(gif_ptr->header_ptr->version, "89a", 3) == 0 && gif_ptr->cmt_data_ptr) { + dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION; + dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_CE; + _gif_write_block_data(gif_ptr->cmt_data_ptr, gif_ptr->cmt_data_len, dst_buf, dst_len, gif_ptr->cur_offset); + dst_buf[gif_ptr->cur_offset++] = 0; + } +#endif +#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION + if (FXSYS_memcmp32(gif_ptr->header_ptr->version, "89a", 3) == 0 && gif_ptr->pte_data_ptr) { + dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION; + dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_PTE; + dst_buf[gif_ptr->cur_offset++] = gif_ptr->pte_ptr->block_size; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->grid_left); + gif_ptr->cur_offset += 2; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->grid_top); + gif_ptr->cur_offset += 2; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->grid_width); + gif_ptr->cur_offset += 2; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->grid_height); + gif_ptr->cur_offset += 2; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->char_width); + gif_ptr->cur_offset += 2; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->char_height); + gif_ptr->cur_offset += 2; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->fc_index); + gif_ptr->cur_offset += 2; + _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->pte_ptr->bc_index); + gif_ptr->cur_offset += 2; + _gif_write_block_data(gif_ptr->pte_data_ptr, gif_ptr->pte_data_len, dst_buf, dst_len, gif_ptr->cur_offset); + gif_ptr->cur_offset += gif_ptr->pte_data_len; + dst_buf[gif_ptr->cur_offset++] = 0; + } +#endif +#ifdef GIF_SUPPORT_APPLICATION_EXTENSION + if (FXSYS_memcmp32(gif_ptr->header_ptr->version, "89a", 3) == 0 && gif_ptr->app_data) { + dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION; + dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_AE; + dst_buf[gif_ptr->cur_offset++] = 11; + FXSYS_memcpy32(&dst_buf[gif_ptr->cur_offset], gif_ptr->app_identify, 8); + gif_ptr->cur_offset += 8; + FXSYS_memcpy32(&dst_buf[gif_ptr->cur_offset], gif_ptr->app_authentication, 8); + gif_ptr->cur_offset += 3; + FXSYS_memcpy32(&dst_buf[gif_ptr->cur_offset], gif_ptr->app_data, gif_ptr->app_data_size); + gif_ptr->cur_offset += gif_ptr->app_data_size; + dst_buf[gif_ptr->cur_offset++] = 0; + } +#endif + dst_buf[gif_ptr->cur_offset++] = GIF_SIG_TRAILER; + return TRUE; +} +FX_BOOL _gif_encode( gif_compress_struct_p gif_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_len ) +{ + if (!_gif_write_header(gif_ptr, dst_buf, dst_len)) { + return FALSE; + } + FX_DWORD cur_offset = gif_ptr->cur_offset; + FX_BOOL res = TRUE; + if (gif_ptr->frames) { + gif_ptr->cur_offset--; + } + if (!_gif_write_data(gif_ptr, dst_buf, dst_len)) { + gif_ptr->cur_offset = cur_offset; + res = FALSE; + } + dst_len = gif_ptr->cur_offset; + dst_buf[dst_len - 1] = GIF_SIG_TRAILER; + if (res) { + gif_ptr->frames++; + } + return res; +} diff --git a/core/src/fxcodec/lgif/fx_gif.h b/core/src/fxcodec/lgif/fx_gif.h new file mode 100644 index 0000000000..b499a542b6 --- /dev/null +++ b/core/src/fxcodec/lgif/fx_gif.h @@ -0,0 +1,307 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef _FX_BASIC_H_ +#include "../../../include/fxcrt/fx_basic.h" +#endif +extern FX_WORD _GetWord_LSBFirst(FX_LPBYTE p); +extern void _SetWord_LSBFirst(FX_LPBYTE p, FX_WORD v); +extern void _BpcConvert(FX_LPCBYTE src_buf, FX_DWORD src_len, FX_INT32 src_bpc, FX_INT32 dst_bpc, + FX_LPBYTE& dst_buf, FX_DWORD& dst_len); +#define GIF_SUPPORT_COMMENT_EXTENSION +#define GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION +#define GIF_SUPPORT_PLAIN_TEXT_EXTENSION +#define GIF_SIGNATURE "GIF" +#define GIF_SIG_EXTENSION 0x21 +#define GIF_SIG_IMAGE 0x2C +#define GIF_SIG_TRAILER 0x3B +#define GIF_BLOCK_GCE 0xF9 +#define GIF_BLOCK_PTE 0x01 +#define GIF_BLOCK_CE 0xFE +#define GIF_BLOCK_AE 0xFF +#define GIF_BLOCK_TERMINAL 0x00 +#define GIF_MAX_LZW_CODE 4096 +#define GIF_DATA_BLOCK 255 +#define GIF_MAX_ERROR_SIZE 256 +#define GIF_D_STATUS_SIG 0x01 +#define GIF_D_STATUS_TAIL 0x02 +#define GIF_D_STATUS_EXT 0x03 +#define GIF_D_STATUS_EXT_AE 0x04 +#define GIF_D_STATUS_EXT_CE 0x05 +#define GIF_D_STATUS_EXT_GCE 0x06 +#define GIF_D_STATUS_EXT_PTE 0x07 +#define GIF_D_STATUS_EXT_UNE 0x08 +#define GIF_D_STATUS_IMG_INFO 0x09 +#define GIF_D_STATUS_IMG_DATA 0x0A +#pragma pack(1) +typedef struct tagGifGF { + FX_BYTE pal_bits : 3; + FX_BYTE sort_flag : 1; + FX_BYTE color_resolution : 3; + FX_BYTE global_pal : 1; +} GifGF; +typedef struct tagGifLF { + FX_BYTE pal_bits : 3; + FX_BYTE reserved : 2; + FX_BYTE sort_flag : 1; + FX_BYTE interlace : 1; + FX_BYTE local_pal : 1; +} GifLF; +typedef struct tagGifHeader { + char signature[3]; + char version[3]; +} GifHeader; +typedef struct tagGifLSD { + FX_WORD width; + FX_WORD height; + FX_BYTE global_flag; + FX_BYTE bc_index; + FX_BYTE pixel_aspect; +} GifLSD; +typedef struct tagGifImageInfo { + FX_WORD left; + FX_WORD top; + FX_WORD width; + FX_WORD height; + + FX_BYTE local_flag; +} GifImageInfo; +typedef struct tagGifCEF { + FX_BYTE transparency : 1; + FX_BYTE user_input : 1; + FX_BYTE disposal_method : 3; + FX_BYTE reserved : 3; +} GifCEF; +typedef struct tagGifGCE { + FX_BYTE block_size; + FX_BYTE gce_flag; + FX_WORD delay_time; + FX_BYTE trans_index; +} GifGCE; +typedef struct tagGifPTE { + FX_BYTE block_size; + FX_WORD grid_left; + FX_WORD grid_top; + FX_WORD grid_width; + FX_WORD grid_height; + + FX_BYTE char_width; + FX_BYTE char_height; + + FX_BYTE fc_index; + FX_BYTE bc_index; +} GifPTE; +typedef struct tagGifAE { + FX_BYTE block_size; + FX_BYTE app_identify[8]; + FX_BYTE app_authentication[3]; +} GifAE; +typedef struct tagGifPalette { + FX_BYTE r, g, b; +} GifPalette; +#pragma pack() +typedef struct tagGifImage { + GifGCE* image_gce_ptr; + GifPalette* local_pal_ptr; + GifImageInfo* image_info_ptr; + FX_BYTE image_code_size; + FX_DWORD image_data_pos; + FX_LPBYTE image_row_buf; + FX_INT32 image_row_num; +} GifImage; +typedef struct tagGifPlainText { + GifGCE* gce_ptr; + GifPTE* pte_ptr; + CFX_ByteString* string_ptr; +} GifPlainText; +class CGifLZWDecoder : public CFX_Object +{ +public: + struct tag_Table { + FX_WORD prefix; + FX_BYTE suffix; + }; + CGifLZWDecoder(FX_LPSTR error_ptr = NULL) + { + err_msg_ptr = error_ptr; + } + void InitTable(FX_BYTE code_len); + + FX_INT32 Decode(FX_LPBYTE des_buf, FX_DWORD& des_size); + + void Input(FX_LPBYTE src_buf, FX_DWORD src_size); + FX_DWORD GetAvailInput(); + +private: + void ClearTable(); + void AddCode(FX_WORD prefix_code, FX_BYTE append_char); + void DecodeString(FX_WORD code); + FX_BYTE code_size; + FX_BYTE code_size_cur; + FX_WORD code_clear; + FX_WORD code_end; + FX_WORD code_next; + FX_BYTE code_first; + FX_BYTE stack[GIF_MAX_LZW_CODE]; + FX_WORD stack_size; + tag_Table code_table[GIF_MAX_LZW_CODE]; + FX_WORD code_old; + + FX_LPBYTE next_in; + FX_DWORD avail_in; + + FX_BYTE bits_left; + FX_DWORD code_store; + + FX_LPSTR err_msg_ptr; +}; +class CGifLZWEncoder : public CFX_Object +{ +public: + struct tag_Table { + FX_WORD prefix; + FX_BYTE suffix; + }; + CGifLZWEncoder(); + ~CGifLZWEncoder(); + void Start(FX_BYTE code_len, FX_LPCBYTE src_buf, FX_LPBYTE& dst_buf, FX_DWORD& offset); + FX_BOOL Encode(FX_LPCBYTE src_buf, FX_DWORD src_len, FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset); + void Finish(FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset); +private: + void ClearTable(); + FX_BOOL LookUpInTable(FX_LPCBYTE buf, FX_DWORD& offset, FX_BYTE& bit_offset); + void EncodeString(FX_DWORD index, FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset); + void WriteBlock(FX_LPBYTE& dst_buf, FX_DWORD& dst_len, FX_DWORD& offset); + jmp_buf jmp; + FX_DWORD src_offset; + FX_BYTE src_bit_offset; + FX_BYTE src_bit_cut; + FX_DWORD src_bit_num; + FX_BYTE code_size; + FX_WORD code_clear; + FX_WORD code_end; + FX_WORD index_num; + FX_BYTE bit_offset; + FX_BYTE index_bit_cur; + FX_BYTE index_buf[GIF_DATA_BLOCK]; + FX_BYTE index_buf_len; + tag_Table code_table[GIF_MAX_LZW_CODE]; + FX_WORD table_cur; +}; +typedef struct tag_gif_decompress_struct gif_decompress_struct; +typedef gif_decompress_struct *gif_decompress_struct_p; +typedef gif_decompress_struct_p *gif_decompress_struct_pp; +static FX_INT32 s_gif_interlace_step[4] = {8, 8, 4, 2}; +struct tag_gif_decompress_struct { + jmp_buf jmpbuf; + FX_LPSTR err_ptr; + void (*_gif_error_fn)(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg); + void* context_ptr; + int width; + int height; + GifPalette* global_pal_ptr; + FX_INT32 global_pal_num; + FX_BYTE global_sort_flag; + FX_BYTE global_color_resolution; + + FX_BYTE bc_index; + FX_BYTE pixel_aspect; + CGifLZWDecoder* img_decoder_ptr; + FX_DWORD img_row_offset; + FX_DWORD img_row_avail_size; + FX_BYTE img_pass_num; + CFX_ArrayTemplate* img_ptr_arr_ptr; + FX_LPBYTE (*_gif_ask_buf_for_pal_fn)(gif_decompress_struct_p gif_ptr, FX_INT32 pal_size); + FX_LPBYTE next_in; + FX_DWORD avail_in; + FX_INT32 decode_status; + FX_DWORD skip_size; + void (*_gif_record_current_position_fn)(gif_decompress_struct_p gif_ptr, FX_DWORD* cur_pos_ptr); + void (*_gif_get_row_fn)(gif_decompress_struct_p gif_ptr, FX_INT32 row_num, FX_LPBYTE row_buf); + FX_BOOL (*_gif_get_record_position_fn)(gif_decompress_struct_p gif_ptr, FX_DWORD cur_pos, + FX_INT32 left, FX_INT32 top, FX_INT32 width, FX_INT32 height, + FX_INT32 pal_num, void* pal_ptr, + FX_INT32 delay_time, FX_BOOL user_input, + FX_INT32 trans_index, FX_INT32 disposal_method, FX_BOOL interlace); +#ifdef GIF_SUPPORT_APPLICATION_EXTENSION + FX_BYTE app_identify[8]; + FX_BYTE app_authentication[3]; + FX_DWORD app_data_size; + FX_LPBYTE app_data; +#endif +#ifdef GIF_SUPPORT_COMMENT_EXTENSION + CFX_ByteString* cmt_data_ptr; +#endif +#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION + GifGCE* gce_ptr; +#endif +#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION + CFX_ArrayTemplate* pt_ptr_arr_ptr; +#endif +}; +typedef struct tag_gif_compress_struct gif_compress_struct; +typedef gif_compress_struct *gif_compress_struct_p; +typedef gif_compress_struct_p *gif_compress_struct_pp; +struct tag_gif_compress_struct { + FX_LPCBYTE src_buf; + FX_DWORD src_pitch; + FX_DWORD src_width; + FX_DWORD src_row; + FX_DWORD cur_offset; + FX_DWORD frames; + GifHeader* header_ptr; + GifLSD* lsd_ptr; + GifPalette* global_pal; + FX_WORD gpal_num; + GifPalette* local_pal; + FX_WORD lpal_num; + GifImageInfo* image_info_ptr; + CGifLZWEncoder* img_encoder_ptr; +#ifdef GIF_SUPPORT_APPLICATION_EXTENSION + FX_BYTE app_identify[8]; + FX_BYTE app_authentication[3]; + FX_DWORD app_data_size; + FX_LPBYTE app_data; +#endif + +#ifdef GIF_SUPPORT_COMMENT_EXTENSION + FX_LPBYTE cmt_data_ptr; + FX_DWORD cmt_data_len; +#endif + +#ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION + GifGCE* gce_ptr; +#endif + +#ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION + GifPTE* pte_ptr; + FX_LPCBYTE pte_data_ptr; + FX_DWORD pte_data_len; +#endif +}; +void _gif_error(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg); +void _gif_warn(gif_decompress_struct_p gif_ptr, FX_LPCSTR err_msg); +gif_decompress_struct_p _gif_create_decompress(); +void _gif_destroy_decompress(gif_decompress_struct_pp gif_ptr_ptr); +gif_compress_struct_p _gif_create_compress(); +void _gif_destroy_compress(gif_compress_struct_pp gif_ptr_ptr); +FX_INT32 _gif_read_header(gif_decompress_struct_p gif_ptr); +FX_INT32 _gif_get_frame(gif_decompress_struct_p gif_ptr); +FX_INT32 _gif_get_frame_num(gif_decompress_struct_p gif_ptr); +FX_INT32 _gif_decode_extension(gif_decompress_struct_p gif_ptr); +FX_INT32 _gif_decode_image_info(gif_decompress_struct_p gif_ptr); +void _gif_takeover_gce_ptr(gif_decompress_struct_p gif_ptr, GifGCE** gce_ptr_ptr); +FX_INT32 _gif_load_frame(gif_decompress_struct_p gif_ptr, FX_INT32 frame_num); +FX_LPBYTE _gif_read_data(gif_decompress_struct_p gif_ptr, FX_LPBYTE* des_buf_pp, FX_DWORD data_size); +void _gif_save_decoding_status(gif_decompress_struct_p gif_ptr, FX_INT32 status); +void _gif_input_buffer(gif_decompress_struct_p gif_ptr, FX_LPBYTE src_buf, FX_DWORD src_size); +FX_DWORD _gif_get_avail_input(gif_decompress_struct_p gif_ptr, FX_LPBYTE* avial_buf_ptr); +void interlace_buf(FX_LPCBYTE buf, FX_DWORD width, FX_DWORD height); +FX_BOOL _gif_encode( gif_compress_struct_p gif_ptr, FX_LPBYTE& dst_buf, FX_DWORD& dst_len ); +#define GIF_PTR_NOT_NULL(ptr,gif_ptr) if(ptr == NULL){ \ + _gif_error(gif_ptr,"Out Of Memory");\ + return 0; \ + } diff --git a/core/src/fxcrt/extension.h b/core/src/fxcrt/extension.h index c23a2e3369..05aad67e40 100644 --- a/core/src/fxcrt/extension.h +++ b/core/src/fxcrt/extension.h @@ -26,6 +26,44 @@ public: virtual FX_BOOL Truncate(FX_FILESIZE szFile) = 0; }; IFXCRT_FileAccess* FXCRT_FileAccess_Create(); +class CFX_CRTFileAccess : public IFX_FileAccess, public CFX_Object +{ +public: + CFX_CRTFileAccess() : m_RefCount(0) {} + + virtual void Release() + { + if (--m_RefCount == 0) + delete this; + } + + IFX_FileAccess* Retain() + { + m_RefCount++; + return (IFX_FileAccess*)this; + } + + virtual FX_BOOL Init(FX_WSTR wsPath) + { + m_path = wsPath; + m_RefCount = 1; + return TRUE; + } + + virtual void GetPath(CFX_WideString& wsPath) + { + wsPath = m_path; + } + + virtual IFX_FileStream* CreateFileStream(FX_DWORD dwModes) + { + return FX_CreateFileStream(m_path, dwModes); + } + +protected: + CFX_WideString m_path; + FX_DWORD m_RefCount; +}; class CFX_CRTFileStream FX_FINAL : public IFX_FileStream, public CFX_Object { public: diff --git a/core/src/fxcrt/fx_arabic.cpp b/core/src/fxcrt/fx_arabic.cpp index 583ce817cf..dd5d1d81bd 100644 --- a/core/src/fxcrt/fx_arabic.cpp +++ b/core/src/fxcrt/fx_arabic.cpp @@ -7,6 +7,1084 @@ #include "../../include/fxcrt/fx_ext.h" #include "fx_arabic.h" extern const FX_DWORD gs_FX_TextLayout_CodeProperties[65536]; +#ifdef __cplusplus +extern "C" { +#endif +static const FX_ARBFORMTABLE g_FX_ArabicFormTables[] = { + {0xFE81, 0xFE82, 0xFE81, 0xFE82}, + {0xFE83, 0xFE84, 0xFE83, 0xFE84}, + {0xFE85, 0xFE86, 0xFE85, 0xFE86}, + {0xFE87, 0xFE88, 0xFE87, 0xFE88}, + {0xFE89, 0xFE8A, 0xFE8B, 0xFE8C}, + {0xFE8D, 0xFE8E, 0xFE8D, 0xFE8E}, + {0xFE8F, 0xFE90, 0xFE91, 0xFE92}, + {0xFE93, 0xFE94, 0xFE93, 0xFE94}, + {0xFE95, 0xFE96, 0xFE97, 0xFE98}, + {0xFE99, 0xFE9A, 0xFE9B, 0xFE9C}, + {0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0}, + {0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4}, + {0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8}, + {0xFEA9, 0xFEAA, 0xFEA9, 0xFEAA}, + {0xFEAB, 0xFEAC, 0xFEAB, 0xFEAC}, + {0xFEAD, 0xFEAE, 0xFEAD, 0xFEAE}, + {0xFEAF, 0xFEB0, 0xFEAF, 0xFEB0}, + {0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4}, + {0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8}, + {0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC}, + {0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0}, + {0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4}, + {0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8}, + {0xFEC9, 0xFECA, 0xFECB, 0xFECC}, + {0xFECD, 0xFECE, 0xFECF, 0xFED0}, + {0x063B, 0x063B, 0x063B, 0x063B}, + {0x063C, 0x063C, 0x063C, 0x063C}, + {0x063D, 0x063D, 0x063D, 0x063D}, + {0x063E, 0x063E, 0x063E, 0x063E}, + {0x063F, 0x063F, 0x063F, 0x063F}, + {0x0640, 0x0640, 0x0640, 0x0640}, + {0xFED1, 0xFED2, 0xFED3, 0xFED4}, + {0xFED5, 0xFED6, 0xFED7, 0xFED8}, + {0xFED9, 0xFEDA, 0xFEDB, 0xFEDC}, + {0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0}, + {0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4}, + {0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8}, + {0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC}, + {0xFEED, 0xFEEE, 0xFEED, 0xFEEE}, + {0xFEEF, 0xFEF0, 0xFBFE, 0xFBFF}, + {0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4}, + {0x064B, 0x064B, 0x064B, 0x064B}, + {0x064C, 0x064C, 0x064C, 0x064C}, + {0x064D, 0x064D, 0x064D, 0x064D}, + {0x064E, 0x064E, 0x064E, 0x064E}, + {0x064F, 0x064F, 0x064F, 0x064F}, + {0x0650, 0x0650, 0x0650, 0x0650}, + {0x0651, 0x0651, 0x0651, 0x0651}, + {0x0652, 0x0652, 0x0652, 0x0652}, + {0x0653, 0x0653, 0x0653, 0x0653}, + {0x0654, 0x0654, 0x0654, 0x0654}, + {0x0655, 0x0655, 0x0655, 0x0655}, + {0x0656, 0x0656, 0x0656, 0x0656}, + {0x0657, 0x0657, 0x0657, 0x0657}, + {0x0658, 0x0658, 0x0658, 0x0658}, + {0x0659, 0x0659, 0x0659, 0x0659}, + {0x065A, 0x065A, 0x065A, 0x065A}, + {0x065B, 0x065B, 0x065B, 0x065B}, + {0x065C, 0x065C, 0x065C, 0x065C}, + {0x065D, 0x065D, 0x065D, 0x065D}, + {0x065E, 0x065E, 0x065E, 0x065E}, + {0x065F, 0x065F, 0x065F, 0x065F}, + {0x0660, 0x0660, 0x0660, 0x0660}, + {0x0661, 0x0661, 0x0661, 0x0661}, + {0x0662, 0x0662, 0x0662, 0x0662}, + {0x0663, 0x0663, 0x0663, 0x0663}, + {0x0664, 0x0664, 0x0664, 0x0664}, + {0x0665, 0x0665, 0x0665, 0x0665}, + {0x0666, 0x0666, 0x0666, 0x0666}, + {0x0667, 0x0667, 0x0667, 0x0667}, + {0x0668, 0x0668, 0x0668, 0x0668}, + {0x0669, 0x0669, 0x0669, 0x0669}, + {0x066A, 0x066A, 0x066A, 0x066A}, + {0x066B, 0x066B, 0x066B, 0x066B}, + {0x066C, 0x066C, 0x066C, 0x066C}, + {0x066D, 0x066D, 0x066D, 0x066D}, + {0x066E, 0x066E, 0x066E, 0x066E}, + {0x066F, 0x066F, 0x066F, 0x066F}, + {0x0670, 0x0670, 0x0670, 0x0670}, + {0xFB50, 0xFB51, 0xFB50, 0xFB51}, + {0x0672, 0x0672, 0x0672, 0x0672}, + {0x0673, 0x0673, 0x0673, 0x0673}, + {0x0674, 0x0674, 0x0674, 0x0674}, + {0x0675, 0x0675, 0x0675, 0x0675}, + {0x0676, 0x0676, 0x0676, 0x0676}, + {0x0677, 0x0677, 0x0677, 0x0677}, + {0x0678, 0x0678, 0x0678, 0x0678}, + {0xFB66, 0xFB67, 0xFB68, 0xFB69}, + {0xFB5E, 0xFB5F, 0xFB60, 0xFB61}, + {0xFB52, 0xFB53, 0xFB54, 0xFB55}, + {0x067C, 0x067C, 0x067C, 0x067C}, + {0x067D, 0x067D, 0x067D, 0x067D}, + {0xFB56, 0xFB57, 0xFB58, 0xFB59}, + {0xFB62, 0xFB63, 0xFB64, 0xFB65}, + {0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D}, + {0x0681, 0x0681, 0x0681, 0x0681}, + {0x0682, 0x0682, 0x0682, 0x0682}, + {0xFB76, 0xFB77, 0xFB78, 0xFB79}, + {0xFB72, 0xFB73, 0xFB74, 0xFB75}, + {0x0685, 0x0685, 0x0685, 0x0685}, + {0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D}, + {0xFB7E, 0xFB7F, 0xFB80, 0xFB81}, + {0xFB88, 0xFB89, 0xFB88, 0xFB89}, + {0x0689, 0x0689, 0x0689, 0x0689}, + {0x068A, 0x068A, 0x068A, 0x068A}, + {0x068B, 0x068B, 0x068B, 0x068B}, + {0xFB84, 0xFB85, 0xFB84, 0xFB85}, + {0xFB82, 0xFB83, 0xFB82, 0xFB83}, + {0xFB86, 0xFB87, 0xFB86, 0xFB87}, + {0x068F, 0x068F, 0x068F, 0x068F}, + {0x0690, 0x0690, 0x0690, 0x0690}, + {0xFB8C, 0xFB8D, 0xFB8C, 0xFB8D}, + {0x0692, 0x0692, 0x0692, 0x0692}, + {0x0693, 0x0693, 0x0693, 0x0693}, + {0x0694, 0x0694, 0x0694, 0x0694}, + {0x0695, 0x0695, 0x0695, 0x0695}, + {0x0696, 0x0696, 0x0696, 0x0696}, + {0x0697, 0x0697, 0x0697, 0x0697}, + {0xFB8A, 0xFB8B, 0xFB8A, 0xFB8B}, + {0x0699, 0x0699, 0x0699, 0x0699}, + {0x069A, 0x069A, 0x069A, 0x069A}, + {0x069B, 0x069B, 0x069B, 0x069B}, + {0x069C, 0x069C, 0x069C, 0x069C}, + {0x069D, 0x069D, 0x069D, 0x069D}, + {0x069E, 0x069E, 0x069E, 0x069E}, + {0x069F, 0x069F, 0x069F, 0x069F}, + {0x06A0, 0x06A0, 0x06A0, 0x06A0}, + {0x06A1, 0x06A1, 0x06A1, 0x06A1}, + {0x06A2, 0x06A2, 0x06A2, 0x06A2}, + {0x06A3, 0x06A3, 0x06A3, 0x06A3}, + {0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D}, + {0x06A5, 0x06A5, 0x06A5, 0x06A5}, + {0xFB6E, 0xFB6F, 0xFB70, 0xFB71}, + {0x06A7, 0x06A7, 0x06A7, 0x06A7}, + {0x06A8, 0x06A8, 0x06A8, 0x06A8}, + {0xFB8E, 0xFB8F, 0xFB90, 0xFB91}, + {0x06AA, 0x06AA, 0x06AA, 0x06AA}, + {0x06AB, 0x06AB, 0x06AB, 0x06AB}, + {0x06AC, 0x06AC, 0x06AC, 0x06AC}, + {0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6}, + {0x06AE, 0x06AE, 0x06AE, 0x06AE}, + {0xFB92, 0xFB93, 0xFB94, 0xFB95}, + {0x06B0, 0x06B0, 0x06B0, 0x06B0}, + {0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D}, + {0x06B2, 0x06B2, 0x06B2, 0x06B2}, + {0xFB96, 0xFB97, 0xFB98, 0xFB99}, + {0x06B4, 0x06B4, 0x06B4, 0x06B4}, + {0x06B5, 0x06B5, 0x06B5, 0x06B5}, + {0x06B6, 0x06B6, 0x06B6, 0x06B6}, + {0x06B7, 0x06B7, 0x06B7, 0x06B7}, + {0x06B8, 0x06B8, 0x06B8, 0x06B8}, + {0x06B9, 0x06B9, 0x06B9, 0x06B9}, + {0xFB9E, 0xFB9F, 0xFBE8, 0xFBE9}, + {0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3}, + {0x06BC, 0x06BC, 0x06BC, 0x06BC}, + {0x06BD, 0x06BD, 0x06BD, 0x06BD}, + {0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD}, + {0x06BF, 0x06BF, 0x06BF, 0x06BF}, + {0xFBA4, 0xFBA5, 0xFBA4, 0xFBA5}, + {0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9}, + {0x06C2, 0x06C2, 0x06C2, 0x06C2}, + {0x06C3, 0x06C3, 0x06C3, 0x06C3}, + {0x06C4, 0x06C4, 0x06C4, 0x06C4}, + {0xFBE0, 0xFBE1, 0xFBE0, 0xFBE1}, + {0xFBD9, 0xFBDA, 0xFBD9, 0xFBDA}, + {0xFBD7, 0xFBD8, 0xFBD7, 0xFBD8}, + {0xFBDB, 0xFBDC, 0xFBDB, 0xFBDC}, + {0xFBE2, 0xFBE3, 0xFBE2, 0xFBE3}, + {0x06CA, 0x06CA, 0x06CA, 0x06CA}, + {0xFBDE, 0xFBDF, 0xFBDE, 0xFBDF}, + {0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF}, + {0x06CD, 0x06CD, 0x06CD, 0x06CD}, + {0x06CE, 0x06CE, 0x06CE, 0x06CE}, + {0x06CF, 0x06CF, 0x06CF, 0x06CF}, + {0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7}, + {0x06D1, 0x06D1, 0x06D1, 0x06D1}, + {0xFBAE, 0xFBAF, 0xFBAE, 0xFBAF}, + {0xFBB0, 0xFBB1, 0xFBB0, 0xFBB1}, + {0x06D4, 0x06D4, 0x06D4, 0x06D4}, + {0x06D5, 0x06D5, 0x06D5, 0x06D5}, +}; +static const FX_ARAALEF gs_FX_AlefTable[] = { + {0x0622, 0xFEF5}, + {0x0623, 0xFEF7}, + {0x0625, 0xFEF9}, + {0x0627, 0xFEFB}, +}; +static const FX_ARASHADDA gs_FX_ShaddaTable[] = { + {0x064C, 0xFC5E}, + {0x064D, 0xFC5F}, + {0x064E, 0xFC60}, + {0x064F, 0xFC61}, + {0x0650, 0xFC62}, +}; +FX_LPCARBFORMTABLE FX_GetArabicFormTable(FX_WCHAR unicode) +{ + if (unicode < 0x622 || unicode > 0x6d5) { + return NULL; + } + return g_FX_ArabicFormTables + unicode - 0x622; +} +FX_WCHAR FX_GetArabicFromAlefTable(FX_WCHAR alef) +{ + static const FX_INT32 s_iAlefCount = sizeof(gs_FX_AlefTable) / sizeof(FX_ARAALEF); + for (FX_INT32 iStart = 0; iStart < s_iAlefCount; iStart ++) { + const FX_ARAALEF &v = gs_FX_AlefTable[iStart]; + if (v.wAlef == alef) { + return v.wIsolated; + } + } + return alef; +} +FX_WCHAR FX_GetArabicFromShaddaTable(FX_WCHAR shadda) +{ + static const FX_INT32 s_iShaddaCount = sizeof(gs_FX_ShaddaTable) / sizeof(FX_ARASHADDA); + for (FX_INT32 iStart = 0; iStart < s_iShaddaCount; iStart ++) { + const FX_ARASHADDA &v = gs_FX_ShaddaTable[iStart]; + if (v.wShadda == shadda) { + return v.wIsolated; + } + } + return shadda; +} +#ifdef __cplusplus +}; +#endif +IFX_ArabicChar* IFX_ArabicChar::Create() +{ + return FX_NEW CFX_ArabicChar; +} +FX_BOOL CFX_ArabicChar::IsArabicChar(FX_WCHAR wch) const +{ + FX_DWORD dwRet = (gs_FX_TextLayout_CodeProperties[(FX_WORD)wch] & FX_CHARTYPEBITSMASK); + return dwRet >= FX_CHARTYPE_ArabicAlef; +} +FX_BOOL CFX_ArabicChar::IsArabicFormChar(FX_WCHAR wch) const +{ + return (gs_FX_TextLayout_CodeProperties[(FX_WORD)wch] & FX_CHARTYPEBITSMASK) == FX_CHARTYPE_ArabicForm; +} +FX_WCHAR CFX_ArabicChar::GetFormChar(FX_WCHAR wch, FX_WCHAR prev, FX_WCHAR next) const +{ + CFX_Char c(wch, gs_FX_TextLayout_CodeProperties[(FX_WORD)wch]); + CFX_Char p(prev, gs_FX_TextLayout_CodeProperties[(FX_WORD)prev]); + CFX_Char n(next, gs_FX_TextLayout_CodeProperties[(FX_WORD)next]); + return GetFormChar(&c, &p, &n); +} +FX_WCHAR CFX_ArabicChar::GetFormChar(const CFX_Char *cur, const CFX_Char *prev, const CFX_Char *next) const +{ + FX_CHARTYPE eCur; + FX_WCHAR wCur; + FX_LPCARBFORMTABLE ft = ParseChar(cur, wCur, eCur); + if (eCur < FX_CHARTYPE_ArabicAlef || eCur >= FX_CHARTYPE_ArabicNormal) { + return wCur; + } + FX_CHARTYPE ePrev; + FX_WCHAR wPrev; + ParseChar(prev, wPrev, ePrev); + if (wPrev == 0x0644 && eCur == FX_CHARTYPE_ArabicAlef) { + return 0xFEFF; + } + FX_CHARTYPE eNext; + FX_WCHAR wNext; + ParseChar(next, wNext, eNext); + FX_BOOL bAlef = (eNext == FX_CHARTYPE_ArabicAlef && wCur == 0x644); + if (ePrev < FX_CHARTYPE_ArabicAlef) { + if (bAlef) { + return FX_GetArabicFromAlefTable(wNext); + } else { + return (eNext < FX_CHARTYPE_ArabicAlef) ? ft->wIsolated : ft->wInitial; + } + } else { + if (bAlef) { + wCur = FX_GetArabicFromAlefTable(wNext); + return (ePrev != FX_CHARTYPE_ArabicDistortion) ? wCur : ++ wCur; + } else if (ePrev == FX_CHARTYPE_ArabicAlef || ePrev == FX_CHARTYPE_ArabicSpecial) { + return (eNext < FX_CHARTYPE_ArabicAlef) ? ft->wIsolated : ft->wInitial; + } else { + return (eNext < FX_CHARTYPE_ArabicAlef) ? ft->wFinal : ft->wMedial; + } + } +} +FX_LPCARBFORMTABLE CFX_ArabicChar::ParseChar(const CFX_Char *pTC, FX_WCHAR &wChar, FX_CHARTYPE &eType) const +{ + if (pTC == NULL) { + eType = FX_CHARTYPE_Unknown; + wChar = 0xFEFF; + return NULL; + } + eType = (FX_CHARTYPE)pTC->GetCharType(); + wChar = (FX_WCHAR)pTC->m_wCharCode; + FX_LPCARBFORMTABLE pFT = FX_GetArabicFormTable(wChar); + if (pFT == NULL || eType >= FX_CHARTYPE_ArabicNormal) { + eType = FX_CHARTYPE_Unknown; + } + return pFT; +} +void FX_BidiReverseString(CFX_WideString &wsText, FX_INT32 iStart, FX_INT32 iCount) +{ + FXSYS_assert(iStart > -1 && iStart < wsText.GetLength()); + FXSYS_assert(iCount >= 0 && iStart + iCount <= wsText.GetLength()); + FX_WCHAR wch; + FX_LPWSTR pStart = (FX_LPWSTR)(FX_LPCWSTR)wsText; + pStart += iStart; + FX_LPWSTR pEnd = pStart + iCount - 1; + while (pStart < pEnd) { + wch = *pStart; + *pStart ++ = *pEnd; + *pEnd -- = wch; + } +} +void FX_BidiSetDeferredRun(CFX_Int32Array &values, FX_INT32 iStart, FX_INT32 iCount, FX_INT32 iValue) +{ + FXSYS_assert(iStart > -1 && iStart <= values.GetSize()); + FXSYS_assert(iStart - iCount > -1); + for (FX_INT32 i = iStart - 1; i >= iStart - iCount; i --) { + values.SetAt(i, iValue); + } +} +const FX_INT32 gc_FX_BidiNTypes[] = { + FX_BIDICLASS_N, + FX_BIDICLASS_L, + FX_BIDICLASS_R, + FX_BIDICLASS_AN, + FX_BIDICLASS_EN, + FX_BIDICLASS_AL, + FX_BIDICLASS_NSM, + FX_BIDICLASS_CS, + FX_BIDICLASS_ES, + FX_BIDICLASS_ET, + FX_BIDICLASS_BN, + FX_BIDICLASS_BN, + FX_BIDICLASS_N, + FX_BIDICLASS_B, + FX_BIDICLASS_RLO, + FX_BIDICLASS_RLE, + FX_BIDICLASS_LRO, + FX_BIDICLASS_LRE, + FX_BIDICLASS_PDF, + FX_BIDICLASS_ON, +}; +void FX_BidiClassify(const CFX_WideString &wsText, CFX_Int32Array &classes, FX_BOOL bWS) +{ + FXSYS_assert(wsText.GetLength() == classes.GetSize()); + FX_INT32 iCount = wsText.GetLength(); + FX_LPCWSTR pwsStart = (FX_LPCWSTR)wsText; + FX_WCHAR wch; + FX_INT32 iCls; + if (bWS) { + for (FX_INT32 i = 0; i < iCount; i ++) { + wch = *pwsStart ++; + iCls = ((gs_FX_TextLayout_CodeProperties[(FX_WORD)wch] & FX_BIDICLASSBITSMASK) >> FX_BIDICLASSBITS); + classes.SetAt(i, iCls); + } + } else { + for (FX_INT32 i = 0; i < iCount; i ++) { + wch = *pwsStart ++; + iCls = ((gs_FX_TextLayout_CodeProperties[(FX_WORD)wch] & FX_BIDICLASSBITSMASK) >> FX_BIDICLASSBITS); + classes.SetAt(i, gc_FX_BidiNTypes[iCls]); + } + } +} +FX_INT32 FX_BidiResolveExplicit(FX_INT32 iBaseLevel, FX_INT32 iDirection, CFX_Int32Array &classes, CFX_Int32Array &levels, FX_INT32 iStart, FX_INT32 iCount, FX_INT32 iNest) +{ + FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL && iNest >= 0); + FXSYS_assert(classes.GetSize() == levels.GetSize()); + FXSYS_assert(iStart >= 0 && iStart < classes.GetSize()); + FXSYS_assert(iCount >= 0 && iStart + iCount <= classes.GetSize()); + if (iCount < 1) { + return 0; + } +#if 0 + FX_INT32 iLastNest = iNest; +#endif + FX_INT32 iSize = classes.GetSize(); + FX_INT32 i = iStart, iCur, iCls; + for (; i < iSize && iCount > 0; i ++, iCount --) { + iCur = iCls = classes.GetAt(i); +#if 0 + switch (iCls) { + case FX_BIDICLASS_LRO: + case FX_BIDICLASS_LRE: + classes.SetAt(i, FX_BIDICLASS_BN); + iCls = FX_BIDICLASS_BN; + iNest ++; + if (FX_BidiGreaterEven(iBaseLevel) <= MAX_LEVEL) { + FX_INT32 iLevel = FX_BidiGreaterEven(iBaseLevel); + levels.SetAt(i, iLevel); + i += FX_BidiResolveExplicit(iLevel, + (iCls == FX_BIDICLASS_LRE ? FX_BIDICLASS_N : FX_BIDICLASS_L), + classes, + levels, + i + 1, + iCount - 1, + iNest); + iNest --; + continue; + } + break; + case FX_BIDICLASS_RLO: + case FX_BIDICLASS_RLE: + classes.SetAt(i, FX_BIDICLASS_BN); + iCls = FX_BIDICLASS_BN; + iNest ++; + if (FX_BidiGreaterOdd(iBaseLevel) <= MAX_LEVEL) { + FX_INT32 iLevel = FX_BidiGreaterOdd(iBaseLevel); + levels.SetAt(i, iLevel); + i += FX_BidiResolveExplicit(iLevel, + (iCls == FX_BIDICLASS_RLE ? FX_BIDICLASS_N : FX_BIDICLASS_R), + classes, + levels, + i + 1, + iCount - 1, + iNest); + iNest --; + continue; + } + break; + case FX_BIDICLASS_PDF: + classes.SetAt(i, FX_BIDICLASS_BN); + iCls = FX_BIDICLASS_BN; + if (iNest) { + if (iLastNest < iNest) { + iNest --; + } else { + iSize = i; + } + } + break; + } + iCur = iCls; +#endif + if (iDirection != FX_BIDICLASS_N) { + iCls = iDirection; + } + if (iCur != FX_BIDICLASS_BN) { + classes.SetAt(i, iCls); + } + levels.SetAt(i, iBaseLevel); + } + return i - iStart; +} +const FX_INT32 gc_FX_BidiWeakStates[][10] = { + {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSxa, FX_BWSao, FX_BWSao, FX_BWSao}, + {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSxr, FX_BWSro, FX_BWSro, FX_BWSrt}, + {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSxl, FX_BWSlo, FX_BWSlo, FX_BWSlt}, + {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSao, FX_BWSao, FX_BWSao, FX_BWSao}, + {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro, FX_BWSro, FX_BWSro, FX_BWSrt}, + {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo, FX_BWSlo, FX_BWSlo, FX_BWSlt}, + {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSrt, FX_BWSro, FX_BWSro, FX_BWSrt}, + {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlt, FX_BWSlo, FX_BWSlo, FX_BWSlt}, + {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWScn, FX_BWSac, FX_BWSao, FX_BWSao}, + {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSra, FX_BWSrc, FX_BWSro, FX_BWSrt}, + {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSre, FX_BWSrs, FX_BWSrs, FX_BWSret}, + {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSla, FX_BWSlc, FX_BWSlo, FX_BWSlt}, + {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSle, FX_BWSls, FX_BWSls, FX_BWSlet}, + {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSao, FX_BWSao, FX_BWSao, FX_BWSao}, + {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro, FX_BWSro, FX_BWSro, FX_BWSrt}, + {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro, FX_BWSro, FX_BWSro, FX_BWSrt}, + {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo, FX_BWSlo, FX_BWSlo, FX_BWSlt}, + {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo, FX_BWSlo, FX_BWSlo, FX_BWSlt}, + {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSret, FX_BWSro, FX_BWSro, FX_BWSret}, + {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlet, FX_BWSlo, FX_BWSlo, FX_BWSlet}, +}; +const FX_INT32 gc_FX_BidiWeakActions[][10] = { + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR, FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR, FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR, FX_BWAxxL, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx}, + {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAExE, FX_BWANxR, FX_BWAxIx, FX_BWANxN, FX_BWANxN, FX_BWAxIx}, + {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWALxL, FX_BWANxR, FX_BWAxIx, FX_BWANxN, FX_BWANxN, FX_BWAxIx}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR, FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxxN}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR, FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxIx}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR, FX_BWAxxE, FX_BWAxIx, FX_BWAxIx, FX_BWAxxE}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR, FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxIx}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR, FX_BWAxxL, FX_BWAxIx, FX_BWAxIx, FX_BWAxxL}, + {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWAAxA, FX_BWANxR, FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANxN}, + {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWANxE, FX_BWANxR, FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx}, + {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAExE, FX_BWANxR, FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx}, + {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWANxL, FX_BWANxR, FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx}, + {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWALxL, FX_BWANxR, FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR, FX_BWAxxE, FX_BWAxxN, FX_BWAxxN, FX_BWAxxE}, + {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR, FX_BWAxxL, FX_BWAxxN, FX_BWAxxN, FX_BWAxxL}, +}; +void FX_BidiResolveWeak(FX_INT32 iBaseLevel, CFX_Int32Array &classes, CFX_Int32Array &levels) +{ + FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL); + FXSYS_assert(classes.GetSize() == levels.GetSize()); + FX_INT32 iSize = classes.GetSize(); + if (iSize < 1) { + return; + } + iSize --; + FX_INT32 iLevelCur = iBaseLevel; + FX_INT32 iState = FX_IsOdd(iBaseLevel) ? FX_BWSxr : FX_BWSxl; + FX_INT32 i = 0, iCount = 0, iClsCur, iClsRun, iClsNew, iAction; + for (; i <= iSize; i ++) { + iClsCur = classes.GetAt(i); +#if 0 + if (iClsCur == FX_BIDICLASS_BN) { + levels.SetAt(i, iLevelCur); + if (i == iSize && iLevelCur != iBaseLevel) { + iClsCur = FX_BidiDirection(iLevelCur); + classes.SetAt(i, iClsCur); + } else if (i < iSize) { + FX_INT32 iLevelNext, iLevelNew; + iClsNew = classes.GetAt(i + 1); + iLevelNext = levels.GetAt(i + 1); + if (iClsNew != FX_BIDICLASS_BN && iLevelCur != iLevelNext) { + iLevelNew = iLevelNext; + if (iLevelCur > iLevelNew) { + iLevelNew = iLevelCur; + } + levels.SetAt(i, iLevelNew); + iClsCur = FX_BidiDirection(iLevelNew); + classes.SetAt(i, iClsCur); + iLevelCur = iLevelNext; + } else { + if (iCount) { + iCount ++; + } + continue; + } + } else { + if (iCount) { + iCount ++; + } + continue; + } + } +#endif + FXSYS_assert(iClsCur <= FX_BIDICLASS_BN); + iAction = gc_FX_BidiWeakActions[iState][iClsCur]; + iClsRun = FX_BidiGetDeferredType(iAction); + if (iClsRun != FX_BIDIWEAKACTION_XX && iCount > 0) { + FX_BidiSetDeferredRun(classes, i, iCount, iClsRun); + iCount = 0; + } + iClsNew = FX_BidiGetResolvedType(iAction); + if (iClsNew != FX_BIDIWEAKACTION_XX) { + classes.SetAt(i, iClsNew); + } + if (FX_BIDIWEAKACTION_IX & iAction) { + iCount ++; + } + iState = gc_FX_BidiWeakStates[iState][iClsCur]; + } + iClsCur = FX_BidiDirection(iLevelCur); + iClsRun = FX_BidiGetDeferredType(gc_FX_BidiWeakActions[iState][iClsCur]); + if (iClsRun != FX_BIDIWEAKACTION_XX && iCount > 0) { + FX_BidiSetDeferredRun(classes, i, iCount, iClsRun); + } +} +const FX_INT32 gc_FX_BidiNeutralStates[][5] = { + {FX_BNSrn, FX_BNSl, FX_BNSr, FX_BNSr, FX_BNSr}, + {FX_BNSln, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl}, + {FX_BNSrn, FX_BNSl, FX_BNSr, FX_BNSr, FX_BNSr}, + {FX_BNSln, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl}, + {FX_BNSna, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl}, + {FX_BNSna, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl}, +}; +const FX_INT32 gc_FX_BidiNeutralActions[][5] = { + {FX_BNAIn, 0, 0, 0, 0 }, + {FX_BNAIn, 0, 0, 0, FX_BCL }, + {FX_BNAIn, FX_BNAEn, FX_BNARn, FX_BNARn, FX_BNARn }, + {FX_BNAIn, FX_BNALn, FX_BNAEn, FX_BNAEn, FX_BNALnL }, + {FX_BNAIn, 0, 0, 0, FX_BCL }, + {FX_BNAIn, FX_BNAEn, FX_BNARn, FX_BNARn, FX_BNAEn }, +}; +FX_INT32 FX_BidiGetDeferredNeutrals(FX_INT32 iAction, FX_INT32 iLevel) +{ + iAction = (iAction >> 4) & 0xF; + if (iAction == (FX_BIDINEUTRALACTION_En >> 4)) { + return FX_BidiDirection(iLevel); + } else { + return iAction; + } +} +FX_INT32 FX_BidiGetResolvedNeutrals(FX_INT32 iAction) +{ + iAction = (iAction & 0xF); + if (iAction == FX_BIDINEUTRALACTION_In) { + return 0; + } else { + return iAction; + } +} +void FX_BidiResolveNeutrals(FX_INT32 iBaseLevel, CFX_Int32Array &classes, const CFX_Int32Array &levels) +{ + FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL); + FXSYS_assert(classes.GetSize() == levels.GetSize()); + FX_INT32 iSize = classes.GetSize(); + if (iSize < 1) { + return; + } + iSize --; + FX_INT32 iLevel = iBaseLevel; + FX_INT32 iState = FX_IsOdd(iBaseLevel) ? FX_BNSr : FX_BNSl; + FX_INT32 i = 0, iCount = 0, iClsCur, iClsRun, iClsNew, iAction; + for (; i <= iSize; i ++) { + iClsCur = classes.GetAt(i); + if (iClsCur == FX_BIDICLASS_BN) { + if (iCount) { + iCount ++; + } + continue; + } + FXSYS_assert(iClsCur < FX_BIDICLASS_AL); + iAction = gc_FX_BidiNeutralActions[iState][iClsCur]; + iClsRun = FX_BidiGetDeferredNeutrals(iAction, iLevel); + if (iClsRun != FX_BIDICLASS_N && iCount > 0) { + FX_BidiSetDeferredRun(classes, i, iCount, iClsRun); + iCount = 0; + } + iClsNew = FX_BidiGetResolvedNeutrals(iAction); + if (iClsNew != FX_BIDICLASS_N) { + classes.SetAt(i, iClsNew); + } + if (FX_BIDINEUTRALACTION_In & iAction) { + iCount ++; + } + iState = gc_FX_BidiNeutralStates[iState][iClsCur]; + iLevel = levels.GetAt(i); + } + iClsCur = FX_BidiDirection(iLevel); + iClsRun = FX_BidiGetDeferredNeutrals(gc_FX_BidiNeutralActions[iState][iClsCur], iLevel); + if (iClsRun != FX_BIDICLASS_N && iCount > 0) { + FX_BidiSetDeferredRun(classes, i, iCount, iClsRun); + } +} +const FX_INT32 gc_FX_BidiAddLevel[][4] = { + {0, 1, 2, 2}, + {1, 0, 1, 1}, +}; +void FX_BidiResolveImplicit(const CFX_Int32Array &classes, CFX_Int32Array &levels) +{ + FXSYS_assert(classes.GetSize() == levels.GetSize()); + FX_INT32 iSize = classes.GetSize(); + if (iSize < 1) { + return; + } + iSize --; + FX_INT32 iCls, iLevel; + for (FX_INT32 i = 0; i <= iSize; i ++) { + iCls = classes.GetAt(i); + if (iCls == FX_BIDICLASS_BN) { + continue; + } + FXSYS_assert(iCls > FX_BIDICLASS_ON && iCls < FX_BIDICLASS_AL); + iLevel = levels.GetAt(i); + iLevel += gc_FX_BidiAddLevel[FX_IsOdd(iLevel)][iCls - 1]; + levels.SetAt(i, iLevel); + } +} +void FX_BidiResolveWhitespace(FX_INT32 iBaseLevel, const CFX_Int32Array &classes, CFX_Int32Array &levels) +{ + FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL); + FXSYS_assert(classes.GetSize() == levels.GetSize()); + FX_INT32 iSize = classes.GetSize(); + if (iSize < 1) { + return; + } + iSize --; + FX_INT32 iLevel = iBaseLevel; + FX_INT32 i = 0, iCount = 0; + for (; i <= iSize; i ++) { + switch(classes.GetAt(i)) { + case FX_BIDICLASS_WS: + iCount ++; + break; + case FX_BIDICLASS_RLE: + case FX_BIDICLASS_LRE: + case FX_BIDICLASS_LRO: + case FX_BIDICLASS_RLO: + case FX_BIDICLASS_PDF: + case FX_BIDICLASS_BN: + levels.SetAt(i, iLevel); + iCount ++; + break; + case FX_BIDICLASS_S: + case FX_BIDICLASS_B: + if (iCount > 0) { + FX_BidiSetDeferredRun(levels, i, iCount, iBaseLevel); + } + levels.SetAt(i, iBaseLevel); + iCount = 0; + break; + default: + iCount = 0; + break; + } + iLevel = levels.GetAt(i); + } + if (iCount > 0) { + FX_BidiSetDeferredRun(levels, i, iCount, iBaseLevel); + } +} +FX_INT32 FX_BidiReorderLevel(FX_INT32 iBaseLevel, CFX_WideString &wsText, const CFX_Int32Array &levels, FX_INT32 iStart, FX_BOOL bReverse) +{ + FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL); + FXSYS_assert(wsText.GetLength() == levels.GetSize()); + FXSYS_assert(iStart >= 0 && iStart < wsText.GetLength()); + FX_INT32 iSize = wsText.GetLength(); + if (iSize < 1) { + return 0; + } + bReverse = bReverse || FX_IsOdd(iBaseLevel); + FX_INT32 i = iStart, iLevel; + for (; i < iSize; i ++) { + if ((iLevel = levels.GetAt(i)) == iBaseLevel) { + continue; + } + if (iLevel < iBaseLevel) { + break; + } + i += FX_BidiReorderLevel(iBaseLevel + 1, wsText, levels, i, bReverse) - 1; + } + FX_INT32 iCount = i - iStart; + if (bReverse && iCount > 1) { + FX_BidiReverseString(wsText, iStart, iCount); + } + return iCount; +} +void FX_BidiReorder(FX_INT32 iBaseLevel, CFX_WideString &wsText, const CFX_Int32Array &levels) +{ + FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL); + FXSYS_assert(wsText.GetLength() == levels.GetSize()); + FX_INT32 iSize = wsText.GetLength(); + if (iSize < 1) { + return; + } + FX_INT32 i = 0; + while (i < iSize) { + i += FX_BidiReorderLevel(iBaseLevel, wsText, levels, i, FALSE); + } +} +void FX_BidiLine(CFX_WideString &wsText, FX_INT32 iBaseLevel) +{ + FX_INT32 iLength = wsText.GetLength(); + if (iLength < 2) { + return; + } + CFX_Int32Array classes, levels; + classes.SetAtGrow(iLength - 1, 0); + levels.SetAtGrow(iLength - 1, 0); + FX_BidiClassify(wsText, classes, FALSE); + FX_BidiResolveExplicit(iBaseLevel, FX_BIDICLASS_N, classes, levels, 0, iLength, 0); + FX_BidiResolveWeak(iBaseLevel, classes, levels); + FX_BidiResolveNeutrals(iBaseLevel, classes, levels); + FX_BidiResolveImplicit(classes, levels); + FX_BidiClassify(wsText, classes, TRUE); + FX_BidiResolveWhitespace(iBaseLevel, classes, levels); + FX_BidiReorder(iBaseLevel, wsText, levels); + classes.RemoveAll(); + levels.RemoveAll(); +} +template +class CFX_BidiLineTemplate +{ +public: + void FX_BidiReverseString(CFX_ArrayTemplate &chars, FX_INT32 iStart, FX_INT32 iCount) + { + FXSYS_assert(iStart > -1 && iStart < chars.GetSize()); + FXSYS_assert(iCount >= 0 && iStart + iCount <= chars.GetSize()); + baseType *pStart, *pEnd; + FX_INT32 iEnd = iStart + iCount - 1, iTemp; + while (iStart < iEnd) { + pStart = chars.GetDataPtr(iStart ++); + pEnd = chars.GetDataPtr(iEnd --); + iTemp = pStart->m_iBidiPos; + pStart->m_iBidiPos = pEnd->m_iBidiPos; + pEnd->m_iBidiPos = iTemp; + } + } + void FX_BidiSetDeferredRun(CFX_ArrayTemplate &chars, FX_BOOL bClass, FX_INT32 iStart, FX_INT32 iCount, FX_INT32 iValue) + { + FXSYS_assert(iStart > -1 && iStart <= chars.GetSize()); + FXSYS_assert(iStart - iCount > -1); + baseType *pTC; + FX_INT32 iLast = iStart - iCount; + if (bClass) { + for (FX_INT32 i = iStart - 1; i >= iLast; i --) { + pTC = chars.GetDataPtr(i); + pTC->m_iBidiClass = (FX_INT16)iValue; + } + } else { + for (FX_INT32 i = iStart - 1; i >= iLast; i --) { + pTC = chars.GetDataPtr(i); + pTC->m_iBidiLevel = (FX_INT16)iValue; + } + } + } + void FX_BidiClassify(CFX_ArrayTemplate &chars, FX_INT32 iCount, FX_BOOL bWS) + { + FXSYS_assert(iCount > -1 && iCount <= chars.GetSize()); + baseType *pTC; + if (bWS) { + for (FX_INT32 i = 0; i < iCount; i ++) { + pTC = chars.GetDataPtr(i); + pTC->m_iBidiClass = (FX_INT16)(pTC->m_dwCharProps & FX_BIDICLASSBITSMASK) >> FX_BIDICLASSBITS; + } + } else { + for (FX_INT32 i = 0; i < iCount; i ++) { + pTC = chars.GetDataPtr(i); + pTC->m_iBidiClass = (FX_INT16)gc_FX_BidiNTypes[(pTC->m_dwCharProps & FX_BIDICLASSBITSMASK) >> FX_BIDICLASSBITS]; + } + } + } + void FX_BidiResolveExplicit(CFX_ArrayTemplate &chars, FX_INT32 iCount, FX_INT32 iBaseLevel) + { + FXSYS_assert(iCount > -1 && iCount <= chars.GetSize()); + FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL); + if (iCount < 1) { + return; + } + baseType *pTC; + for (FX_INT32 i = 0; i < iCount; i ++) { + pTC = chars.GetDataPtr(i); + pTC->m_iBidiLevel = (FX_INT16)iBaseLevel; + } + } + void FX_BidiResolveWeak(CFX_ArrayTemplate &chars, FX_INT32 iCount, FX_INT32 iBaseLevel) + { + FXSYS_assert(iCount > -1 && iCount <= chars.GetSize()); + iCount --; + if (iCount < 1) { + return; + } + baseType *pTC, *pTCNext; + FX_INT32 iLevelCur = iBaseLevel; + FX_INT32 iState = FX_IsOdd(iBaseLevel) ? FX_BWSxr : FX_BWSxl; + FX_INT32 i = 0, iNum = 0, iClsCur, iClsRun, iClsNew, iAction; + for (; i <= iCount; i ++) { + pTC = chars.GetDataPtr(i); + iClsCur = pTC->m_iBidiClass; + if (iClsCur == FX_BIDICLASS_BN) { + pTC->m_iBidiLevel = (FX_INT16)iLevelCur; + if (i == iCount && iLevelCur != iBaseLevel) { + iClsCur = FX_BidiDirection(iLevelCur); + pTC->m_iBidiClass = (FX_INT16)iClsCur; + } else if (i < iCount) { + pTCNext = chars.GetDataPtr(i + 1); + FX_INT32 iLevelNext, iLevelNew; + iClsNew = pTCNext->m_iBidiClass; + iLevelNext = pTCNext->m_iBidiLevel; + if (iClsNew != FX_BIDICLASS_BN && iLevelCur != iLevelNext) { + iLevelNew = iLevelNext; + if (iLevelCur > iLevelNew) { + iLevelNew = iLevelCur; + } + pTC->m_iBidiLevel = (FX_INT16)iLevelNew; + iClsCur = FX_BidiDirection(iLevelNew); + pTC->m_iBidiClass = (FX_INT16)iClsCur; + iLevelCur = iLevelNext; + } else { + if (iNum > 0) { + iNum ++; + } + continue; + } + } else { + if (iNum > 0) { + iNum ++; + } + continue; + } + } + FXSYS_assert(iClsCur <= FX_BIDICLASS_BN); + iAction = gc_FX_BidiWeakActions[iState][iClsCur]; + iClsRun = FX_BidiGetDeferredType(iAction); + if (iClsRun != FX_BIDIWEAKACTION_XX && iNum > 0) { + FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun); + iNum = 0; + } + iClsNew = FX_BidiGetResolvedType(iAction); + if (iClsNew != FX_BIDIWEAKACTION_XX) { + pTC->m_iBidiClass = (FX_INT16)iClsNew; + } + if (FX_BIDIWEAKACTION_IX & iAction) { + iNum ++; + } + iState = gc_FX_BidiWeakStates[iState][iClsCur]; + } + if (iNum > 0) { + iClsCur = FX_BidiDirection(iBaseLevel); + iClsRun = FX_BidiGetDeferredType(gc_FX_BidiWeakActions[iState][iClsCur]); + if (iClsRun != FX_BIDIWEAKACTION_XX) { + FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun); + } + } + } + void FX_BidiResolveNeutrals(CFX_ArrayTemplate &chars, FX_INT32 iCount, FX_INT32 iBaseLevel) + { + FXSYS_assert(iCount > -1 && iCount <= chars.GetSize()); + FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL); + iCount --; + if (iCount < 1) { + return; + } + baseType *pTC; + FX_INT32 iLevel = iBaseLevel; + FX_INT32 iState = FX_IsOdd(iBaseLevel) ? FX_BNSr : FX_BNSl; + FX_INT32 i = 0, iNum = 0, iClsCur, iClsRun, iClsNew, iAction; + for (; i <= iCount; i ++) { + pTC = chars.GetDataPtr(i); + iClsCur = pTC->m_iBidiClass; + if (iClsCur == FX_BIDICLASS_BN) { + if (iNum) { + iNum ++; + } + continue; + } + FXSYS_assert(iClsCur < FX_BIDICLASS_AL); + iAction = gc_FX_BidiNeutralActions[iState][iClsCur]; + iClsRun = FX_BidiGetDeferredNeutrals(iAction, iLevel); + if (iClsRun != FX_BIDICLASS_N && iNum > 0) { + FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun); + iNum = 0; + } + iClsNew = FX_BidiGetResolvedNeutrals(iAction); + if (iClsNew != FX_BIDICLASS_N) { + pTC->m_iBidiClass = (FX_INT16)iClsNew; + } + if (FX_BIDINEUTRALACTION_In & iAction) { + iNum ++; + } + iState = gc_FX_BidiNeutralStates[iState][iClsCur]; + iLevel = pTC->m_iBidiLevel; + } + if (iNum > 0) { + iClsCur = FX_BidiDirection(iLevel); + iClsRun = FX_BidiGetDeferredNeutrals(gc_FX_BidiNeutralActions[iState][iClsCur], iLevel); + if (iClsRun != FX_BIDICLASS_N) { + FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun); + } + } + } + void FX_BidiResolveImplicit(CFX_ArrayTemplate &chars, FX_INT32 iCount) + { + FXSYS_assert(iCount > -1 && iCount <= chars.GetSize()); + baseType *pTC; + FX_INT32 iCls, iLevel; + for (FX_INT32 i = 0; i < iCount; i ++) { + pTC = chars.GetDataPtr(i); + iCls = pTC->m_iBidiClass; + if (iCls == FX_BIDICLASS_BN) { + continue; + } + FXSYS_assert(iCls > FX_BIDICLASS_ON && iCls < FX_BIDICLASS_AL); + iLevel = pTC->m_iBidiLevel; + iLevel += gc_FX_BidiAddLevel[FX_IsOdd(iLevel)][iCls - 1]; + pTC->m_iBidiLevel = (FX_INT16)iLevel; + } + } + void FX_BidiResolveWhitespace(CFX_ArrayTemplate &chars, FX_INT32 iCount, FX_INT32 iBaseLevel) + { + FXSYS_assert(iCount > -1 && iCount <= chars.GetSize()); + FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL); + if (iCount < 1) { + return; + } + iCount --; + FX_INT32 iLevel = iBaseLevel; + FX_INT32 i = 0, iNum = 0; + baseType *pTC; + for (; i <= iCount; i ++) { + pTC = chars.GetDataPtr(i); + switch(pTC->m_iBidiClass) { + case FX_BIDICLASS_WS: + iNum ++; + break; + case FX_BIDICLASS_RLE: + case FX_BIDICLASS_LRE: + case FX_BIDICLASS_LRO: + case FX_BIDICLASS_RLO: + case FX_BIDICLASS_PDF: + case FX_BIDICLASS_BN: + pTC->m_iBidiLevel = (FX_INT16)iLevel; + iNum ++; + break; + case FX_BIDICLASS_S: + case FX_BIDICLASS_B: + if (iNum > 0) { + FX_BidiSetDeferredRun(chars, FALSE, i, iNum, iBaseLevel); + } + pTC->m_iBidiLevel = (FX_INT16)iBaseLevel; + iNum = 0; + break; + default: + iNum = 0; + break; + } + iLevel = pTC->m_iBidiLevel; + } + if (iNum > 0) { + FX_BidiSetDeferredRun(chars, FALSE, i, iNum, iBaseLevel); + } + } + FX_INT32 FX_BidiReorderLevel(CFX_ArrayTemplate &chars, FX_INT32 iCount, FX_INT32 iBaseLevel, FX_INT32 iStart, FX_BOOL bReverse) + { + FXSYS_assert(iCount > -1 && iCount <= chars.GetSize()); + FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL); + FXSYS_assert(iStart >= 0 && iStart < iCount); + if (iCount < 1) { + return 0; + } + baseType *pTC; + bReverse = bReverse || FX_IsOdd(iBaseLevel); + FX_INT32 i = iStart, iLevel; + for (; i < iCount; i ++) { + pTC = chars.GetDataPtr(i); + if ((iLevel = pTC->m_iBidiLevel) == iBaseLevel) { + continue; + } + if (iLevel < iBaseLevel) { + break; + } + i += FX_BidiReorderLevel(chars, iCount, iBaseLevel + 1, i, bReverse) - 1; + } + FX_INT32 iNum = i - iStart; + if (bReverse && iNum > 1) { + FX_BidiReverseString(chars, iStart, iNum); + } + return iNum; + } + void FX_BidiReorder(CFX_ArrayTemplate &chars, FX_INT32 iCount, FX_INT32 iBaseLevel) + { + FXSYS_assert(iCount > -1 && iCount <= chars.GetSize()); + FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL); + FX_INT32 i = 0; + while (i < iCount) { + i += FX_BidiReorderLevel(chars, iCount, iBaseLevel, i, FALSE); + } + } + void FX_BidiPosition(CFX_ArrayTemplate &chars, FX_INT32 iCount) + { + FXSYS_assert(iCount > -1 && iCount <= chars.GetSize()); + baseType *pTC; + FX_INT32 i = 0; + while (i < iCount) { + pTC = chars.GetDataPtr(i); + pTC = chars.GetDataPtr(pTC->m_iBidiPos); + pTC->m_iBidiOrder = i ++; + } + } + + void FX_BidiLine(CFX_ArrayTemplate &chars, FX_INT32 iCount, FX_INT32 iBaseLevel) + { + FXSYS_assert(iCount > -1 && iCount <= chars.GetSize()); + if (iCount < 2) { + return; + } + FX_BidiClassify(chars, iCount, FALSE); + FX_BidiResolveExplicit(chars, iCount, iBaseLevel); + FX_BidiResolveWeak(chars, iCount, iBaseLevel); + FX_BidiResolveNeutrals(chars, iCount, iBaseLevel); + FX_BidiResolveImplicit(chars, iCount); + FX_BidiClassify(chars, iCount, TRUE); + FX_BidiResolveWhitespace(chars, iCount, iBaseLevel); + FX_BidiReorder(chars, iCount, iBaseLevel); + FX_BidiPosition(chars, iCount); + } +}; +void FX_BidiLine(CFX_TxtCharArray &chars, FX_INT32 iCount, FX_INT32 iBaseLevel) +{ + CFX_BidiLineTemplate blt; + blt.FX_BidiLine(chars, iCount, iBaseLevel); +} +void FX_BidiLine(CFX_RTFCharArray &chars, FX_INT32 iCount, FX_INT32 iBaseLevel) +{ + CFX_BidiLineTemplate blt; + blt.FX_BidiLine(chars, iCount, iBaseLevel); +} IFX_BidiChar* IFX_BidiChar::Create() { return FX_NEW CFX_BidiChar; diff --git a/core/src/fxcrt/fx_arabic.h b/core/src/fxcrt/fx_arabic.h index c404449af0..e44bfb8142 100644 --- a/core/src/fxcrt/fx_arabic.h +++ b/core/src/fxcrt/fx_arabic.h @@ -6,7 +6,180 @@ #ifndef _FX_ARABIC_IMP #define _FX_ARABIC_IMP -class CFX_BidiChar FX_FINAL : public IFX_BidiChar, public CFX_Object +typedef struct _FX_ARABICCHARRANGE { + FX_WCHAR wStart; + FX_WCHAR wEnd; +} FX_ARABICCHARRANGE; +class CFX_ArabicChar : public IFX_ArabicChar, public CFX_Object +{ +public: + virtual void Release() + { + delete this; + } + virtual FX_BOOL IsArabicChar(FX_WCHAR wch) const; + virtual FX_BOOL IsArabicFormChar(FX_WCHAR wch) const; + + virtual FX_WCHAR GetFormChar(FX_WCHAR wch, FX_WCHAR prev = 0, FX_WCHAR next = 0) const; + virtual FX_WCHAR GetFormChar(const CFX_Char *cur, const CFX_Char *prev, const CFX_Char *next) const; +protected: + FX_LPCARBFORMTABLE ParseChar(const CFX_Char *pTC, FX_WCHAR &wChar, FX_CHARTYPE &eType) const; +}; +void FX_BidiReverseString(CFX_WideString &wsText, FX_INT32 iStart, FX_INT32 iCount); +void FX_BidiSetDeferredRun(CFX_Int32Array &values, FX_INT32 iStart, FX_INT32 iCount, FX_INT32 iValue); +#define FX_BCON FX_BIDICLASS_ON +#define FX_BCL FX_BIDICLASS_L +#define FX_BCR FX_BIDICLASS_R +#define FX_BCAN FX_BIDICLASS_AN +#define FX_BCEN FX_BIDICLASS_EN +#define FX_BCAL FX_BIDICLASS_AL +#define FX_BCNSM FX_BIDICLASS_NSM +#define FX_BCCS FX_BIDICLASS_CS +#define FX_BCES FX_BIDICLASS_ES +#define FX_BCET FX_BIDICLASS_ET +#define FX_BCBN FX_BIDICLASS_BN +#define FX_BCS FX_BIDICLASS_S +#define FX_BCWS FX_BIDICLASS_WS +#define FX_BCB FX_BIDICLASS_B +#define FX_BCRLO FX_BIDICLASS_RLO +#define FX_BCRLE FX_BIDICLASS_RLE +#define FX_BCLRO FX_BIDICLASS_LRO +#define FX_BCLRE FX_BIDICLASS_LRE +#define FX_BCPDF FX_BIDICLASS_PDF +#define FX_BCN FX_BIDICLASS_N +void FX_BidiClassify(const CFX_WideString &wsText, CFX_Int32Array &classes, FX_BOOL bWS = FALSE); +#define FX_BIDIMAXLEVEL 61 +#define FX_BidiGreaterEven(a) (FX_IsOdd(a) ? ((a) + 1) : ((a) + 2)) +#define FX_BidiGreaterOdd(a) (FX_IsOdd(a) ? ((a) + 2) : ((a) + 1)) +FX_INT32 FX_BidiResolveExplicit(FX_INT32 iBaseLevel, FX_INT32 iDirection, CFX_Int32Array &classes, CFX_Int32Array &levels, FX_INT32 iStart, FX_INT32 iCount, FX_INT32 iNest = 0); +#define FX_BidiDirection(a) (FX_IsOdd(a) ? FX_BIDICLASS_R : FX_BIDICLASS_L) +enum FX_BIDIWEAKSTATE { + FX_BIDIWEAKSTATE_xa = 0, + FX_BIDIWEAKSTATE_xr, + FX_BIDIWEAKSTATE_xl, + FX_BIDIWEAKSTATE_ao, + FX_BIDIWEAKSTATE_ro, + FX_BIDIWEAKSTATE_lo, + FX_BIDIWEAKSTATE_rt, + FX_BIDIWEAKSTATE_lt, + FX_BIDIWEAKSTATE_cn, + FX_BIDIWEAKSTATE_ra, + FX_BIDIWEAKSTATE_re, + FX_BIDIWEAKSTATE_la, + FX_BIDIWEAKSTATE_le, + FX_BIDIWEAKSTATE_ac, + FX_BIDIWEAKSTATE_rc, + FX_BIDIWEAKSTATE_rs, + FX_BIDIWEAKSTATE_lc, + FX_BIDIWEAKSTATE_ls, + FX_BIDIWEAKSTATE_ret, + FX_BIDIWEAKSTATE_let, +}; +#define FX_BWSxa FX_BIDIWEAKSTATE_xa +#define FX_BWSxr FX_BIDIWEAKSTATE_xr +#define FX_BWSxl FX_BIDIWEAKSTATE_xl +#define FX_BWSao FX_BIDIWEAKSTATE_ao +#define FX_BWSro FX_BIDIWEAKSTATE_ro +#define FX_BWSlo FX_BIDIWEAKSTATE_lo +#define FX_BWSrt FX_BIDIWEAKSTATE_rt +#define FX_BWSlt FX_BIDIWEAKSTATE_lt +#define FX_BWScn FX_BIDIWEAKSTATE_cn +#define FX_BWSra FX_BIDIWEAKSTATE_ra +#define FX_BWSre FX_BIDIWEAKSTATE_re +#define FX_BWSla FX_BIDIWEAKSTATE_la +#define FX_BWSle FX_BIDIWEAKSTATE_le +#define FX_BWSac FX_BIDIWEAKSTATE_ac +#define FX_BWSrc FX_BIDIWEAKSTATE_rc +#define FX_BWSrs FX_BIDIWEAKSTATE_rs +#define FX_BWSlc FX_BIDIWEAKSTATE_lc +#define FX_BWSls FX_BIDIWEAKSTATE_ls +#define FX_BWSret FX_BIDIWEAKSTATE_ret +#define FX_BWSlet FX_BIDIWEAKSTATE_let +enum FX_BIDIWEAKACTION { + FX_BIDIWEAKACTION_IX = 0x100, + FX_BIDIWEAKACTION_XX = 0x0F, + FX_BIDIWEAKACTION_xxx = (0x0F << 4) + 0x0F, + FX_BIDIWEAKACTION_xIx = 0x100 + FX_BIDIWEAKACTION_xxx, + FX_BIDIWEAKACTION_xxN = (0x0F << 4) + FX_BIDICLASS_ON, + FX_BIDIWEAKACTION_xxE = (0x0F << 4) + FX_BIDICLASS_EN, + FX_BIDIWEAKACTION_xxA = (0x0F << 4) + FX_BIDICLASS_AN, + FX_BIDIWEAKACTION_xxR = (0x0F << 4) + FX_BIDICLASS_R, + FX_BIDIWEAKACTION_xxL = (0x0F << 4) + FX_BIDICLASS_L, + FX_BIDIWEAKACTION_Nxx = (FX_BIDICLASS_ON << 4) + 0x0F, + FX_BIDIWEAKACTION_Axx = (FX_BIDICLASS_AN << 4) + 0x0F, + FX_BIDIWEAKACTION_ExE = (FX_BIDICLASS_EN << 4) + FX_BIDICLASS_EN, + FX_BIDIWEAKACTION_NIx = (FX_BIDICLASS_ON << 4) + 0x0F + 0x100, + FX_BIDIWEAKACTION_NxN = (FX_BIDICLASS_ON << 4) + FX_BIDICLASS_ON, + FX_BIDIWEAKACTION_NxR = (FX_BIDICLASS_ON << 4) + FX_BIDICLASS_R, + FX_BIDIWEAKACTION_NxE = (FX_BIDICLASS_ON << 4) + FX_BIDICLASS_EN, + FX_BIDIWEAKACTION_AxA = (FX_BIDICLASS_AN << 4) + FX_BIDICLASS_AN, + FX_BIDIWEAKACTION_NxL = (FX_BIDICLASS_ON << 4) + FX_BIDICLASS_L, + FX_BIDIWEAKACTION_LxL = (FX_BIDICLASS_L << 4) + FX_BIDICLASS_L, + FX_BIDIWEAKACTION_xIL = (0x0F << 4) + FX_BIDICLASS_L + 0x100, + FX_BIDIWEAKACTION_AxR = (FX_BIDICLASS_AN << 4) + FX_BIDICLASS_R, + FX_BIDIWEAKACTION_Lxx = (FX_BIDICLASS_L << 4) + 0x0F, +}; +#define FX_BWAIX FX_BIDIWEAKACTION_IX +#define FX_BWAXX FX_BIDIWEAKACTION_XX +#define FX_BWAxxx FX_BIDIWEAKACTION_xxx +#define FX_BWAxIx FX_BIDIWEAKACTION_xIx +#define FX_BWAxxN FX_BIDIWEAKACTION_xxN +#define FX_BWAxxE FX_BIDIWEAKACTION_xxE +#define FX_BWAxxA FX_BIDIWEAKACTION_xxA +#define FX_BWAxxR FX_BIDIWEAKACTION_xxR +#define FX_BWAxxL FX_BIDIWEAKACTION_xxL +#define FX_BWANxx FX_BIDIWEAKACTION_Nxx +#define FX_BWAAxx FX_BIDIWEAKACTION_Axx +#define FX_BWAExE FX_BIDIWEAKACTION_ExE +#define FX_BWANIx FX_BIDIWEAKACTION_NIx +#define FX_BWANxN FX_BIDIWEAKACTION_NxN +#define FX_BWANxR FX_BIDIWEAKACTION_NxR +#define FX_BWANxE FX_BIDIWEAKACTION_NxE +#define FX_BWAAxA FX_BIDIWEAKACTION_AxA +#define FX_BWANxL FX_BIDIWEAKACTION_NxL +#define FX_BWALxL FX_BIDIWEAKACTION_LxL +#define FX_BWAxIL FX_BIDIWEAKACTION_xIL +#define FX_BWAAxR FX_BIDIWEAKACTION_AxR +#define FX_BWALxx FX_BIDIWEAKACTION_Lxx +#define FX_BidiGetDeferredType(a) (((a) >> 4) & 0x0F) +#define FX_BidiGetResolvedType(a) ((a) & 0x0F) +void FX_BidiResolveWeak(FX_INT32 iBaseLevel, CFX_Int32Array &classes, CFX_Int32Array &levels); +enum FX_BIDINEUTRALSTATE { + FX_BIDINEUTRALSTATE_r = 0, + FX_BIDINEUTRALSTATE_l, + FX_BIDINEUTRALSTATE_rn, + FX_BIDINEUTRALSTATE_ln, + FX_BIDINEUTRALSTATE_a, + FX_BIDINEUTRALSTATE_na, +}; +#define FX_BNSr FX_BIDINEUTRALSTATE_r +#define FX_BNSl FX_BIDINEUTRALSTATE_l +#define FX_BNSrn FX_BIDINEUTRALSTATE_rn +#define FX_BNSln FX_BIDINEUTRALSTATE_ln +#define FX_BNSa FX_BIDINEUTRALSTATE_a +#define FX_BNSna FX_BIDINEUTRALSTATE_na +enum FX_BIDINEUTRALACTION { + FX_BIDINEUTRALACTION_nL = FX_BIDICLASS_L, + FX_BIDINEUTRALACTION_En = (FX_BIDICLASS_AN << 4), + FX_BIDINEUTRALACTION_Rn = (FX_BIDICLASS_R << 4), + FX_BIDINEUTRALACTION_Ln = (FX_BIDICLASS_L << 4), + FX_BIDINEUTRALACTION_In = FX_BIDIWEAKACTION_IX, + FX_BIDINEUTRALACTION_LnL = (FX_BIDICLASS_L << 4) + FX_BIDICLASS_L, +}; +#define FX_BNAnL FX_BIDINEUTRALACTION_nL +#define FX_BNAEn FX_BIDINEUTRALACTION_En +#define FX_BNARn FX_BIDINEUTRALACTION_Rn +#define FX_BNALn FX_BIDINEUTRALACTION_Ln +#define FX_BNAIn FX_BIDINEUTRALACTION_In +#define FX_BNALnL FX_BIDINEUTRALACTION_LnL +FX_INT32 FX_BidiGetDeferredNeutrals(FX_INT32 iAction, FX_INT32 iLevel); +FX_INT32 FX_BidiGetResolvedNeutrals(FX_INT32 iAction); +void FX_BidiResolveNeutrals(FX_INT32 iBaseLevel, CFX_Int32Array &classes, const CFX_Int32Array &levels); +void FX_BidiResolveImplicit(const CFX_Int32Array &classes, CFX_Int32Array &levels); +void FX_BidiResolveWhitespace(FX_INT32 iBaseLevel, const CFX_Int32Array &classes, CFX_Int32Array &levels); +FX_INT32 FX_BidiReorderLevel(FX_INT32 iBaseLevel, CFX_WideString &wsText, const CFX_Int32Array &levels, FX_INT32 iStart, FX_BOOL bReverse = FALSE); +void FX_BidiReorder(FX_INT32 iBaseLevel, CFX_WideString &wsText, const CFX_Int32Array &levels); +class CFX_BidiChar : public IFX_BidiChar, public CFX_Object { public: CFX_BidiChar(); diff --git a/core/src/fxcrt/fx_extension.cpp b/core/src/fxcrt/fx_extension.cpp index 7ff6b062b4..330c675457 100644 --- a/core/src/fxcrt/fx_extension.cpp +++ b/core/src/fxcrt/fx_extension.cpp @@ -80,6 +80,18 @@ FX_BOOL FX_File_Truncate(FX_HFILE hFile, FX_FILESIZE szFile) FXSYS_assert(hFile != NULL); return ((IFXCRT_FileAccess*)hFile)->Truncate(szFile); } +IFX_FileAccess* FX_CreateDefaultFileAccess(FX_WSTR wsPath) +{ + if (wsPath.GetLength() == 0) + return NULL; + + CFX_CRTFileAccess* pFA = NULL; + pFA = FX_NEW CFX_CRTFileAccess; + if (NULL == pFA) return NULL; + + pFA->Init(wsPath); + return pFA; +} IFX_FileStream* FX_CreateFileStream(FX_LPCSTR filename, FX_DWORD dwModes) { IFXCRT_FileAccess* pFA = FXCRT_FileAccess_Create(); @@ -383,3 +395,40 @@ void FX_Random_GenerateCrypto(FX_LPDWORD pBuffer, FX_INT32 iCount) #ifdef __cplusplus } #endif +#ifdef __cplusplus +extern "C" { +#endif +void FX_GUID_CreateV4(FX_LPGUID pGUID) +{ +#if (_FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || _FX_OS_ == _FX_WIN64_) +#ifdef _FX_WINAPI_PARTITION_DESKTOP_ + if (!FX_GenerateCryptoRandom((FX_LPDWORD)pGUID, 4)) { + FX_Random_GenerateMT((FX_LPDWORD)pGUID, 4); + } +#else + FX_Random_GenerateMT((FX_LPDWORD)pGUID, 4); +#endif +#else + FX_Random_GenerateMT((FX_LPDWORD)pGUID, 4); +#endif + FX_BYTE &b = ((FX_LPBYTE)pGUID)[6]; + b = (b & 0x0F) | 0x40; +} +FX_LPCSTR gs_FX_pHexChars = "0123456789ABCDEF"; +void FX_GUID_ToString(FX_LPCGUID pGUID, CFX_ByteString &bsStr, FX_BOOL bSeparator) +{ + FX_LPSTR pBuf = bsStr.GetBuffer(40); + FX_BYTE b; + for (FX_INT32 i = 0; i < 16; i ++) { + b = ((FX_LPCBYTE)pGUID)[i]; + *pBuf ++ = gs_FX_pHexChars[b >> 4]; + *pBuf ++ = gs_FX_pHexChars[b & 0x0F]; + if (bSeparator && (i == 3 || i == 5 || i == 7 || i == 9)) { + *pBuf ++ = L'-'; + } + } + bsStr.ReleaseBuffer(bSeparator ? 36 : 32); +} +#ifdef __cplusplus +} +#endif diff --git a/core/src/fxcrt/fx_xml_parser.cpp b/core/src/fxcrt/fx_xml_parser.cpp index 05fc7d5fbe..bd418b2d08 100644 --- a/core/src/fxcrt/fx_xml_parser.cpp +++ b/core/src/fxcrt/fx_xml_parser.cpp @@ -672,7 +672,7 @@ FX_BOOL CXML_Element::GetAttrValue(FX_BSTR name, CFX_WideString& attribute) cons FX_XML_SplitQualifiedName(name, bsSpace, bsName); const CFX_WideString* pValue = m_AttrMap.Lookup(bsSpace, bsName); if (pValue) { - attribute = CFX_WideString((FX_LPCWSTR)pValue, pValue->GetLength()); + attribute = CFX_WideString((FX_LPCWSTR)*pValue, pValue->GetLength()); return TRUE; } return FALSE; @@ -681,7 +681,7 @@ FX_BOOL CXML_Element::GetAttrValue(FX_BSTR space, FX_BSTR name, CFX_WideString& { const CFX_WideString* pValue = m_AttrMap.Lookup(space, name); if (pValue) { - attribute = CFX_WideString((FX_LPCWSTR)pValue, pValue->GetLength()); + attribute = CFX_WideString((FX_LPCWSTR)*pValue, pValue->GetLength()); return TRUE; } return FALSE; diff --git a/core/src/fxge/ge/fx_ge_font.cpp b/core/src/fxge/ge/fx_ge_font.cpp index 817f3712d9..e3c68e0f65 100644 --- a/core/src/fxge/ge/fx_ge_font.cpp +++ b/core/src/fxge/ge/fx_ge_font.cpp @@ -25,6 +25,52 @@ CFX_Font::CFX_Font() m_pDwFont = NULL; m_hHandle = NULL; m_bDwLoaded = FALSE; + m_bLogic = FALSE; +} +FX_BOOL CFX_Font::LoadClone(const CFX_Font* pFont) +{ + if (pFont == NULL) { + return FALSE; + } + m_bLogic = TRUE; + if (pFont->m_pSubstFont) { + m_pSubstFont = FX_NEW CFX_SubstFont; + if (!m_pSubstFont) { + return FALSE; + } + m_pSubstFont->m_Charset = pFont->m_pSubstFont->m_Charset; + m_pSubstFont->m_ExtHandle = pFont->m_pSubstFont->m_ExtHandle; + m_pSubstFont->m_SubstFlags = pFont->m_pSubstFont->m_SubstFlags; + m_pSubstFont->m_Weight = pFont->m_pSubstFont->m_Weight; + m_pSubstFont->m_Family = pFont->m_pSubstFont->m_Family; + m_pSubstFont->m_ItalicAngle = pFont->m_pSubstFont->m_ItalicAngle; + } + if (pFont->m_OtfFontData.GetSize()) { + m_OtfFontData.AttachData(pFont->m_OtfFontData.GetBuffer(), pFont->m_OtfFontData.GetSize()); + } + m_Face = pFont->m_Face; + m_bEmbedded = pFont->m_bEmbedded; + m_bVertical = pFont->m_bVertical; + m_dwSize = pFont->m_dwSize; + m_pFontData = pFont->m_pFontData; + m_pGsubData = pFont->m_pGsubData; +#ifdef FOXIT_CHROME_BUILD + if (pFont->m_pFontDataAllocation) { + m_pFontDataAllocation = FX_Alloc(FX_BYTE, m_dwSize); + if (!m_pFontDataAllocation) { + return FALSE; + } + m_pFontData = m_pFontDataAllocation; + FXSYS_memcpy32(m_pFontDataAllocation, pFont->m_pFontDataAllocation, m_dwSize); + } +#endif + m_pPlatformFont = pFont->m_pPlatformFont; + m_pPlatformFontCollection = pFont->m_pPlatformFontCollection; + m_pDwFont = pFont->m_pDwFont; + m_hHandle = pFont->m_hHandle; + m_bDwLoaded = pFont->m_bDwLoaded; + m_pOwnedStream = pFont->m_pOwnedStream; + return TRUE; } CFX_Font::~CFX_Font() { @@ -38,6 +84,10 @@ CFX_Font::~CFX_Font() m_pFontDataAllocation = NULL; } #endif + if (m_bLogic) { + m_OtfFontData.DetachBuffer(); + return; + } if (m_Face) { #ifdef FOXIT_CHROME_BUILD if (FXFT_Get_Face_External_Stream(m_Face)) { @@ -108,7 +158,7 @@ extern "C" { { } }; -FX_BOOL _LoadFile(FXFT_Library library, FXFT_Face* Face, IFX_FileRead* pFile, FXFT_Stream* stream) +FX_BOOL _LoadFile(FXFT_Library library, FXFT_Face* Face, IFX_FileRead* pFile, FXFT_Stream* stream, FX_INT32 faceIndex = 0) { FXFT_Stream stream1 = (FXFT_Stream)FX_Alloc(FX_BYTE, sizeof (FXFT_StreamRec)); if (!stream1) { @@ -123,7 +173,7 @@ FX_BOOL _LoadFile(FXFT_Library library, FXFT_Face* Face, IFX_FileRead* pFile, FX FXFT_Open_Args args; args.flags = FT_OPEN_STREAM; args.stream = stream1; - if (FXFT_Open_Face(library, &args, 0, Face)) { + if (FXFT_Open_Face(library, &args, faceIndex, Face)) { FX_Free(stream1); return FALSE; } @@ -132,19 +182,21 @@ FX_BOOL _LoadFile(FXFT_Library library, FXFT_Face* Face, IFX_FileRead* pFile, FX } return TRUE; } -FX_BOOL CFX_Font::LoadFile(IFX_FileRead* pFile) +FX_BOOL CFX_Font::LoadFile(IFX_FileRead* pFile, int nFaceIndex, int* pFaceCount) { m_bEmbedded = FALSE; FXFT_Library library; - if (CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary == NULL) { + if (CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary == NULL) FXFT_Init_FreeType(&CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary); - } library = CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary; FXFT_Stream stream = NULL; - if (!_LoadFile(library, &m_Face, pFile, &stream)) { + if (!_LoadFile(library, &m_Face, pFile, &stream, nFaceIndex)) return FALSE; - } + if (pFaceCount) + *pFaceCount = (int)m_Face->num_faces; +#ifndef FOXIT_CHROME_BUILD m_pOwnedStream = stream; +#endif FXFT_Set_Pixel_Sizes(m_Face, 0, 64); return TRUE; } @@ -455,3 +507,168 @@ IFX_FontEncoding* FXGE_CreateUnicodeEncoding(CFX_Font* pFont) pEncoding = FX_NEW CFX_UnicodeEncoding(pFont); return pEncoding; } +CFX_FontEncodingEX::CFX_FontEncodingEX() +{ + m_pFont = NULL; + m_nEncodingID = FXFM_ENCODING_NONE; +} +FX_BOOL CFX_FontEncodingEX::Init(CFX_Font* pFont, FX_DWORD EncodingID) +{ + if (!pFont) { + return FALSE; + } + m_pFont = pFont; + m_nEncodingID = EncodingID; + return TRUE; +} +FX_DWORD CFX_FontEncodingEX::GlyphFromCharCode(FX_DWORD charcode) +{ + FXFT_Face face = m_pFont->m_Face; + FT_UInt nIndex = FXFT_Get_Char_Index(face, charcode); + if (nIndex > 0) { + return nIndex; + } + int nmaps = FXFT_Get_Face_CharmapCount(face); + int m = 0; + while (m < nmaps) { + int nEncodingID = FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[m++]); + if (m_nEncodingID == nEncodingID) { + continue; + } + int error = FXFT_Select_Charmap(face, nEncodingID); + if (error) { + continue; + } + nIndex = FXFT_Get_Char_Index(face, charcode); + if (nIndex > 0) { + m_nEncodingID = nEncodingID; + return nIndex; + } + } + FXFT_Select_Charmap(face, m_nEncodingID); + return 0; +} +CFX_WideString CFX_FontEncodingEX::UnicodeFromCharCode(FX_DWORD charcode) const +{ + if (m_nEncodingID == FXFM_ENCODING_UNICODE) { + return CFX_WideString((FX_WCHAR)charcode); + } + return CFX_WideString((FX_WCHAR)0); +} +FX_DWORD CFX_FontEncodingEX::CharCodeFromUnicode(FX_WCHAR Unicode) const +{ + if (m_nEncodingID == FXFM_ENCODING_UNICODE || m_nEncodingID == FXFM_ENCODING_MS_SYMBOL) { + return Unicode; + } + FXFT_Face face = m_pFont->m_Face; + int nmaps = FXFT_Get_Face_CharmapCount(face); + for (int i = 0; i < nmaps; i++) { + int nEncodingID = FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[i]); + if (nEncodingID == FXFM_ENCODING_UNICODE || nEncodingID == FXFM_ENCODING_MS_SYMBOL) { + return Unicode; + } + } + return -1; +} +FX_BOOL CFX_FontEncodingEX::IsUnicodeCompatible() const +{ + return m_nEncodingID == FXFM_ENCODING_UNICODE; +} +FX_DWORD CFX_FontEncodingEX::GlyphIndexFromName(FX_LPCSTR pStrName) +{ + FXFT_Face face = m_pFont->m_Face; + return FT_Get_Name_Index(face, (FT_String*)pStrName); +} +CFX_ByteString CFX_FontEncodingEX::NameFromGlyphIndex(FX_DWORD dwGlyphIndex) +{ + FXFT_Face face = m_pFont->m_Face; + CFX_ByteString glyphName(" "); + if (FT_HAS_GLYPH_NAMES(((FT_Face)face))) { + if (FT_Get_Glyph_Name((FT_Face)face, dwGlyphIndex, (FT_Pointer)(FX_LPCSTR)glyphName, 16)) { + glyphName.Empty(); + return glyphName; + } + return glyphName; + } else { + return glyphName; + } +} +FX_DWORD CFX_FontEncodingEX::CharCodeFromGlyphIndex(FX_DWORD dwGlyphIndex) +{ + FXFT_Face face = m_pFont->GetFace(); + FX_DWORD charcode; + FT_UInt gid; + charcode = FT_Get_First_Char((FT_Face)face, &gid); + while (gid != 0) { + if (dwGlyphIndex == gid) { + return charcode; + } + charcode = FT_Get_Next_Char((FT_Face)face, charcode, &gid); + } + int nmaps = FXFT_Get_Face_CharmapCount(face); + int m = 0; + while (m < nmaps) { + int nEncodingID = FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[m++]); + if (m_nEncodingID == nEncodingID) { + continue; + } + int error = FXFT_Select_Charmap(face, nEncodingID); + if (error) { + continue; + } + charcode = FT_Get_First_Char((FT_Face)face, &gid); + while (gid != 0) { + if (dwGlyphIndex == gid) { + m_nEncodingID = nEncodingID; + return charcode; + } + charcode = FT_Get_Next_Char((FT_Face)face, charcode, &gid); + } + } + return (FX_DWORD) - 1; +} +static const FX_DWORD gs_EncodingID[] = { + FXFM_ENCODING_MS_SYMBOL, + FXFM_ENCODING_UNICODE, + FXFM_ENCODING_MS_SJIS, + FXFM_ENCODING_MS_GB2312, + FXFM_ENCODING_MS_BIG5, + FXFM_ENCODING_MS_WANSUNG, + FXFM_ENCODING_MS_JOHAB, + FXFM_ENCODING_ADOBE_STANDARD, + FXFM_ENCODING_ADOBE_EXPERT, + FXFM_ENCODING_ADOBE_CUSTOM, + FXFM_ENCODING_ADOBE_LATIN_1, + FXFM_ENCODING_OLD_LATIN_2, + FXFM_ENCODING_APPLE_ROMAN +}; +static IFX_FontEncodingEx* _FXFM_CreateFontEncoding(CFX_Font* pFont, FX_DWORD nEncodingID) +{ + int error = FXFT_Select_Charmap(pFont->m_Face, nEncodingID); + if (error) { + return NULL; + } + CFX_FontEncodingEX* pFontEncoding = FX_NEW CFX_FontEncodingEX; + if (pFontEncoding && !pFontEncoding->Init(pFont, nEncodingID)) { + delete pFontEncoding; + pFontEncoding = NULL; + } + return pFontEncoding; +} +IFX_FontEncodingEx* FX_CreateFontEncodingEx(CFX_Font* pFont, FX_DWORD nEncodingID) +{ + if (!pFont || !pFont->m_Face) { + return NULL; + } + if (nEncodingID != FXFM_ENCODING_NONE) { + return _FXFM_CreateFontEncoding(pFont, nEncodingID); + } + static int s_count = sizeof(gs_EncodingID) / sizeof(FX_DWORD); + for (int i = 0; i < s_count; i++) { + IFX_FontEncodingEx* pFontEncoding = _FXFM_CreateFontEncoding(pFont, gs_EncodingID[i]); + if (pFontEncoding) { + return pFontEncoding; + } + } + return NULL; +} diff --git a/core/src/fxge/ge/fx_ge_fontmap.cpp b/core/src/fxge/ge/fx_ge_fontmap.cpp index a5fa6443a8..fe790d8664 100644 --- a/core/src/fxge/ge/fx_ge_fontmap.cpp +++ b/core/src/fxge/ge/fx_ge_fontmap.cpp @@ -1156,6 +1156,9 @@ FXFT_Face CFX_FontMapper::FindSubstFont(const CFX_ByteString& name, FX_BOOL bTru pSubstFont->m_SubstFlags |= FXFONT_SUBST_EXACT; } if (hFont == NULL) { + if (flags & FXFONT_EXACTMATCH) { + return NULL; + } if (bCJK) { if (italic_angle != 0) { bItalic = TRUE; @@ -1284,6 +1287,68 @@ FXFT_Face CFX_FontMapper::FindSubstFont(const CFX_ByteString& name, FX_BOOL bTru m_pFontInfo->DeleteFont(hFont); return face; } +FXFT_Face CFX_FontMapper::FindSubstFontByUnicode(FX_DWORD dwUnicode, FX_DWORD flags, int weight, int italic_angle) +{ + if (m_pFontInfo == NULL) { + return NULL; + } + FX_BOOL bItalic = (flags & FXFONT_ITALIC) != 0; + int PitchFamily = 0; + if (flags & FXFONT_SERIF) { + PitchFamily |= FXFONT_FF_ROMAN; + } + if (flags & FXFONT_SCRIPT) { + PitchFamily |= FXFONT_FF_SCRIPT; + } + if (flags & FXFONT_FIXED_PITCH) { + PitchFamily |= FXFONT_FF_FIXEDPITCH; + } + void* hFont = m_pFontInfo->MapFontByUnicode(dwUnicode, weight, bItalic, PitchFamily); + if (hFont == NULL) { + return NULL; + } + FX_DWORD ttc_size = m_pFontInfo->GetFontData(hFont, 0x74746366, NULL, 0); + FX_DWORD font_size = m_pFontInfo->GetFontData(hFont, 0, NULL, 0); + if(font_size == 0 && ttc_size == 0) { + m_pFontInfo->DeleteFont(hFont); + return NULL; + } + FXFT_Face face = NULL; + if (ttc_size) { + FX_BYTE temp[1024]; + m_pFontInfo->GetFontData(hFont, 0x74746366, temp, 1024); + FX_DWORD checksum = 0; + for (int i = 0; i < 256; i ++) { + checksum += ((FX_DWORD*)temp)[i]; + } + FX_LPBYTE pFontData; + face = m_pFontMgr->GetCachedTTCFace(ttc_size, checksum, ttc_size - font_size, pFontData); + if (face == NULL) { + pFontData = FX_Alloc(FX_BYTE, ttc_size); + if (pFontData) { + m_pFontInfo->GetFontData(hFont, 0x74746366, pFontData, ttc_size); + face = m_pFontMgr->AddCachedTTCFace(ttc_size, checksum, pFontData, ttc_size, + ttc_size - font_size); + } + } + } else { + CFX_ByteString SubstName; + m_pFontInfo->GetFaceName(hFont, SubstName); + FX_LPBYTE pFontData; + face = m_pFontMgr->GetCachedFace(SubstName, weight, bItalic, pFontData); + if (face == NULL) { + pFontData = FX_Alloc(FX_BYTE, font_size); + if (!pFontData) { + m_pFontInfo->DeleteFont(hFont); + return NULL; + } + m_pFontInfo->GetFontData(hFont, 0, pFontData, font_size); + face = m_pFontMgr->AddCachedFace(SubstName, weight, bItalic, pFontData, font_size, m_pFontInfo->GetFaceIndex(hFont)); + } + } + m_pFontInfo->DeleteFont(hFont); + return face; +} extern "C" { unsigned long _FTStreamRead(FXFT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count); @@ -1483,6 +1548,10 @@ void* CFX_FolderFontInfo::MapFont(int weight, FX_BOOL bItalic, int charset, int { return NULL; } +void* CFX_FolderFontInfo::MapFontByUnicode(FX_DWORD dwUnicode, int weight, FX_BOOL bItalic, int pitch_family) +{ + return NULL; +} void* CFX_FolderFontInfo::GetFont(FX_LPCSTR face) { FX_LPVOID p; diff --git a/core/src/fxge/ge/text_int.h b/core/src/fxge/ge/text_int.h index c8d55965e3..e51976f172 100644 --- a/core/src/fxge/ge/text_int.h +++ b/core/src/fxge/ge/text_int.h @@ -101,5 +101,24 @@ public: int m_PitchFamily; CFX_ByteString m_FontTables; }; - +class CFX_FontEncodingEX : public IFX_FontEncodingEx +{ +public: + CFX_FontEncodingEX(); + FX_BOOL Init(CFX_Font* pFont, FX_DWORD EncodingID); + virtual FX_DWORD GlyphIndexFromName(FX_LPCSTR pStrName); + virtual CFX_ByteString NameFromGlyphIndex(FX_DWORD dwGlyphIndex); + virtual FX_DWORD CharCodeFromGlyphIndex(FX_DWORD dwGlyphIndex); + virtual FX_DWORD GlyphFromCharCode(FX_DWORD charcode); + virtual CFX_WideString UnicodeFromCharCode(FX_DWORD charcode) const; + virtual FX_DWORD CharCodeFromUnicode(FX_WCHAR Unicode) const; + virtual FX_BOOL IsUnicodeCompatible() const; + virtual FX_DWORD GlyphFromCharCodeEx(FX_DWORD charcode, int encoding = ENCODING_UNICODE) + { + return GlyphFromCharCode(charcode); + } +private: + CFX_Font* m_pFont; + FX_DWORD m_nEncodingID; +}; #endif // _TEXT_INT_H_ -- cgit v1.2.3