#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#include "tiffiop.h"
#ifdef OJPEG_SUPPORT
#define SETJMP(jbuf) setjmp(jbuf)
#define LONGJMP(jbuf, code) longjmp(jbuf, code)
#define JMP_BUF jmp_buf
#define OJPEG_BUFFER 2048
#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 <setjmp.h>
#endif
#ifdef FAR
#undef FAR
#endif
#if defined(__BORLANDC__) || defined(__MINGW32__)
#define XMD_H 1
#endif
#if defined(__WIN32__) && !defined(__MINGW32__)
#ifndef __RPCNDR_H__
typedef unsigned char boolean;
#endif
#define HAVE_BOOLEAN
#endif
#include "jerror.h"
#include "jpeglib.h"
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;
int decoder_ok;
int error_in_raw_data_decoding;
#ifndef LIBJPEG_ENCAP_EXTERNAL
JMP_BUF exit_jmpbuf;
#endif
TIFFVGetMethod vgetparent;
TIFFVSetMethod vsetparent;
TIFFPrintMethod printdir;
uint64_t file_size;
uint32_t image_width;
uint32_t image_length;
uint32_t strile_width;
uint32_t strile_length;
uint32_t strile_length_total;
uint8_t samples_per_pixel;
uint8_t plane_sample_offset;
uint8_t samples_per_pixel_per_plane;
uint64_t jpeg_interchange_format;
uint64_t jpeg_interchange_format_length;
uint8_t jpeg_proc;
uint8_t subsamplingcorrect;
uint8_t subsamplingcorrect_done;
uint8_t subsampling_tag;
uint8_t subsampling_hor;
uint8_t subsampling_ver;
uint8_t subsampling_force_desubsampling_inside_decompression;
uint8_t qtable_offset_count;
uint8_t dctable_offset_count;
uint8_t actable_offset_count;
uint64_t qtable_offset[3];
uint64_t dctable_offset[3];
uint64_t actable_offset[3];
uint8_t *qtable[4];
uint8_t *dctable[4];
uint8_t *actable[4];
uint16_t restart_interval;
uint8_t restart_index;
uint8_t sof_log;
uint8_t sof_marker_id;
uint32_t sof_x;
uint32_t sof_y;
uint8_t sof_c[3];
uint8_t sof_hv[3];
uint8_t sof_tq[3];
uint8_t sos_cs[3];
uint8_t sos_tda[3];
struct
{
uint8_t log;
OJPEGStateInBufferSource in_buffer_source;
uint32_t in_buffer_next_strile;
uint64_t in_buffer_file_pos;
uint64_t in_buffer_file_togo;
} sos_end[3];
uint8_t readheader_done;
uint8_t writeheader_done;
uint16_t write_cursample;
uint32_t write_curstrile;
uint8_t libjpeg_session_active;
uint8_t 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_t subsampling_convert_log;
uint32_t subsampling_convert_ylinelen;
uint32_t subsampling_convert_ylines;
uint32_t subsampling_convert_clinelen;
uint32_t subsampling_convert_clines;
uint32_t subsampling_convert_ybuflen;
uint32_t subsampling_convert_cbuflen;
uint32_t subsampling_convert_ycbcrbuflen;
uint8_t *subsampling_convert_ycbcrbuf;
uint8_t *subsampling_convert_ybuf;
uint8_t *subsampling_convert_cbbuf;
uint8_t *subsampling_convert_crbuf;
uint32_t subsampling_convert_ycbcrimagelen;
uint8_t **subsampling_convert_ycbcrimage;
uint32_t subsampling_convert_clinelenout;
uint32_t subsampling_convert_state;
uint32_t bytes_per_line;
uint32_t lines_per_strile;
OJPEGStateInBufferSource in_buffer_source;
uint32_t in_buffer_next_strile;
uint32_t in_buffer_strile_count;
uint64_t in_buffer_file_pos;
uint8_t in_buffer_file_pos_log;
uint64_t in_buffer_file_togo;
uint16_t in_buffer_togo;
uint8_t *in_buffer_cur;
uint8_t in_buffer[OJPEG_BUFFER];
OJPEGStateOutState out_state;
uint8_t out_buffer[OJPEG_BUFFER];
uint8_t *skip_buffer;
} OJPEGState;
static int OJPEGVGetField(TIFF *tif, uint32_t tag, va_list ap);
static int OJPEGVSetField(TIFF *tif, uint32_t 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_t s);
static int OJPEGPreDecodeSkipRaw(TIFF *tif);
static int OJPEGPreDecodeSkipScanlines(TIFF *tif);
static int OJPEGDecode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s);
static int OJPEGDecodeRaw(TIFF *tif, uint8_t *buf, tmsize_t cc);
static int OJPEGDecodeScanlines(TIFF *tif, uint8_t *buf, tmsize_t cc);
static void OJPEGPostDecode(TIFF *tif, uint8_t *buf, tmsize_t cc);
static int OJPEGSetupEncode(TIFF *tif);
static int OJPEGPreEncode(TIFF *tif, uint16_t s);
static int OJPEGEncode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t 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_t 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_t 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_t *byte);
static int OJPEGReadBytePeek(OJPEGState *sp, uint8_t *byte);
static void OJPEGReadByteAdvance(OJPEGState *sp);
static int OJPEGReadWord(OJPEGState *sp, uint16_t *word);
static int OJPEGReadBlock(OJPEGState *sp, uint16_t len, void *mem);
static void OJPEGReadSkip(OJPEGState *sp, uint16_t len);
static int OJPEGWriteStream(TIFF *tif, void **mem, uint32_t *len);
static void OJPEGWriteStreamSoi(TIFF *tif, void **mem, uint32_t *len);
static void OJPEGWriteStreamQTable(TIFF *tif, uint8_t table_index, void **mem,
uint32_t *len);
static void OJPEGWriteStreamDcTable(TIFF *tif, uint8_t table_index, void **mem,
uint32_t *len);
static void OJPEGWriteStreamAcTable(TIFF *tif, uint8_t table_index, void **mem,
uint32_t *len);
static void OJPEGWriteStreamDri(TIFF *tif, void **mem, uint32_t *len);
static void OJPEGWriteStreamSof(TIFF *tif, void **mem, uint32_t *len);
static void OJPEGWriteStreamSos(TIFF *tif, void **mem, uint32_t *len);
static int OJPEGWriteStreamCompressed(TIFF *tif, void **mem, uint32_t *len);
static void OJPEGWriteStreamRst(TIFF *tif, void **mem, uint32_t *len);
static void OJPEGWriteStreamEoi(TIFF *tif, void **mem, uint32_t *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_t 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_t max_lines);
extern int jpeg_read_raw_data_encap(OJPEGState *sp,
jpeg_decompress_struct *cinfo, void *data,
uint32_t 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_t 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_t max_lines);
static int jpeg_read_raw_data_encap(OJPEGState *sp,
jpeg_decompress_struct *cinfo, void *data,
uint32_t 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;
(void)scheme;
assert(scheme == COMPRESSION_OJPEG);
if (!_TIFFMergeFields(tif, ojpegFields, TIFFArrayCount(ojpegFields)))
{
TIFFErrorExtR(tif, module,
"Merging Old JPEG codec-specific tags failed");
return 0;
}
sp = _TIFFmallocExt(tif, sizeof(OJPEGState));
if (sp == NULL)
{
TIFFErrorExtR(tif, 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->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_t *)sp;
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;
tif->tif_flags |= TIFF_NOREADRAW;
return (1);
}
static int OJPEGVGetField(TIFF *tif, uint32_t tag, va_list ap)
{
OJPEGState *sp = (OJPEGState *)tif->tif_data;
switch (tag)
{
case TIFFTAG_JPEGIFOFFSET:
*va_arg(ap, uint64_t *) = (uint64_t)sp->jpeg_interchange_format;
break;
case TIFFTAG_JPEGIFBYTECOUNT:
*va_arg(ap, uint64_t *) =
(uint64_t)sp->jpeg_interchange_format_length;
break;
case TIFFTAG_YCBCRSUBSAMPLING:
if (sp->subsamplingcorrect_done == 0)
OJPEGSubsamplingCorrect(tif);
*va_arg(ap, uint16_t *) = (uint16_t)sp->subsampling_hor;
*va_arg(ap, uint16_t *) = (uint16_t)sp->subsampling_ver;
break;
case TIFFTAG_JPEGQTABLES:
*va_arg(ap, uint32_t *) = (uint32_t)sp->qtable_offset_count;
*va_arg(ap, const void **) = (const void *)sp->qtable_offset;
break;
case TIFFTAG_JPEGDCTABLES:
*va_arg(ap, uint32_t *) = (uint32_t)sp->dctable_offset_count;
*va_arg(ap, const void **) = (const void *)sp->dctable_offset;
break;
case TIFFTAG_JPEGACTABLES:
*va_arg(ap, uint32_t *) = (uint32_t)sp->actable_offset_count;
*va_arg(ap, const void **) = (const void *)sp->actable_offset;
break;
case TIFFTAG_JPEGPROC:
*va_arg(ap, uint16_t *) = (uint16_t)sp->jpeg_proc;
break;
case TIFFTAG_JPEGRESTARTINTERVAL:
*va_arg(ap, uint16_t *) = sp->restart_interval;
break;
default:
return (*sp->vgetparent)(tif, tag, ap);
}
return (1);
}
static int OJPEGVSetField(TIFF *tif, uint32_t tag, va_list ap)
{
static const char module[] = "OJPEGVSetField";
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint32_t ma;
uint64_t *mb;
uint32_t n;
const TIFFField *fip;
switch (tag)
{
case TIFFTAG_JPEGIFOFFSET:
sp->jpeg_interchange_format = (uint64_t)va_arg(ap, uint64_t);
break;
case TIFFTAG_JPEGIFBYTECOUNT:
sp->jpeg_interchange_format_length = (uint64_t)va_arg(ap, uint64_t);
break;
case TIFFTAG_YCBCRSUBSAMPLING:
sp->subsampling_tag = 1;
sp->subsampling_hor = (uint8_t)va_arg(ap, uint16_vap);
sp->subsampling_ver = (uint8_t)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_t)va_arg(ap, uint32_t);
if (ma != 0)
{
if (ma > 3)
{
TIFFErrorExtR(tif, module,
"JpegQTables tag has incorrect count");
return (0);
}
sp->qtable_offset_count = (uint8_t)ma;
mb = (uint64_t *)va_arg(ap, uint64_t *);
for (n = 0; n < ma; n++)
sp->qtable_offset[n] = mb[n];
}
break;
case TIFFTAG_JPEGDCTABLES:
ma = (uint32_t)va_arg(ap, uint32_t);
if (ma != 0)
{
if (ma > 3)
{
TIFFErrorExtR(tif, module,
"JpegDcTables tag has incorrect count");
return (0);
}
sp->dctable_offset_count = (uint8_t)ma;
mb = (uint64_t *)va_arg(ap, uint64_t *);
for (n = 0; n < ma; n++)
sp->dctable_offset[n] = mb[n];
}
break;
case TIFFTAG_JPEGACTABLES:
ma = (uint32_t)va_arg(ap, uint32_t);
if (ma != 0)
{
if (ma > 3)
{
TIFFErrorExtR(tif, module,
"JpegAcTables tag has incorrect count");
return (0);
}
sp->actable_offset_count = (uint8_t)ma;
mb = (uint64_t *)va_arg(ap, uint64_t *);
for (n = 0; n < ma; n++)
sp->actable_offset[n] = mb[n];
}
break;
case TIFFTAG_JPEGPROC:
sp->jpeg_proc = (uint8_t)va_arg(ap, uint16_vap);
break;
case TIFFTAG_JPEGRESTARTINTERVAL:
sp->restart_interval = (uint16_t)va_arg(ap, uint16_vap);
break;
default:
return (*sp->vsetparent)(tif, tag, ap);
}
fip = TIFFFieldWithTag(tif, tag);
if (fip == NULL)
return (0);
TIFFSetFieldBit(tif, fip->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_t m;
(void)flags;
assert(sp != NULL);
if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGINTERCHANGEFORMAT))
fprintf(fd, " JpegInterchangeFormat: %" PRIu64 "\n",
(uint64_t)sp->jpeg_interchange_format);
if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH))
fprintf(fd, " JpegInterchangeFormatLength: %" PRIu64 "\n",
(uint64_t)sp->jpeg_interchange_format_length);
if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGQTABLES))
{
fprintf(fd, " JpegQTables:");
for (m = 0; m < sp->qtable_offset_count; m++)
fprintf(fd, " %" PRIu64, (uint64_t)sp->qtable_offset[m]);
fprintf(fd, "\n");
}
if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGDCTABLES))
{
fprintf(fd, " JpegDcTables:");
for (m = 0; m < sp->dctable_offset_count; m++)
fprintf(fd, " %" PRIu64, (uint64_t)sp->dctable_offset[m]);
fprintf(fd, "\n");
}
if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGACTABLES))
{
fprintf(fd, " JpegAcTables:");
for (m = 0; m < sp->actable_offset_count; m++)
fprintf(fd, " %" PRIu64, (uint64_t)sp->actable_offset[m]);
fprintf(fd, "\n");
}
if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGPROC))
fprintf(fd, " JpegProc: %" PRIu8 "\n", sp->jpeg_proc);
if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGRESTARTINTERVAL))
fprintf(fd, " JpegRestartInterval: %" PRIu16 "\n",
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";
TIFFWarningExtR(tif, module,
"Deprecated 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_t s)
{
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint32_t 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_t)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_curstrile < m)
{
if (sp->libjpeg_jpeg_query_style == 0)
{
if (OJPEGPreDecodeSkipRaw(tif) == 0)
return (0);
}
else
{
if (OJPEGPreDecodeSkipScanlines(tif) == 0)
return (0);
}
sp->write_curstrile++;
}
sp->decoder_ok = 1;
return (1);
}
static int OJPEGPreDecodeSkipRaw(TIFF *tif)
{
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint32_t 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;
sp->error_in_raw_data_decoding = 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_t m;
if (sp->skip_buffer == NULL)
{
sp->skip_buffer = _TIFFmallocExt(tif, sp->bytes_per_line);
if (sp->skip_buffer == NULL)
{
TIFFErrorExtR(tif, module, "Out of memory");
return (0);
}
}
for (m = 0; m < sp->lines_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_t *buf, tmsize_t cc, uint16_t s)
{
static const char module[] = "OJPEGDecode";
OJPEGState *sp = (OJPEGState *)tif->tif_data;
(void)s;
if (!sp->decoder_ok)
{
TIFFErrorExtR(tif, module,
"Cannot decode: decoder not correctly initialized");
return 0;
}
if (sp->libjpeg_session_active == 0)
{
TIFFErrorExtR(tif, module,
"Cannot decode: libjpeg_session_active == 0");
return 0;
}
if (sp->error_in_raw_data_decoding)
{
return 0;
}
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_t *buf, tmsize_t cc)
{
static const char module[] = "OJPEGDecodeRaw";
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint8_t *m;
tmsize_t n;
uint8_t *oy;
uint8_t *ocb;
uint8_t *ocr;
uint8_t *p;
uint32_t q;
uint8_t *r;
uint8_t sx, sy;
if (cc % sp->bytes_per_line != 0)
{
TIFFErrorExtR(tif, 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)
{
sp->error_in_raw_data_decoding = 1;
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; q < sp->subsampling_convert_clinelenout; q++)
{
r = oy;
for (sy = 0; sy < sp->subsampling_ver; sy++)
{
for (sx = 0; sx < sp->subsampling_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_t *buf, tmsize_t cc)
{
static const char module[] = "OJPEGDecodeScanlines";
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint8_t *m;
tmsize_t n;
if (cc % sp->bytes_per_line != 0)
{
TIFFErrorExtR(tif, 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_t *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";
TIFFErrorExtR(
tif, module,
"OJPEG encoding not supported; use new-style JPEG compression instead");
return (0);
}
static int OJPEGPreEncode(TIFF *tif, uint16_t s)
{
static const char module[] = "OJPEGPreEncode";
(void)s;
TIFFErrorExtR(
tif, module,
"OJPEG encoding not supported; use new-style JPEG compression instead");
return (0);
}
static int OJPEGEncode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s)
{
static const char module[] = "OJPEGEncode";
(void)buf;
(void)cc;
(void)s;
TIFFErrorExtR(
tif, module,
"OJPEG encoding not supported; use new-style JPEG compression instead");
return (0);
}
static int OJPEGPostEncode(TIFF *tif)
{
static const char module[] = "OJPEGPostEncode";
TIFFErrorExtR(
tif, 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)
_TIFFfreeExt(tif, sp->qtable[0]);
if (sp->qtable[1] != 0)
_TIFFfreeExt(tif, sp->qtable[1]);
if (sp->qtable[2] != 0)
_TIFFfreeExt(tif, sp->qtable[2]);
if (sp->qtable[3] != 0)
_TIFFfreeExt(tif, sp->qtable[3]);
if (sp->dctable[0] != 0)
_TIFFfreeExt(tif, sp->dctable[0]);
if (sp->dctable[1] != 0)
_TIFFfreeExt(tif, sp->dctable[1]);
if (sp->dctable[2] != 0)
_TIFFfreeExt(tif, sp->dctable[2]);
if (sp->dctable[3] != 0)
_TIFFfreeExt(tif, sp->dctable[3]);
if (sp->actable[0] != 0)
_TIFFfreeExt(tif, sp->actable[0]);
if (sp->actable[1] != 0)
_TIFFfreeExt(tif, sp->actable[1]);
if (sp->actable[2] != 0)
_TIFFfreeExt(tif, sp->actable[2]);
if (sp->actable[3] != 0)
_TIFFfreeExt(tif, sp->actable[3]);
if (sp->libjpeg_session_active != 0)
OJPEGLibjpegSessionAbort(tif);
if (sp->subsampling_convert_ycbcrbuf != 0)
_TIFFfreeExt(tif, sp->subsampling_convert_ycbcrbuf);
if (sp->subsampling_convert_ycbcrimage != 0)
_TIFFfreeExt(tif, sp->subsampling_convert_ycbcrimage);
if (sp->skip_buffer != 0)
_TIFFfreeExt(tif, sp->skip_buffer);
_TIFFfreeExt(tif, sp);
tif->tif_data = NULL;
_TIFFSetDefaultCompressionState(tif);
}
}
static void OJPEGSubsamplingCorrect(TIFF *tif)
{
static const char module[] = "OJPEGSubsamplingCorrect";
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint8_t mh;
uint8_t mv;
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)
TIFFWarningExtR(tif, 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)
TIFFWarningExtR(
tif, module,
"Subsampling tag is not set, yet subsampling inside JPEG "
"data [%" PRIu8 ",%" PRIu8
"] does not match default values [2,2]; assuming "
"subsampling inside JPEG data is correct",
sp->subsampling_hor, sp->subsampling_ver);
else
TIFFWarningExtR(
tif, module,
"Subsampling inside JPEG data [%" PRIu8 ",%" PRIu8
"] does not match subsampling tag values [%" PRIu8
",%" PRIu8
"]; 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)
TIFFWarningExtR(
tif, 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
TIFFWarningExtR(
tif, module,
"Subsampling inside JPEG data does not match subsampling "
"tag values [%" PRIu8 ",%" PRIu8
"] (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_hor < sp->subsampling_ver)
TIFFWarningExtR(tif, module,
"Subsampling values [%" PRIu8 ",%" PRIu8
"] 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;
if (sp->strile_length == (uint32_t)-1)
sp->strile_length = sp->image_length;
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)
{
TIFFErrorExtR(tif, module,
"SamplesPerPixel %" PRIu8
" 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_length < sp->image_length)
{
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)))
{
TIFFErrorExtR(tif, module, "Invalid subsampling values");
return (0);
}
if (sp->strile_length % (sp->subsampling_ver * 8) != 0)
{
TIFFErrorExtR(tif, module,
"Incompatible vertical subsampling and image "
"strip/tile length");
return (0);
}
sp->restart_interval =
(uint16_t)(((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_t s)
{
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint8_t 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 = (uint8_t)(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_offset < s)
{
do
{
if (OJPEGReadByte(sp, &m) == 0)
return (0);
if (m == 255)
{
do
{
if (OJPEGReadByte(sp, &m) == 0)
return (0);
if (m != 255)
break;
} while (1);
if (m == JPEG_MARKER_SOS)
break;
}
} while (1);
sp->plane_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_t **m;
uint32_t n;
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);
if (sp->subsampling_hor == 0 || sp->subsampling_ver == 0)
return (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 =
_TIFFcallocExt(tif, 1, sp->subsampling_convert_ycbcrbuflen);
if (sp->subsampling_convert_ycbcrbuf == 0)
{
TIFFErrorExtR(tif, 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 = _TIFFmallocExt(
tif, sp->subsampling_convert_ycbcrimagelen * sizeof(uint8_t *));
if (sp->subsampling_convert_ycbcrimage == 0)
{
TIFFErrorExtR(tif, module, "Out of memory");
return (0);
}
m = sp->subsampling_convert_ycbcrimage;
*m++ = (uint8_t *)(sp->subsampling_convert_ycbcrimage + 3);
*m++ = (uint8_t *)(sp->subsampling_convert_ycbcrimage + 3 +
sp->subsampling_convert_ylines);
*m++ = (uint8_t *)(sp->subsampling_convert_ycbcrimage + 3 +
sp->subsampling_convert_ylines +
sp->subsampling_convert_clines);
for (n = 0; n < sp->subsampling_convert_ylines; n++)
*m++ = sp->subsampling_convert_ybuf +
n * sp->subsampling_convert_ylinelen;
for (n = 0; n < sp->subsampling_convert_clines; n++)
*m++ = sp->subsampling_convert_cbbuf +
n * sp->subsampling_convert_clinelen;
for (n = 0; n < sp->subsampling_convert_clines; n++)
*m++ = sp->subsampling_convert_crbuf +
n * sp->subsampling_convert_clinelen;
sp->subsampling_convert_clinelenout =
sp->strile_width / sp->subsampling_hor +
((sp->strile_width % sp->subsampling_hor) != 0 ? 1 : 0);
sp->subsampling_convert_state = 0;
sp->error_in_raw_data_decoding = 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 +
((sp->strile_length % sp->subsampling_ver) != 0 ? 1 : 0);
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);
if (sp->libjpeg_jpeg_decompress_struct.image_width != sp->strile_width)
{
TIFFErrorExtR(tif, module,
"jpeg_start_decompress() returned image_width = %u, "
"expected %" PRIu32,
sp->libjpeg_jpeg_decompress_struct.image_width,
sp->strile_width);
return 0;
}
if (sp->libjpeg_jpeg_decompress_struct.max_h_samp_factor !=
sp->subsampling_hor ||
sp->libjpeg_jpeg_decompress_struct.max_v_samp_factor !=
sp->subsampling_ver)
{
TIFFErrorExtR(tif, module,
"jpeg_start_decompress() returned max_h_samp_factor = %d "
"and max_v_samp_factor = %d, expected %" PRIu8
" and %" PRIu8,
sp->libjpeg_jpeg_decompress_struct.max_h_samp_factor,
sp->libjpeg_jpeg_decompress_struct.max_v_samp_factor,
sp->subsampling_hor, sp->subsampling_ver);
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_t m;
uint16_t n;
uint8_t 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 >
UINT64_MAX - sp->jpeg_interchange_format_length) ||
(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:
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:
if (OJPEGReadWord(sp, &n) == 0)
return (0);
if (n < 2)
{
if (sp->subsamplingcorrect == 0)
TIFFErrorExtR(tif, 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:
TIFFErrorExtR(tif, module,
"Unknown marker type %" PRIu8 " 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; o < sp->samples_per_pixel; o++)
sp->sof_c[o] = o;
sp->sof_hv[0] = ((sp->subsampling_hor << 4) | sp->subsampling_ver);
for (o = 1; o < sp->samples_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; o < sp->samples_per_pixel; o++)
sp->sos_cs[o] = o;
}
return (1);
}
static int OJPEGReadHeaderInfoSecStreamDri(TIFF *tif)
{
static const char module[] = "OJPEGReadHeaderInfoSecStreamDri";
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint16_t m;
if (OJPEGReadWord(sp, &m) == 0)
return (0);
if (m != 4)
{
TIFFErrorExtR(tif, 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)
{
static const char module[] = "OJPEGReadHeaderInfoSecStreamDqt";
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint16_t m;
uint32_t na;
uint8_t *nb;
uint8_t o;
if (OJPEGReadWord(sp, &m) == 0)
return (0);
if (m <= 2)
{
if (sp->subsamplingcorrect == 0)
TIFFErrorExtR(tif, module, "Corrupt DQT marker in JPEG data");
return (0);
}
if (sp->subsamplingcorrect != 0)
OJPEGReadSkip(sp, m - 2);
else
{
m -= 2;
do
{
if (m < 65)
{
TIFFErrorExtR(tif, module, "Corrupt DQT marker in JPEG data");
return (0);
}
na = sizeof(uint32_t) + 69;
nb = _TIFFmallocExt(tif, na);
if (nb == 0)
{
TIFFErrorExtR(tif, module, "Out of memory");
return (0);
}
*(uint32_t *)nb = na;
nb[sizeof(uint32_t)] = 255;
nb[sizeof(uint32_t) + 1] = JPEG_MARKER_DQT;
nb[sizeof(uint32_t) + 2] = 0;
nb[sizeof(uint32_t) + 3] = 67;
if (OJPEGReadBlock(sp, 65, &nb[sizeof(uint32_t) + 4]) == 0)
{
_TIFFfreeExt(tif, nb);
return (0);
}
o = nb[sizeof(uint32_t) + 4] & 15;
if (3 < o)
{
TIFFErrorExtR(tif, module, "Corrupt DQT marker in JPEG data");
_TIFFfreeExt(tif, nb);
return (0);
}
if (sp->qtable[o] != 0)
_TIFFfreeExt(tif, sp->qtable[o]);
sp->qtable[o] = nb;
m -= 65;
} while (m > 0);
}
return (1);
}
static int OJPEGReadHeaderInfoSecStreamDht(TIFF *tif)
{
static const char module[] = "OJPEGReadHeaderInfoSecStreamDht";
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint16_t m;
uint32_t na;
uint8_t *nb;
uint8_t o;
if (OJPEGReadWord(sp, &m) == 0)
return (0);
if (m <= 2)
{
if (sp->subsamplingcorrect == 0)
TIFFErrorExtR(tif, module, "Corrupt DHT marker in JPEG data");
return (0);
}
if (sp->subsamplingcorrect != 0)
{
OJPEGReadSkip(sp, m - 2);
}
else
{
na = sizeof(uint32_t) + 2 + m;
nb = _TIFFmallocExt(tif, na);
if (nb == 0)
{
TIFFErrorExtR(tif, module, "Out of memory");
return (0);
}
*(uint32_t *)nb = na;
nb[sizeof(uint32_t)] = 255;
nb[sizeof(uint32_t) + 1] = JPEG_MARKER_DHT;
nb[sizeof(uint32_t) + 2] = (m >> 8);
nb[sizeof(uint32_t) + 3] = (m & 255);
if (OJPEGReadBlock(sp, m - 2, &nb[sizeof(uint32_t) + 4]) == 0)
{
_TIFFfreeExt(tif, nb);
return (0);
}
o = nb[sizeof(uint32_t) + 4];
if ((o & 240) == 0)
{
if (3 < o)
{
TIFFErrorExtR(tif, module, "Corrupt DHT marker in JPEG data");
_TIFFfreeExt(tif, nb);
return (0);
}
if (sp->dctable[o] != 0)
_TIFFfreeExt(tif, sp->dctable[o]);
sp->dctable[o] = nb;
}
else
{
if ((o & 240) != 16)
{
TIFFErrorExtR(tif, module, "Corrupt DHT marker in JPEG data");
_TIFFfreeExt(tif, nb);
return (0);
}
o &= 15;
if (3 < o)
{
TIFFErrorExtR(tif, module, "Corrupt DHT marker in JPEG data");
_TIFFfreeExt(tif, nb);
return (0);
}
if (sp->actable[o] != 0)
_TIFFfreeExt(tif, sp->actable[o]);
sp->actable[o] = nb;
}
}
return (1);
}
static int OJPEGReadHeaderInfoSecStreamSof(TIFF *tif, uint8_t marker_id)
{
static const char module[] = "OJPEGReadHeaderInfoSecStreamSof";
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint16_t m;
uint16_t n;
uint8_t o;
uint16_t p;
uint16_t q;
if (sp->sof_log != 0)
{
TIFFErrorExtR(tif, module, "Corrupt JPEG data");
return (0);
}
if (sp->subsamplingcorrect == 0)
sp->sof_marker_id = marker_id;
if (OJPEGReadWord(sp, &m) == 0)
return (0);
if (m < 11)
{
if (sp->subsamplingcorrect == 0)
TIFFErrorExtR(tif, module, "Corrupt SOF marker in JPEG data");
return (0);
}
m -= 8;
if (m % 3 != 0)
{
if (sp->subsamplingcorrect == 0)
TIFFErrorExtR(tif, module, "Corrupt SOF marker in JPEG data");
return (0);
}
n = m / 3;
if (sp->subsamplingcorrect == 0)
{
if (n != sp->samples_per_pixel)
{
TIFFErrorExtR(
tif, module,
"JPEG compressed data indicates unexpected number of samples");
return (0);
}
}
if (OJPEGReadByte(sp, &o) == 0)
return (0);
if (o != 8)
{
if (sp->subsamplingcorrect == 0)
TIFFErrorExtR(tif, module,
"JPEG compressed data indicates unexpected number of "
"bits per sample");
return (0);
}
if (sp->subsamplingcorrect)
OJPEGReadSkip(sp, 4);
else
{
if (OJPEGReadWord(sp, &p) == 0)
return (0);
if (((uint32_t)p < sp->image_length) &&
((uint32_t)p < sp->strile_length_total))
{
TIFFErrorExtR(tif, module,
"JPEG compressed data indicates unexpected height");
return (0);
}
sp->sof_y = p;
if (OJPEGReadWord(sp, &p) == 0)
return (0);
if (((uint32_t)p < sp->image_width) && ((uint32_t)p < sp->strile_width))
{
TIFFErrorExtR(tif, module,
"JPEG compressed data indicates unexpected width");
return (0);
}
if ((uint32_t)p > sp->strile_width)
{
TIFFErrorExtR(tif, module,
"JPEG compressed data image width exceeds expected "
"image width");
return (0);
}
sp->sof_x = p;
}
if (OJPEGReadByte(sp, &o) == 0)
return (0);
if (o != n)
{
if (sp->subsamplingcorrect == 0)
TIFFErrorExtR(tif, module, "Corrupt SOF marker in JPEG data");
return (0);
}
for (q = 0; q < n; q++)
{
if (OJPEGReadByte(sp, &o) == 0)
return (0);
if (sp->subsamplingcorrect == 0)
sp->sof_c[q] = o;
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))
{
TIFFErrorExtR(tif, module,
"JPEG compressed data indicates "
"unexpected subsampling values");
return (0);
}
}
else
{
if (o != 17)
{
TIFFErrorExtR(tif, module,
"JPEG compressed data indicates "
"unexpected subsampling values");
return (0);
}
}
}
}
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)
{
static const char module[] = "OJPEGReadHeaderInfoSecStreamSos";
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint16_t m;
uint8_t n;
uint8_t o;
assert(sp->subsamplingcorrect == 0);
if (sp->sof_log == 0)
{
TIFFErrorExtR(tif, module, "Corrupt SOS marker in JPEG data");
return (0);
}
if (OJPEGReadWord(sp, &m) == 0)
return (0);
if (m != 6 + sp->samples_per_pixel_per_plane * 2)
{
TIFFErrorExtR(tif, module, "Corrupt SOS marker in JPEG data");
return (0);
}
if (OJPEGReadByte(sp, &n) == 0)
return (0);
if (n != sp->samples_per_pixel_per_plane)
{
TIFFErrorExtR(tif, module, "Corrupt SOS marker in JPEG data");
return (0);
}
for (o = 0; o < sp->samples_per_pixel_per_plane; o++)
{
if (OJPEGReadByte(sp, &n) == 0)
return (0);
sp->sos_cs[sp->plane_sample_offset + o] = n;
if (OJPEGReadByte(sp, &n) == 0)
return (0);
sp->sos_tda[sp->plane_sample_offset + o] = n;
}
OJPEGReadSkip(sp, 3);
return (1);
}
static int OJPEGReadHeaderInfoSecTablesQTable(TIFF *tif)
{
static const char module[] = "OJPEGReadHeaderInfoSecTablesQTable";
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint8_t m;
uint8_t n;
uint32_t oa;
uint8_t *ob;
uint32_t p;
if (sp->qtable_offset[0] == 0)
{
TIFFErrorExtR(tif, module, "Missing JPEG tables");
return (0);
}
sp->in_buffer_file_pos_log = 0;
for (m = 0; m < sp->samples_per_pixel; m++)
{
if ((sp->qtable_offset[m] != 0) &&
((m == 0) || (sp->qtable_offset[m] != sp->qtable_offset[m - 1])))
{
for (n = 0; n < m - 1; n++)
{
if (sp->qtable_offset[m] == sp->qtable_offset[n])
{
TIFFErrorExtR(tif, module, "Corrupt JpegQTables tag value");
return (0);
}
}
oa = sizeof(uint32_t) + 69;
ob = _TIFFmallocExt(tif, oa);
if (ob == 0)
{
TIFFErrorExtR(tif, module, "Out of memory");
return (0);
}
*(uint32_t *)ob = oa;
ob[sizeof(uint32_t)] = 255;
ob[sizeof(uint32_t) + 1] = JPEG_MARKER_DQT;
ob[sizeof(uint32_t) + 2] = 0;
ob[sizeof(uint32_t) + 3] = 67;
ob[sizeof(uint32_t) + 4] = m;
TIFFSeekFile(tif, sp->qtable_offset[m], SEEK_SET);
p = (uint32_t)TIFFReadFile(tif, &ob[sizeof(uint32_t) + 5], 64);
if (p != 64)
{
_TIFFfreeExt(tif, ob);
return (0);
}
if (sp->qtable[m] != 0)
_TIFFfreeExt(tif, sp->qtable[m]);
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_t m;
uint8_t n;
uint8_t o[16];
uint32_t p;
uint32_t q;
uint32_t ra;
uint8_t *rb;
if (sp->dctable_offset[0] == 0)
{
TIFFErrorExtR(tif, module, "Missing JPEG tables");
return (0);
}
sp->in_buffer_file_pos_log = 0;
for (m = 0; m < sp->samples_per_pixel; m++)
{
if ((sp->dctable_offset[m] != 0) &&
((m == 0) || (sp->dctable_offset[m] != sp->dctable_offset[m - 1])))
{
for (n = 0; n < m - 1; n++)
{
if (sp->dctable_offset[m] == sp->dctable_offset[n])
{
TIFFErrorExtR(tif, module,
"Corrupt JpegDcTables tag value");
return (0);
}
}
TIFFSeekFile(tif, sp->dctable_offset[m], SEEK_SET);
p = (uint32_t)TIFFReadFile(tif, o, 16);
if (p != 16)
return (0);
q = 0;
for (n = 0; n < 16; n++)
q += o[n];
ra = sizeof(uint32_t) + 21 + q;
rb = _TIFFmallocExt(tif, ra);
if (rb == 0)
{
TIFFErrorExtR(tif, module, "Out of memory");
return (0);
}
*(uint32_t *)rb = ra;
rb[sizeof(uint32_t)] = 255;
rb[sizeof(uint32_t) + 1] = JPEG_MARKER_DHT;
rb[sizeof(uint32_t) + 2] = (uint8_t)((19 + q) >> 8);
rb[sizeof(uint32_t) + 3] = ((19 + q) & 255);
rb[sizeof(uint32_t) + 4] = m;
for (n = 0; n < 16; n++)
rb[sizeof(uint32_t) + 5 + n] = o[n];
p = (uint32_t)TIFFReadFile(tif, &(rb[sizeof(uint32_t) + 21]), q);
if (p != q)
{
_TIFFfreeExt(tif, rb);
return (0);
}
if (sp->dctable[m] != 0)
_TIFFfreeExt(tif, sp->dctable[m]);
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_t m;
uint8_t n;
uint8_t o[16];
uint32_t p;
uint32_t q;
uint32_t ra;
uint8_t *rb;
if (sp->actable_offset[0] == 0)
{
TIFFErrorExtR(tif, module, "Missing JPEG tables");
return (0);
}
sp->in_buffer_file_pos_log = 0;
for (m = 0; m < sp->samples_per_pixel; m++)
{
if ((sp->actable_offset[m] != 0) &&
((m == 0) || (sp->actable_offset[m] != sp->actable_offset[m - 1])))
{
for (n = 0; n < m - 1; n++)
{
if (sp->actable_offset[m] == sp->actable_offset[n])
{
TIFFErrorExtR(tif, module,
"Corrupt JpegAcTables tag value");
return (0);
}
}
TIFFSeekFile(tif, sp->actable_offset[m], SEEK_SET);
p = (uint32_t)TIFFReadFile(tif, o, 16);
if (p != 16)
return (0);
q = 0;
for (n = 0; n < 16; n++)
q += o[n];
ra = sizeof(uint32_t) + 21 + q;
rb = _TIFFmallocExt(tif, ra);
if (rb == 0)
{
TIFFErrorExtR(tif, module, "Out of memory");
return (0);
}
*(uint32_t *)rb = ra;
rb[sizeof(uint32_t)] = 255;
rb[sizeof(uint32_t) + 1] = JPEG_MARKER_DHT;
rb[sizeof(uint32_t) + 2] = (uint8_t)((19 + q) >> 8);
rb[sizeof(uint32_t) + 3] = ((19 + q) & 255);
rb[sizeof(uint32_t) + 4] = (16 | m);
for (n = 0; n < 16; n++)
rb[sizeof(uint32_t) + 5 + n] = o[n];
p = (uint32_t)TIFFReadFile(tif, &(rb[sizeof(uint32_t) + 21]), q);
if (p != q)
{
_TIFFfreeExt(tif, rb);
return (0);
}
if (sp->actable[m] != 0)
_TIFFfreeExt(tif, sp->actable[m]);
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_t m;
tmsize_t n;
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_t)m > sp->in_buffer_file_togo)
m = (uint16_t)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_t)n <= sp->in_buffer_file_togo);
m = (uint16_t)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;
break;
case osibsStrile:
if (sp->in_buffer_next_strile == sp->in_buffer_strile_count)
sp->in_buffer_source = osibsEof;
else
{
int err = 0;
sp->in_buffer_file_pos = TIFFGetStrileOffsetWithErr(
sp->tif, sp->in_buffer_next_strile, &err);
if (err)
return 0;
if (sp->in_buffer_file_pos != 0)
{
uint64_t bytecount = TIFFGetStrileByteCountWithErr(
sp->tif, sp->in_buffer_next_strile, &err);
if (err)
return 0;
if (sp->in_buffer_file_pos >= sp->file_size)
sp->in_buffer_file_pos = 0;
else if (bytecount == 0)
sp->in_buffer_file_togo =
sp->file_size - sp->in_buffer_file_pos;
else
{
sp->in_buffer_file_togo = bytecount;
if (sp->in_buffer_file_togo == 0)
sp->in_buffer_file_pos = 0;
else if (sp->in_buffer_file_pos >
UINT64_MAX - sp->in_buffer_file_togo ||
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_t *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_t *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_t *word)
{
uint8_t 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_t len, void *mem)
{
uint16_t mlen;
uint8_t *mmem;
uint16_t n;
assert(len > 0);
mlen = len;
mmem = mem;
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_t len)
{
uint16_t m;
uint16_t 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_t)n > sp->in_buffer_file_togo)
n = (uint16_t)sp->in_buffer_file_togo;
sp->in_buffer_file_pos += n;
sp->in_buffer_file_togo -= n;
sp->in_buffer_file_pos_log = 0;
}
}
static int OJPEGWriteStream(TIFF *tif, void **mem, uint32_t *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_t *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_t table_index, void **mem,
uint32_t *len)
{
OJPEGState *sp = (OJPEGState *)tif->tif_data;
if (sp->qtable[table_index] != 0)
{
*mem = (void *)(sp->qtable[table_index] + sizeof(uint32_t));
*len = *((uint32_t *)sp->qtable[table_index]) - sizeof(uint32_t);
}
sp->out_state++;
}
static void OJPEGWriteStreamDcTable(TIFF *tif, uint8_t table_index, void **mem,
uint32_t *len)
{
OJPEGState *sp = (OJPEGState *)tif->tif_data;
if (sp->dctable[table_index] != 0)
{
*mem = (void *)(sp->dctable[table_index] + sizeof(uint32_t));
*len = *((uint32_t *)sp->dctable[table_index]) - sizeof(uint32_t);
}
sp->out_state++;
}
static void OJPEGWriteStreamAcTable(TIFF *tif, uint8_t table_index, void **mem,
uint32_t *len)
{
OJPEGState *sp = (OJPEGState *)tif->tif_data;
if (sp->actable[table_index] != 0)
{
*mem = (void *)(sp->actable[table_index] + sizeof(uint32_t));
*len = *((uint32_t *)sp->actable[table_index]) - sizeof(uint32_t);
}
sp->out_state++;
}
static void OJPEGWriteStreamDri(TIFF *tif, void **mem, uint32_t *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_t *len)
{
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint8_t 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;
sp->out_buffer[2] = 0;
sp->out_buffer[3] = 8 + sp->samples_per_pixel_per_plane * 3;
sp->out_buffer[4] = 8;
sp->out_buffer[5] = (uint8_t)(sp->sof_y >> 8);
sp->out_buffer[6] = (sp->sof_y & 255);
sp->out_buffer[7] = (uint8_t)(sp->sof_x >> 8);
sp->out_buffer[8] = (sp->sof_x & 255);
sp->out_buffer[9] = sp->samples_per_pixel_per_plane;
for (m = 0; m < sp->samples_per_pixel_per_plane; m++)
{
sp->out_buffer[10 + m * 3] = sp->sof_c[sp->plane_sample_offset + m];
sp->out_buffer[10 + m * 3 + 1] =
sp->sof_hv[sp->plane_sample_offset + m];
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_t *len)
{
OJPEGState *sp = (OJPEGState *)tif->tif_data;
uint8_t 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;
sp->out_buffer[2] = 0;
sp->out_buffer[3] = 6 + sp->samples_per_pixel_per_plane * 2;
sp->out_buffer[4] = sp->samples_per_pixel_per_plane;
for (m = 0; m < sp->samples_per_pixel_per_plane; m++)
{
sp->out_buffer[5 + m * 2] = sp->sos_cs[sp->plane_sample_offset + m];
sp->out_buffer[5 + m * 2 + 1] =
sp->sos_tda[sp->plane_sample_offset + m];
}
sp->out_buffer[5 + sp->samples_per_pixel_per_plane * 2] = 0;
sp->out_buffer[5 + sp->samples_per_pixel_per_plane * 2 + 1] = 63;
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_t *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_strile < sp->in_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_t *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_t *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)
{
if (SETJMP(sp->exit_jmpbuf))
return 0;
else
{
jpeg_create_decompress(cinfo);
return 1;
}
}
#endif
#ifndef LIBJPEG_ENCAP_EXTERNAL
static int jpeg_read_header_encap(OJPEGState *sp, jpeg_decompress_struct *cinfo,
uint8_t require_image)
{
if (SETJMP(sp->exit_jmpbuf))
return 0;
else
{
jpeg_read_header(cinfo, require_image);
return 1;
}
}
#endif
#ifndef LIBJPEG_ENCAP_EXTERNAL
static int jpeg_start_decompress_encap(OJPEGState *sp,
jpeg_decompress_struct *cinfo)
{
if (SETJMP(sp->exit_jmpbuf))
return 0;
else
{
jpeg_start_decompress(cinfo);
return 1;
}
}
#endif
#ifndef LIBJPEG_ENCAP_EXTERNAL
static int jpeg_read_scanlines_encap(OJPEGState *sp,
jpeg_decompress_struct *cinfo,
void *scanlines, uint32_t max_lines)
{
if (SETJMP(sp->exit_jmpbuf))
return 0;
else
{
jpeg_read_scanlines(cinfo, scanlines, max_lines);
return 1;
}
}
#endif
#ifndef LIBJPEG_ENCAP_EXTERNAL
static int jpeg_read_raw_data_encap(OJPEGState *sp,
jpeg_decompress_struct *cinfo, void *data,
uint32_t max_lines)
{
if (SETJMP(sp->exit_jmpbuf))
return 0;
else
{
jpeg_read_raw_data(cinfo, data, max_lines);
return 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);
TIFFWarningExtR(((TIFF *)(cinfo->client_data)), "LibJpeg", "%s", buffer);
}
static void OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct *cinfo)
{
char buffer[JMSG_LENGTH_MAX];
(*cinfo->err->format_message)(cinfo, buffer);
TIFFErrorExtR(((TIFF *)(cinfo->client_data)), "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_t len = 0U;
if (OJPEGWriteStream(tif, &mem, &len) == 0)
{
TIFFErrorExtR(tif, "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 = mem;
return (1);
}
static void
OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct *cinfo,
long num_bytes)
{
TIFF *tif = (TIFF *)cinfo->client_data;
(void)num_bytes;
TIFFErrorExtR(tif, "LibJpeg", "Unexpected error");
jpeg_encap_unwind(tif);
}
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4702)
#endif
static boolean
OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct *cinfo,
int desired)
{
TIFF *tif = (TIFF *)cinfo->client_data;
(void)desired;
TIFFErrorExtR(tif, "LibJpeg", "Unexpected error");
jpeg_encap_unwind(tif);
return (0);
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
static void OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct *cinfo)
{
(void)cinfo;
}
#endif