+/* Error codes for cell decoding. */
+enum {
+ IV3_NOERR = 0,
+ IV3_BAD_RLE = 1,
+ IV3_BAD_DATA = 2,
+ IV3_BAD_COUNTER = 3,
+ IV3_UNSUPPORTED = 4,
+ IV3_OUT_OF_DATA = 5
+};
+
+
+#define BUFFER_PRECHECK \
+if (*data_ptr >= last_ptr) \
+ return IV3_OUT_OF_DATA; \
+
+#define RLE_BLOCK_COPY \
+ if (cell->mv_ptr || !skip_flag) \
+ copy_block4(dst, ref, row_offset, row_offset, 4 << v_zoom)
+
+#define RLE_BLOCK_COPY_8 \
+ pix64 = AV_RN64A(ref);\
+ if (is_first_row) {/* special prediction case: top line of a cell */\
+ pix64 = replicate64(pix64);\
+ fill_64(dst + row_offset, pix64, 7, row_offset);\
+ AVG_64(dst, ref, dst + row_offset);\
+ } else \
+ fill_64(dst, pix64, 8, row_offset)
+
+#define RLE_LINES_COPY \
+ copy_block4(dst, ref, row_offset, row_offset, num_lines << v_zoom)
+
+#define RLE_LINES_COPY_M10 \
+ pix64 = AV_RN64A(ref);\
+ if (is_top_of_cell) {\
+ pix64 = replicate64(pix64);\
+ fill_64(dst + row_offset, pix64, (num_lines << 1) - 1, row_offset);\
+ AVG_64(dst, ref, dst + row_offset);\
+ } else \
+ fill_64(dst, pix64, num_lines << 1, row_offset)
+
+#define APPLY_DELTA_4 \
+ AV_WN16A(dst + line_offset , AV_RN16A(ref ) + delta_tab->deltas[dyad1]);\
+ AV_WN16A(dst + line_offset + 2, AV_RN16A(ref + 2) + delta_tab->deltas[dyad2]);\
+ if (mode >= 3) {\
+ if (is_top_of_cell && !cell->ypos) {\
+ AV_COPY32(dst, dst + row_offset);\
+ } else {\
+ AVG_32(dst, ref, dst + row_offset);\
+ }\
+ }
+
+#define APPLY_DELTA_8 \
+ /* apply two 32-bit VQ deltas to next even line */\
+ if (is_top_of_cell) { \
+ AV_WN32A(dst + row_offset , \
+ replicate32(AV_RN32A(ref )) + delta_tab->deltas_m10[dyad1]);\
+ AV_WN32A(dst + row_offset + 4, \
+ replicate32(AV_RN32A(ref + 4)) + delta_tab->deltas_m10[dyad2]);\
+ } else { \
+ AV_WN32A(dst + row_offset , \
+ AV_RN32A(ref ) + delta_tab->deltas_m10[dyad1]);\
+ AV_WN32A(dst + row_offset + 4, \
+ AV_RN32A(ref + 4) + delta_tab->deltas_m10[dyad2]);\
+ } \
+ /* odd lines are not coded but rather interpolated/replicated */\
+ /* first line of the cell on the top of image? - replicate */\
+ /* otherwise - interpolate */\
+ if (is_top_of_cell && !cell->ypos) {\
+ AV_COPY64(dst, dst + row_offset);\
+ } else \
+ AVG_64(dst, ref, dst + row_offset);
+
+
+#define APPLY_DELTA_1011_INTER \
+ if (mode == 10) { \
+ AV_WN32A(dst , \
+ AV_RN32A(dst ) + delta_tab->deltas_m10[dyad1]);\
+ AV_WN32A(dst + 4 , \
+ AV_RN32A(dst + 4 ) + delta_tab->deltas_m10[dyad2]);\
+ AV_WN32A(dst + row_offset , \
+ AV_RN32A(dst + row_offset ) + delta_tab->deltas_m10[dyad1]);\
+ AV_WN32A(dst + row_offset + 4, \
+ AV_RN32A(dst + row_offset + 4) + delta_tab->deltas_m10[dyad2]);\
+ } else { \
+ AV_WN16A(dst , \
+ AV_RN16A(dst ) + delta_tab->deltas[dyad1]);\
+ AV_WN16A(dst + 2 , \
+ AV_RN16A(dst + 2 ) + delta_tab->deltas[dyad2]);\
+ AV_WN16A(dst + row_offset , \
+ AV_RN16A(dst + row_offset ) + delta_tab->deltas[dyad1]);\
+ AV_WN16A(dst + row_offset + 2, \
+ AV_RN16A(dst + row_offset + 2) + delta_tab->deltas[dyad2]);\
+ }
+
+
+static int decode_cell_data(Cell *cell, uint8_t *block, uint8_t *ref_block,
+ int pitch, int h_zoom, int v_zoom, int mode,
+ const vqEntry *delta[2], int swap_quads[2],
+ const uint8_t **data_ptr, const uint8_t *last_ptr)
+{
+ int x, y, line, num_lines;
+ int rle_blocks = 0;
+ uint8_t code, *dst, *ref;
+ const vqEntry *delta_tab;
+ unsigned int dyad1, dyad2;
+ uint64_t pix64;
+ int skip_flag = 0, is_top_of_cell, is_first_row = 1;
+ int row_offset, blk_row_offset, line_offset;
+
+ row_offset = pitch;
+ blk_row_offset = (row_offset << (2 + v_zoom)) - (cell->width << 2);
+ line_offset = v_zoom ? row_offset : 0;
+
+ for (y = 0; y < cell->height; is_first_row = 0, y += 1 + v_zoom) {
+ for (x = 0; x < cell->width; x += 1 + h_zoom) {
+ ref = ref_block;
+ dst = block;
+
+ if (rle_blocks > 0) {
+ if (mode <= 4) {
+ RLE_BLOCK_COPY;
+ } else if (mode == 10 && !cell->mv_ptr) {
+ RLE_BLOCK_COPY_8;
+ }
+ rle_blocks--;
+ } else {
+ for (line = 0; line < 4;) {
+ num_lines = 1;
+ is_top_of_cell = is_first_row && !line;
+
+ /* select primary VQ table for odd, secondary for even lines */
+ if (mode <= 4)
+ delta_tab = delta[line & 1];
+ else
+ delta_tab = delta[1];
+ BUFFER_PRECHECK;
+ code = bytestream_get_byte(data_ptr);
+ if (code < 248) {
+ if (code < delta_tab->num_dyads) {
+ BUFFER_PRECHECK;
+ dyad1 = bytestream_get_byte(data_ptr);
+ dyad2 = code;
+ if (dyad1 >= delta_tab->num_dyads || dyad1 >= 248)
+ return IV3_BAD_DATA;
+ } else {
+ /* process QUADS */
+ code -= delta_tab->num_dyads;
+ dyad1 = code / delta_tab->quad_exp;
+ dyad2 = code % delta_tab->quad_exp;
+ if (swap_quads[line & 1])
+ FFSWAP(unsigned int, dyad1, dyad2);
+ }
+ if (mode <= 4) {
+ APPLY_DELTA_4;
+ } else if (mode == 10 && !cell->mv_ptr) {
+ APPLY_DELTA_8;
+ } else {
+ APPLY_DELTA_1011_INTER;
+ }
+ } else {
+ /* process RLE codes */
+ switch (code) {
+ case RLE_ESC_FC:
+ skip_flag = 0;
+ rle_blocks = 1;
+ code = 253;
+ /* FALLTHROUGH */
+ case RLE_ESC_FF:
+ case RLE_ESC_FE:
+ case RLE_ESC_FD:
+ num_lines = 257 - code - line;
+ if (num_lines <= 0)
+ return IV3_BAD_RLE;
+ if (mode <= 4) {
+ RLE_LINES_COPY;
+ } else if (mode == 10 && !cell->mv_ptr) {
+ RLE_LINES_COPY_M10;
+ }
+ break;
+ case RLE_ESC_FB:
+ BUFFER_PRECHECK;
+ code = bytestream_get_byte(data_ptr);
+ rle_blocks = (code & 0x1F) - 1; /* set block counter */
+ if (code >= 64 || rle_blocks < 0)
+ return IV3_BAD_COUNTER;
+ skip_flag = code & 0x20;
+ num_lines = 4 - line; /* enforce next block processing */
+ if (mode >= 10 || (cell->mv_ptr || !skip_flag)) {
+ if (mode <= 4) {
+ RLE_LINES_COPY;
+ } else if (mode == 10 && !cell->mv_ptr) {
+ RLE_LINES_COPY_M10;