/* * jchuff.h * * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * libjpeg-turbo Modifications: * Copyright (C) 2009, 2018, 2021, D. R. Commander. * Copyright (C) 2018, Matthias Räncker. * Copyright (C) 2020-2021, Arm Limited. * For conditions of distribution and use, see the accompanying README.ijg * file. */ /* Expanded entropy encoder object for Huffman encoding. * * The savable_state subrecord contains fields that change within an MCU, * but must not be updated permanently until we complete the MCU. */ #if defined(__aarch64__) || defined(_M_ARM64) #define BIT_BUF_SIZE 64 #else #define BIT_BUF_SIZE 32 #endif typedef struct { size_t put_buffer; /* current bit accumulation buffer */ int free_bits; /* # of bits available in it */ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ } savable_state; typedef struct { JOCTET *next_output_byte; /* => next byte to write in buffer */ size_t free_in_buffer; /* # of byte spaces remaining in buffer */ savable_state cur; /* Current bit buffer & DC state */ j_compress_ptr cinfo; /* dump_buffer needs access to this */ int simd; } working_state; /* Outputting bits to the file */ /* Output byte b and, speculatively, an additional 0 byte. 0xFF must be encoded * as 0xFF 0x00, so the output buffer pointer is advanced by 2 if the byte is * 0xFF. Otherwise, the output buffer pointer is advanced by 1, and the * speculative 0 byte will be overwritten by the next byte. */ #define EMIT_BYTE(b) { \ buffer[0] = (JOCTET)(b); \ buffer[1] = 0; \ buffer -= -2 + ((JOCTET)(b) < 0xFF); \ } /* Output the entire bit buffer. If there are no 0xFF bytes in it, then write * directly to the output buffer. Otherwise, use the EMIT_BYTE() macro to * encode 0xFF as 0xFF 0x00. */ #if defined(__aarch64__) || defined(_M_ARM64) #define FLUSH() { \ if (put_buffer & 0x8080808080808080 & ~(put_buffer + 0x0101010101010101)) { \ EMIT_BYTE(put_buffer >> 56) \ EMIT_BYTE(put_buffer >> 48) \ EMIT_BYTE(put_buffer >> 40) \ EMIT_BYTE(put_buffer >> 32) \ EMIT_BYTE(put_buffer >> 24) \ EMIT_BYTE(put_buffer >> 16) \ EMIT_BYTE(put_buffer >> 8) \ EMIT_BYTE(put_buffer ) \ } else { \ *((uint64_t *)buffer) = BUILTIN_BSWAP64(put_buffer); \ buffer += 8; \ } \ } #else #if defined(_MSC_VER) && !defined(__clang__) #define SPLAT() { \ buffer[0] = (JOCTET)(put_buffer >> 24); \ buffer[1] = (JOCTET)(put_buffer >> 16); \ buffer[2] = (JOCTET)(put_buffer >> 8); \ buffer[3] = (JOCTET)(put_buffer ); \ buffer += 4; \ } #else #define SPLAT() { \ put_buffer = __builtin_bswap32(put_buffer); \ __asm__("str %1, [%0], #4" : "+r" (buffer) : "r" (put_buffer)); \ } #endif #define FLUSH() { \ if (put_buffer & 0x80808080 & ~(put_buffer + 0x01010101)) { \ EMIT_BYTE(put_buffer >> 24) \ EMIT_BYTE(put_buffer >> 16) \ EMIT_BYTE(put_buffer >> 8) \ EMIT_BYTE(put_buffer ) \ } else { \ SPLAT(); \ } \ } #endif /* Fill the bit buffer to capacity with the leading bits from code, then output * the bit buffer and put the remaining bits from code into the bit buffer. */ #define PUT_AND_FLUSH(code, size) { \ put_buffer = (put_buffer << (size + free_bits)) | (code >> -free_bits); \ FLUSH() \ free_bits += BIT_BUF_SIZE; \ put_buffer = code; \ } /* Insert code into the bit buffer and output the bit buffer if needed. * NOTE: We can't flush with free_bits == 0, since the left shift in * PUT_AND_FLUSH() would have undefined behavior. */ #define PUT_BITS(code, size) { \ free_bits -= size; \ if (free_bits < 0) \ PUT_AND_FLUSH(code, size) \ else \ put_buffer = (put_buffer << size) | code; \ } #define PUT_CODE(code, size, diff) { \ diff |= code << nbits; \ nbits += size; \ PUT_BITS(diff, nbits) \ }