/* * jdmarker.c * * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1998, Thomas G. Lane. * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: * Copyright (C) 2012, 2015, 2022, 2024, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * * This file contains routines to decode JPEG datastream markers. * Most of the complexity arises from our desire to support input * suspension: if not all of the data for a marker is available, * we must exit back to the application. On resumption, we reprocess * the marker. */ #define JPEG_INTERNALS #include "jinclude.h" #include "jpeglib.h" JPEG_MARKER; /* Private state */ my_marker_reader; my_marker_ptr; /* * Macros for fetching data from the data source module. * * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect * the current restart point; we update them only when we have reached a * suitable place to restart if a suspension occurs. */ /* Declare and initialize local copies of input pointer/count */ #define INPUT_VARS(cinfo) … /* Unload the local copies --- do this only at a restart boundary */ #define INPUT_SYNC(cinfo) … /* Reload the local copies --- used only in MAKE_BYTE_AVAIL */ #define INPUT_RELOAD(cinfo) … /* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, * but we must reload the local copies after a successful fill. */ #define MAKE_BYTE_AVAIL(cinfo, action) … /* Read a byte into variable V. * If must suspend, take the specified action (typically "return FALSE"). */ #define INPUT_BYTE(cinfo, V, action) … /* As above, but read two bytes interpreted as an unsigned 16-bit integer. * V should be declared unsigned int or perhaps JLONG. */ #define INPUT_2BYTES(cinfo, V, action) … /* * Routines to process JPEG markers. * * Entry condition: JPEG marker itself has been read and its code saved * in cinfo->unread_marker; input restart point is just after the marker. * * Exit: if return TRUE, have read and processed any parameters, and have * updated the restart point to point after the parameters. * If return FALSE, was forced to suspend before reaching end of * marker parameters; restart point has not been moved. Same routine * will be called again after application supplies more input data. * * This approach to suspension assumes that all of a marker's parameters * can fit into a single input bufferload. This should hold for "normal" * markers. Some COM/APPn markers might have large parameter segments * that might not fit. If we are simply dropping such a marker, we use * skip_input_data to get past it, and thereby put the problem on the * source manager's shoulders. If we are saving the marker's contents * into memory, we use a slightly different convention: when forced to * suspend, the marker processor updates the restart point to the end of * what it's consumed (ie, the end of the buffer) before returning FALSE. * On resumption, cinfo->unread_marker still contains the marker code, * but the data source will point to the next chunk of marker data. * The marker processor must retain internal state to deal with this. * * Note that we don't bother to avoid duplicate trace messages if a * suspension occurs within marker parameters. Other side effects * require more care. */ LOCAL(boolean) get_soi(j_decompress_ptr cinfo) /* Process an SOI marker */ { … } LOCAL(boolean) get_sof(j_decompress_ptr cinfo, boolean is_prog, boolean is_arith) /* Process a SOFn marker */ { … } LOCAL(boolean) get_sos(j_decompress_ptr cinfo) /* Process a SOS marker */ { … } #ifdef D_ARITH_CODING_SUPPORTED LOCAL(boolean) get_dac(j_decompress_ptr cinfo) /* Process a DAC marker */ { JLONG length; int index, val; INPUT_VARS(cinfo); INPUT_2BYTES(cinfo, length, return FALSE); length -= 2; while (length > 0) { INPUT_BYTE(cinfo, index, return FALSE); INPUT_BYTE(cinfo, val, return FALSE); length -= 2; TRACEMS2(cinfo, 1, JTRC_DAC, index, val); if (index < 0 || index >= (2 * NUM_ARITH_TBLS)) ERREXIT1(cinfo, JERR_DAC_INDEX, index); if (index >= NUM_ARITH_TBLS) { /* define AC table */ cinfo->arith_ac_K[index - NUM_ARITH_TBLS] = (UINT8)val; } else { /* define DC table */ cinfo->arith_dc_L[index] = (UINT8)(val & 0x0F); cinfo->arith_dc_U[index] = (UINT8)(val >> 4); if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) ERREXIT1(cinfo, JERR_DAC_VALUE, val); } } if (length != 0) ERREXIT(cinfo, JERR_BAD_LENGTH); INPUT_SYNC(cinfo); return TRUE; } #else /* !D_ARITH_CODING_SUPPORTED */ #define get_dac(cinfo) … #endif /* D_ARITH_CODING_SUPPORTED */ LOCAL(boolean) get_dht(j_decompress_ptr cinfo) /* Process a DHT marker */ { … } LOCAL(boolean) get_dqt(j_decompress_ptr cinfo) /* Process a DQT marker */ { … } LOCAL(boolean) get_dri(j_decompress_ptr cinfo) /* Process a DRI marker */ { … } /* * Routines for processing APPn and COM markers. * These are either saved in memory or discarded, per application request. * APP0 and APP14 are specially checked to see if they are * JFIF and Adobe markers, respectively. */ #define APP0_DATA_LEN … #define APP14_DATA_LEN … #define APPN_DATA_LEN … LOCAL(void) examine_app0(j_decompress_ptr cinfo, JOCTET *data, unsigned int datalen, JLONG remaining) /* Examine first few bytes from an APP0. * Take appropriate action if it is a JFIF marker. * datalen is # of bytes at data[], remaining is length of rest of marker data. */ { … } LOCAL(void) examine_app14(j_decompress_ptr cinfo, JOCTET *data, unsigned int datalen, JLONG remaining) /* Examine first few bytes from an APP14. * Take appropriate action if it is an Adobe marker. * datalen is # of bytes at data[], remaining is length of rest of marker data. */ { … } METHODDEF(boolean) get_interesting_appn(j_decompress_ptr cinfo) /* Process an APP0 or APP14 marker without saving it */ { … } #ifdef SAVE_MARKERS_SUPPORTED METHODDEF(boolean) save_marker(j_decompress_ptr cinfo) /* Save an APPn or COM marker into the marker list */ { … } #endif /* SAVE_MARKERS_SUPPORTED */ METHODDEF(boolean) skip_variable(j_decompress_ptr cinfo) /* Skip over an unknown or uninteresting variable-length marker */ { … } /* * Find the next JPEG marker, save it in cinfo->unread_marker. * Returns FALSE if had to suspend before reaching a marker; * in that case cinfo->unread_marker is unchanged. * * Note that the result might not be a valid marker code, * but it will never be 0 or FF. */ LOCAL(boolean) next_marker(j_decompress_ptr 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, * we might well scan an entire input file before realizing it ain't JPEG. * If an application wants to process non-JFIF files, it must seek to the * SOI before calling the JPEG library. */ { … } /* * Read markers until SOS or EOI. * * Returns same codes as are defined for jpeg_consume_input: * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. */ METHODDEF(int) read_markers(j_decompress_ptr cinfo) { … } /* * Read a restart marker, which is expected to appear next in the datastream; * if the marker is not there, take appropriate recovery action. * Returns FALSE if suspension is required. * * This is called by the entropy decoder after it has read an appropriate * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder * has already read a marker from the data source. Under normal conditions * cinfo->unread_marker will be reset to 0 before returning; if not reset, * it holds a marker which the decoder will be unable to read past. */ METHODDEF(boolean) read_restart_marker(j_decompress_ptr cinfo) { … } /* * This is the default resync_to_restart method for data source managers * to use if they don't have any better approach. Some data source managers * may be able to back up, or may have additional knowledge about the data * which permits a more intelligent recovery strategy; such managers would * presumably supply their own resync method. * * read_restart_marker calls resync_to_restart if it finds a marker other than * the restart marker it was expecting. (This code is *not* used unless * a nonzero restart interval has been declared.) cinfo->unread_marker is * the marker code actually found (might be anything, except 0 or FF). * The desired restart marker number (0..7) is passed as a parameter. * This routine is supposed to apply whatever error recovery strategy seems * appropriate in order to position the input stream to the next data segment. * Note that cinfo->unread_marker is treated as a marker appearing before * the current data-source input point; usually it should be reset to zero * before returning. * Returns FALSE if suspension is required. * * This implementation is substantially constrained by wanting to treat the * input as a data stream; this means we can't back up. Therefore, we have * only the following actions to work with: * 1. Simply discard the marker and let the entropy decoder resume at next * byte of file. * 2. Read forward until we find another marker, discarding intervening * data. (In theory we could look ahead within the current bufferload, * without having to discard data if we don't find the desired marker. * This idea is not implemented here, in part because it makes behavior * dependent on buffer size and chance buffer-boundary positions.) * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). * This will cause the entropy decoder to process an empty data segment, * inserting dummy zeroes, and then we will reprocess the marker. * * #2 is appropriate if we think the desired marker lies ahead, while #3 is * appropriate if the found marker is a future restart marker (indicating * that we have missed the desired restart marker, probably because it got * corrupted). * We apply #2 or #3 if the found marker is a restart marker no more than * two counts behind or ahead of the expected one. We also apply #2 if the * found marker is not a legal JPEG marker code (it's certainly bogus data). * If the found marker is a restart marker more than 2 counts away, we do #1 * (too much risk that the marker is erroneous; with luck we will be able to * resync at some future point). * For any valid non-restart JPEG marker, we apply #3. This keeps us from * overrunning the end of a scan. An implementation limited to single-scan * files might find it better to apply #2 for markers other than EOI, since * any other marker would have to be bogus data in that case. */ GLOBAL(boolean) jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) { … } /* * Reset marker processing state to begin a fresh datastream. */ METHODDEF(void) reset_marker_reader(j_decompress_ptr cinfo) { … } /* * Initialize the marker reader module. * This is called only once, when the decompression object is created. */ GLOBAL(void) jinit_marker_reader(j_decompress_ptr cinfo) { … } /* * Control saving of COM and APPn markers into marker_list. */ #ifdef SAVE_MARKERS_SUPPORTED GLOBAL(void) jpeg_save_markers(j_decompress_ptr cinfo, int marker_code, unsigned int length_limit) { … } #endif /* SAVE_MARKERS_SUPPORTED */ /* * Install a special processing method for COM or APPn markers. */ GLOBAL(void) jpeg_set_marker_processor(j_decompress_ptr cinfo, int marker_code, jpeg_marker_parser_method routine) { … }