/* Limit on marker data length to save for each marker type */ unsignedint length_limit_COM; unsignedint length_limit_APPn[16];
/* Status of COM/APPn marker saving */
jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */ unsignedint bytes_read; /* data bytes read so far in marker */ /* Note: cur_marker is not linked into marker_list until it's all read. */
} my_marker_reader;
/* Declare and initialize local copies of input pointer/count */ #define INPUT_VARS(cinfo) \ struct jpeg_source_mgr *datasrc = (cinfo)->src; \ const JOCTET *next_input_byte = datasrc->next_input_byte; \
size_t bytes_in_buffer = datasrc->bytes_in_buffer
/* Unload the local copies --- do this only at a restart boundary */ #define INPUT_SYNC(cinfo) \
( datasrc->next_input_byte = next_input_byte, \
datasrc->bytes_in_buffer = bytes_in_buffer )
/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */ #define INPUT_RELOAD(cinfo) \
( next_input_byte = datasrc->next_input_byte, \
bytes_in_buffer = datasrc->bytes_in_buffer )
/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. *Notewedo*not*doINPUT_SYNCbeforecallingfill_input_buffer, *butwemustreloadthelocalcopiesafterasuccessfulfill.
*/ #define MAKE_BYTE_AVAIL(cinfo, action) \ if (bytes_in_buffer == 0) { \ if (!(*datasrc->fill_input_buffer) (cinfo)) \
{ action; } \
INPUT_RELOAD(cinfo); \
}
/* Read a byte into variable V. *Ifmustsuspend,takethespecifiedaction(typically"returnFALSE").
*/ #define INPUT_BYTE(cinfo, V, action) \
MAKESTMT( MAKE_BYTE_AVAIL(cinfo, action); \
bytes_in_buffer--; \
V = *next_input_byte++; )
/* As above, but read two bytes interpreted as an unsigned 16-bit integer. *VshouldbedeclaredunsignedintorperhapsJLONG.
*/ #define INPUT_2BYTES(cinfo, V, action) \
MAKESTMT( MAKE_BYTE_AVAIL(cinfo, action); \
bytes_in_buffer--; \
V = ((unsignedint)(*next_input_byte++)) << 8; \
MAKE_BYTE_AVAIL(cinfo, action); \
bytes_in_buffer--; \
V += *next_input_byte++; )
/* We don't support files in which the image height is initially specified */ /* as 0 and is later redefined by DNL. As long as we have to check that, */ /* might as well have a general sanity check. */ if (cinfo->image_height <= 0 || cinfo->image_width <= 0 ||
cinfo->num_components <= 0)
ERREXIT(cinfo, JERR_EMPTY_IMAGE);
if (length != (cinfo->num_components * 3))
ERREXIT(cinfo, JERR_BAD_LENGTH);
if (cinfo->comp_info == NULL) /* do only once, even if suspend */
cinfo->comp_info = (jpeg_component_info *)(*cinfo->mem->alloc_small)
((j_common_ptr)cinfo, JPOOL_IMAGE,
cinfo->num_components * sizeof(jpeg_component_info));
LOCAL(boolean)
get_sos(j_decompress_ptr cinfo) /* Process a SOS marker */
{
JLONG length; int i, ci, n, c, cc, pi;
jpeg_component_info *compptr;
INPUT_VARS(cinfo);
if (!cinfo->marker->saw_SOF)
ERREXIT(cinfo, JERR_SOS_NO_SOF);
INPUT_2BYTES(cinfo, length, returnFALSE);
INPUT_BYTE(cinfo, n, returnFALSE); /* Number of components */
TRACEMS1(cinfo, 1, JTRC_SOS, n);
if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN)
ERREXIT(cinfo, JERR_BAD_LENGTH);
cinfo->comps_in_scan = n;
/* Collect the component-spec parameters */
for (i = 0; i < MAX_COMPS_IN_SCAN; i++)
cinfo->cur_comp_info[i] = NULL;
for (i = 0; i < n; i++) {
INPUT_BYTE(cinfo, cc, returnFALSE);
INPUT_BYTE(cinfo, c, returnFALSE);
for (ci = 0, compptr = cinfo->comp_info;
ci < cinfo->num_components && ci < MAX_COMPS_IN_SCAN;
ci++, compptr++) { if (cc == compptr->component_id && !cinfo->cur_comp_info[ci]) goto id_found;
}
/* This CSi (cc) should differ from the previous CSi */ for (pi = 0; pi < i; pi++) { if (cinfo->cur_comp_info[pi] == compptr) {
ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc);
}
}
}
/* Here we just do minimal validation of the counts to avoid walking *offtheendofourtablespace.jdhuff.cwillcheckmorecarefully.
*/ if (count > 256 || ((JLONG)count) > length)
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
for (i = 0; i < count; i++)
INPUT_BYTE(cinfo, huffval[i], returnFALSE);
LOCAL(boolean)
get_dqt(j_decompress_ptr cinfo) /* Process a DQT marker */
{
JLONG length; int n, i, prec; unsignedint tmp;
JQUANT_TBL *quant_ptr;
INPUT_VARS(cinfo);
while (length > 0) {
INPUT_BYTE(cinfo, n, returnFALSE);
prec = n >> 4;
n &= 0x0F;
TRACEMS2(cinfo, 1, JTRC_DQT, n, prec);
if (n >= NUM_QUANT_TBLS)
ERREXIT1(cinfo, JERR_DQT_INDEX, n);
if (cinfo->quant_tbl_ptrs[n] == NULL)
cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr)cinfo);
quant_ptr = cinfo->quant_tbl_ptrs[n];
for (i = 0; i < DCTSIZE2; i++) { if (prec)
INPUT_2BYTES(cinfo, tmp, returnFALSE); else
INPUT_BYTE(cinfo, tmp, returnFALSE); /* We convert the zigzag-order table to natural array order. */
quant_ptr->quantval[jpeg_natural_order[i]] = (UINT16)tmp;
}
if (cinfo->err->trace_level >= 2) { for (i = 0; i < DCTSIZE2; i += 8) {
TRACEMS8(cinfo, 2, JTRC_QUANTVALS,
quant_ptr->quantval[i], quant_ptr->quantval[i + 1],
quant_ptr->quantval[i + 2], quant_ptr->quantval[i + 3],
quant_ptr->quantval[i + 4], quant_ptr->quantval[i + 5],
quant_ptr->quantval[i + 6], quant_ptr->quantval[i + 7]);
}
}
#define APP0_DATA_LEN 14/* Length of interesting data in APP0 */ #define APP14_DATA_LEN 12/* Length of interesting data in APP14 */ #define APPN_DATA_LEN 14/* Must be the largest of the above!! */
LOCAL(void)
examine_app0(j_decompress_ptr cinfo, JOCTET *data, unsignedint datalen,
JLONG remaining) /* Examine first few bytes from an APP0. *TakeappropriateactionifitisaJFIFmarker. *datalenis#ofbytesatdata[],remainingislengthofrestofmarkerdata.
*/
{
JLONG totallen = (JLONG)datalen + remaining;
LOCAL(void)
examine_app14(j_decompress_ptr cinfo, JOCTET *data, unsignedint datalen,
JLONG remaining) /* Examine first few bytes from an APP14. *TakeappropriateactionifitisanAdobemarker. *datalenis#ofbytesatdata[],remainingislengthofrestofmarkerdata.
*/
{ unsignedint version, flags0, flags1, transform;
if (datalen >= APP14_DATA_LEN &&
data[0] == 0x41 &&
data[1] == 0x64 &&
data[2] == 0x6F &&
data[3] == 0x62 &&
data[4] == 0x65) { /* Found Adobe APP14 marker */
version = (data[5] << 8) + data[6];
flags0 = (data[7] << 8) + data[8];
flags1 = (data[9] << 8) + data[10];
transform = data[11];
TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform);
cinfo->saw_Adobe_marker = TRUE;
cinfo->Adobe_transform = (UINT8)transform;
} else { /* Start of APP14 does not match "Adobe", or too short */
TRACEMS1(cinfo, 1, JTRC_APP14, (int)(datalen + remaining));
}
}
METHODDEF(boolean)
get_interesting_appn(j_decompress_ptr cinfo) /* Process an APP0 or APP14 marker without saving it */
{
JLONG length;
JOCTET b[APPN_DATA_LEN]; unsignedint i, numtoread;
INPUT_VARS(cinfo);
/* get the interesting part of the marker data */ if (length >= APPN_DATA_LEN)
numtoread = APPN_DATA_LEN; elseif (length > 0)
numtoread = (unsignedint)length; else
numtoread = 0; for (i = 0; i < numtoread; i++)
INPUT_BYTE(cinfo, b[i], returnFALSE);
length -= numtoread;
/* process it */ switch (cinfo->unread_marker) { case M_APP0:
examine_app0(cinfo, (JOCTET *)b, numtoread, length); break; case M_APP14:
examine_app14(cinfo, (JOCTET *)b, numtoread, length); break; default: /* can't get here unless jpeg_save_markers chooses wrong processor */
ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); break;
}
/* skip any remaining data -- could be lots */
INPUT_SYNC(cinfo); if (length > 0)
(*cinfo->src->skip_input_data) (cinfo, (long)length);
return TRUE;
}
#ifdef SAVE_MARKERS_SUPPORTED
METHODDEF(boolean)
save_marker(j_decompress_ptr cinfo) /* Save an APPn or COM marker into the marker list */
{
my_marker_ptr marker = (my_marker_ptr)cinfo->marker;
jpeg_saved_marker_ptr cur_marker = marker->cur_marker; unsignedint bytes_read, data_length;
JOCTET *data;
JLONG length = 0;
INPUT_VARS(cinfo);
if (cur_marker == NULL) { /* begin reading a marker */
INPUT_2BYTES(cinfo, length, returnFALSE);
length -= 2; if (length >= 0) { /* watch out for bogus length word */ /* figure out how much we want to save */ unsignedint limit; if (cinfo->unread_marker == (int)M_COM)
limit = marker->length_limit_COM; else
limit = marker->length_limit_APPn[cinfo->unread_marker - (int)M_APP0]; if ((unsignedint)length < limit)
limit = (unsignedint)length; /* allocate and initialize the marker item */
cur_marker = (jpeg_saved_marker_ptr)
(*cinfo->mem->alloc_large) ((j_common_ptr)cinfo, JPOOL_IMAGE, sizeof(struct jpeg_marker_struct) + limit);
cur_marker->next = NULL;
cur_marker->marker = (UINT8)cinfo->unread_marker;
cur_marker->original_length = (unsignedint)length;
cur_marker->data_length = limit; /* data area is just beyond the jpeg_marker_struct */
data = cur_marker->data = (JOCTET *)(cur_marker + 1);
marker->cur_marker = cur_marker;
marker->bytes_read = 0;
bytes_read = 0;
data_length = limit;
} else { /* deal with bogus length word */
bytes_read = data_length = 0;
data = NULL;
}
} else { /* resume reading a marker */
bytes_read = marker->bytes_read;
data_length = cur_marker->data_length;
data = cur_marker->data + bytes_read;
}
while (bytes_read < data_length) {
INPUT_SYNC(cinfo); /* move the restart point to here */
marker->bytes_read = bytes_read; /* If there's not at least one byte in buffer, suspend */
MAKE_BYTE_AVAIL(cinfo, returnFALSE); /* Copy bytes with reasonable rapidity */ while (bytes_read < data_length && bytes_in_buffer > 0) {
*data++ = *next_input_byte++;
bytes_in_buffer--;
bytes_read++;
}
}
/* Done reading what we want to read */ if (cur_marker != NULL) { /* will be NULL if bogus length word */ /* Add new marker to end of list */ if (cinfo->marker_list == NULL || cinfo->master->marker_list_end == NULL) {
cinfo->marker_list = cinfo->master->marker_list_end = cur_marker;
} else {
cinfo->master->marker_list_end->next = cur_marker;
cinfo->master->marker_list_end = cur_marker;
} /* Reset pointer & calc remaining data length */
data = cur_marker->data;
length = cur_marker->original_length - data_length;
} /* Reset to initial state for next marker */
marker->cur_marker = NULL;
/* Process the marker if interesting; else just make a generic trace msg */ switch (cinfo->unread_marker) { case M_APP0:
examine_app0(cinfo, data, data_length, length); break; case M_APP14:
examine_app14(cinfo, data, data_length, length); break; default:
TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker,
(int)(data_length + length)); break;
}
/* skip any remaining data -- could be lots */
INPUT_SYNC(cinfo); /* do before skip_input_data */ if (length > 0)
(*cinfo->src->skip_input_data) (cinfo, (long)length);
return TRUE;
}
#endif/* SAVE_MARKERS_SUPPORTED */
METHODDEF(boolean)
skip_variable(j_decompress_ptr cinfo) /* Skip over an unknown or uninteresting variable-length marker */
{
JLONG length;
INPUT_VARS(cinfo);
LOCAL(boolean)
next_marker(j_decompress_ptr cinfo)
{ int c;
INPUT_VARS(cinfo);
for (;;) {
INPUT_BYTE(cinfo, c, returnFALSE); /* Skip any non-FF bytes. *Thismaylookabitinefficient,butitwillnotoccurinavalidfile. *Wesyncaftereachdiscardedbytesothatasuspendingdatasource *candiscardthebytefromitsbuffer.
*/ while (c != 0xFF) {
cinfo->marker->discarded_bytes++;
INPUT_SYNC(cinfo);
INPUT_BYTE(cinfo, c, returnFALSE);
} /* This loop swallows any duplicate FF bytes. Extra FFs are legal as *padbytes,sodon'tcountthemindiscarded_bytes.Weassumethere *willnotbesomanyconsecutiveFFbytesastooverflowasuspending *datasource'sinputbuffer.
*/ do {
INPUT_BYTE(cinfo, c, returnFALSE);
} while (c == 0xFF); if (c != 0) break; /* found a valid marker, exit loop */ /* Reach here if we found a stuffed-zero data sequence (FF/00). *Discarditandloopbacktotryagain.
*/
cinfo->marker->discarded_bytes += 2;
INPUT_SYNC(cinfo);
}
LOCAL(boolean)
first_marker(j_decompress_ptr cinfo) /* Like next_marker, but used to obtain the initial SOI marker. */ /* For this marker, we do not allow preceding garbage or fill; otherwise, *wemightwellscananentireinputfilebeforerealizingitain'tJPEG. *Ifanapplicationwantstoprocessnon-JFIFfiles,itmustseektothe *SOIbeforecallingtheJPEGlibrary.
*/
{ int c, c2;
INPUT_VARS(cinfo);
METHODDEF(int)
read_markers(j_decompress_ptr cinfo)
{ /* Outer loop repeats once for each marker. */ for (;;) { /* Collect the marker proper, unless we already did. */ /* NB: first_marker() enforces the requirement that SOI appear first. */ if (cinfo->unread_marker == 0) { if (!cinfo->marker->saw_SOI) { if (!first_marker(cinfo)) return JPEG_SUSPENDED;
} else { if (!next_marker(cinfo)) return JPEG_SUSPENDED;
}
} /* At this point cinfo->unread_marker contains the marker code and the *inputpointisjustpastthemarkerproper,butbeforeanyparameters. *Asuspensionwillcauseustoreturnwiththisstatestilltrue.
*/ switch (cinfo->unread_marker) { case M_SOI: if (!get_soi(cinfo)) return JPEG_SUSPENDED; break;
case M_SOF0: /* Baseline */ case M_SOF1: /* Extended sequential, Huffman */ if (!get_sof(cinfo, FALSE, FALSE, FALSE)) return JPEG_SUSPENDED; break;
case M_SOF2: /* Progressive, Huffman */ if (!get_sof(cinfo, TRUE, FALSE, FALSE)) return JPEG_SUSPENDED; break;
case M_SOF3: /* Lossless, Huffman */ if (!get_sof(cinfo, FALSE, TRUE, FALSE)) return JPEG_SUSPENDED; break;
case M_SOF9: /* Extended sequential, arithmetic */ if (!get_sof(cinfo, FALSE, FALSE, TRUE)) return JPEG_SUSPENDED; break;
case M_SOF10: /* Progressive, arithmetic */ if (!get_sof(cinfo, TRUE, FALSE, TRUE)) return JPEG_SUSPENDED; break;
case M_SOF11: /* Lossless, arithmetic */ if (!get_sof(cinfo, FALSE, TRUE, TRUE)) return JPEG_SUSPENDED; break;
/* Currently unsupported SOFn types */ case M_SOF5: /* Differential sequential, Huffman */ case M_SOF6: /* Differential progressive, Huffman */ case M_SOF7: /* Differential lossless, Huffman */ case M_JPG: /* Reserved for JPEG extensions */ case M_SOF13: /* Differential sequential, arithmetic */ case M_SOF14: /* Differential progressive, arithmetic */ case M_SOF15: /* Differential lossless, arithmetic */
ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); break;
case M_SOS: if (!get_sos(cinfo)) return JPEG_SUSPENDED;
cinfo->unread_marker = 0; /* processed the marker */ return JPEG_REACHED_SOS;
case M_EOI:
TRACEMS(cinfo, 1, JTRC_EOI);
cinfo->unread_marker = 0; /* processed the marker */ return JPEG_REACHED_EOI;
case M_DAC: if (!get_dac(cinfo)) return JPEG_SUSPENDED; break;
case M_DHT: if (!get_dht(cinfo)) return JPEG_SUSPENDED; break;
case M_DQT: if (!get_dqt(cinfo)) return JPEG_SUSPENDED; break;
case M_DRI: if (!get_dri(cinfo)) return JPEG_SUSPENDED; break;
case M_APP0: case M_APP1: case M_APP2: case M_APP3: case M_APP4: case M_APP5: case M_APP6: case M_APP7: case M_APP8: case M_APP9: case M_APP10: case M_APP11: case M_APP12: case M_APP13: case M_APP14: case M_APP15: if (!(*((my_marker_ptr)cinfo->marker)->process_APPn[
cinfo->unread_marker - (int)M_APP0]) (cinfo)) return JPEG_SUSPENDED; break;
case M_COM: if (!(*((my_marker_ptr)cinfo->marker)->process_COM) (cinfo)) return JPEG_SUSPENDED; break;
case M_RST0: /* these are all parameterless */ case M_RST1: case M_RST2: case M_RST3: case M_RST4: case M_RST5: case M_RST6: case M_RST7: case M_TEM:
TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); break;
case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ if (!skip_variable(cinfo)) return JPEG_SUSPENDED; break;
default: /* must be DHP, EXP, JPGn, or RESn */ /* For now, we treat the reserved markers as fatal errors since they are *likelytobeusedtosignalincompatibleJPEGPart3extensions. *OncetheJPEG3version-numbermarkeriswelldefined,thiscode *oughttochange!
*/
ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); break;
} /* Successfully processed marker, so reset state variable */
cinfo->unread_marker = 0;
} /* end loop */
}
METHODDEF(boolean)
read_restart_marker(j_decompress_ptr cinfo)
{ /* Obtain a marker unless we already did. */ /* Note that next_marker will complain if it skips any data. */ if (cinfo->unread_marker == 0) { if (!next_marker(cinfo)) returnFALSE;
}
if (cinfo->unread_marker ==
((int)M_RST0 + cinfo->marker->next_restart_num)) { /* Normal case --- swallow the marker and let entropy decoder continue */
TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num);
cinfo->unread_marker = 0;
} else { /* Uh-oh, the restart markers have been messed up. */ /* Let the data source manager determine how to resync. */ if (!(*cinfo->src->resync_to_restart) (cinfo,
cinfo->marker->next_restart_num)) returnFALSE;
}
cinfo->comp_info = NULL; /* until allocated by get_sof */
cinfo->input_scan_number = 0; /* no SOS seen yet */
cinfo->unread_marker = 0; /* no pending marker */
marker->pub.saw_SOI = FALSE; /* set internal state too */
marker->pub.saw_SOF = FALSE;
marker->pub.discarded_bytes = 0;
marker->cur_marker = NULL;
}
GLOBAL(void)
jpeg_save_markers(j_decompress_ptr cinfo, int marker_code, unsignedint length_limit)
{
my_marker_ptr marker = (my_marker_ptr)cinfo->marker; long maxlength;
jpeg_marker_parser_method processor;
/* Length limit mustn't be larger than what we can allocate *(shouldonlybeaconcernina16-bitenvironment).
*/
maxlength = cinfo->mem->max_alloc_chunk - sizeof(struct jpeg_marker_struct); if (((long)length_limit) > maxlength)
length_limit = (unsignedint)maxlength;
/* Choose processor routine to use. *APP0/APP14havespecialrequirements.
*/ if (length_limit) {
processor = save_marker; /* If saving APP0/APP14, save at least enough for our internal use. */ if (marker_code == (int)M_APP0 && length_limit < APP0_DATA_LEN)
length_limit = APP0_DATA_LEN; elseif (marker_code == (int)M_APP14 && length_limit < APP14_DATA_LEN)
length_limit = APP14_DATA_LEN;
} else {
processor = skip_variable; /* If discarding APP0/APP14, use our regular on-the-fly processor. */ if (marker_code == (int)M_APP0 || marker_code == (int)M_APP14)
processor = get_interesting_appn;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.