Compare commits

..

4 Commits

Author SHA1 Message Date
ca332209cb update ChangeLog
Bug: webp:620
Change-Id: I5703f222de7262736339dbfd6ba82f2039dfc850
2023-09-13 15:11:07 -07:00
1ace578c91 update NEWS
Bug: webp:620
Change-Id: I393c58cc23ccf98fa3c5d1568f0689a36e64575b
2023-09-13 13:33:58 -07:00
63234c4296 bump version to 1.3.2
libwebp{,decoder} - 1.3.2
libwebp libtool - 8.8.1
libwebpdecoder libtool - 4.8.1

mux - 1.3.2
libtool - 3.13.0

demux - 1.3.2
libtool - 2.14.0

sharpyuv - 0.2.1 (no change)
libtool - 0.1.0 (no change)

Bug: webp:620
Change-Id: I9a61d83ee92809de1c2501d1b4fb68aa38f98850
2023-09-13 13:24:49 -07:00
2af26267cd Fix OOB write in BuildHuffmanTable.
First, BuildHuffmanTable is called to check if the data is valid.
If it is and the table is not big enough, more memory is allocated.

This will make sure that valid (but unoptimized because of unbalanced
codes) streams are still decodable.

Bug: chromium:1479274
Change-Id: I31c36dbf3aa78d35ecf38706b50464fd3d375741
(cherry picked from commit 902bc91903)
2023-09-07 15:14:39 -07:00
20 changed files with 164 additions and 70 deletions

View File

@ -1,3 +1,7 @@
1ace578c update NEWS
63234c42 bump version to 1.3.2
2af26267 Fix OOB write in BuildHuffmanTable.
fd7bb21c update ChangeLog (tag: v1.3.1-rc2, tag: v1.3.1)
e1adea50 update NEWS e1adea50 update NEWS
43393320 enc/*: normalize WebPEncodingSetError() calls 43393320 enc/*: normalize WebPEncodingSetError() calls
287fdefe enc/*: add missing WebPEncodingSetError() calls 287fdefe enc/*: add missing WebPEncodingSetError() calls

4
NEWS
View File

@ -1,3 +1,7 @@
- 9/13/2023: version 1.3.2
This is a binary compatible release.
* security fix for lossless decoder (chromium: #1479274, CVE-2023-4863)
- 6/23/2023: version 1.3.1 - 6/23/2023: version 1.3.1
This is a binary compatible release. This is a binary compatible release.
* security fixes for lossless encoder (#603, chromium: #1420107, #1455619, * security fixes for lossless encoder (#603, chromium: #1420107, #1455619,

View File

@ -7,7 +7,7 @@
\__\__/\____/\_____/__/ ____ ___ \__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/ / _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__ / \_/ / / \ \ __/ \__
\____/____/\_____/_____/____/v1.3.1 \____/____/\_____/_____/____/v1.3.2
``` ```
WebP codec is a library to encode and decode images in WebP format. This package WebP codec is a library to encode and decode images in WebP format. This package

View File

@ -1,4 +1,4 @@
AC_INIT([libwebp], [1.3.1], AC_INIT([libwebp], [1.3.2],
[https://bugs.chromium.org/p/webp],, [https://bugs.chromium.org/p/webp],,
[https://developers.google.com/speed/webp]) [https://developers.google.com/speed/webp])
AC_CANONICAL_HOST AC_CANONICAL_HOST

View File

@ -19,7 +19,7 @@
#define XTRA_MAJ_VERSION 1 #define XTRA_MAJ_VERSION 1
#define XTRA_MIN_VERSION 3 #define XTRA_MIN_VERSION 3
#define XTRA_REV_VERSION 1 #define XTRA_REV_VERSION 2
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -36,7 +36,7 @@ libwebp_la_LIBADD += utils/libwebputils.la
# other than the ones listed on the command line, i.e., after linking, it will # other than the ones listed on the command line, i.e., after linking, it will
# not have unresolved symbols. Some platforms (Windows among them) require all # not have unresolved symbols. Some platforms (Windows among them) require all
# symbols in shared libraries to be resolved at library creation. # symbols in shared libraries to be resolved at library creation.
libwebp_la_LDFLAGS = -no-undefined -version-info 8:7:1 libwebp_la_LDFLAGS = -no-undefined -version-info 8:8:1
libwebpincludedir = $(includedir)/webp libwebpincludedir = $(includedir)/webp
pkgconfig_DATA = libwebp.pc pkgconfig_DATA = libwebp.pc
@ -48,7 +48,7 @@ if BUILD_LIBWEBPDECODER
libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:7:1 libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:8:1
pkgconfig_DATA += libwebpdecoder.pc pkgconfig_DATA += libwebpdecoder.pc
endif endif

View File

@ -32,7 +32,7 @@ extern "C" {
// version numbers // version numbers
#define DEC_MAJ_VERSION 1 #define DEC_MAJ_VERSION 1
#define DEC_MIN_VERSION 3 #define DEC_MIN_VERSION 3
#define DEC_REV_VERSION 1 #define DEC_REV_VERSION 2
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). // YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y), // Constraints are: We need to store one 16x16 block of luma samples (y),

View File

@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths(
int symbol; int symbol;
int max_symbol; int max_symbol;
int prev_code_len = DEFAULT_CODE_LENGTH; int prev_code_len = DEFAULT_CODE_LENGTH;
HuffmanCode table[1 << LENGTHS_TABLE_BITS]; HuffmanTables tables;
if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS, if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) ||
code_length_code_lengths, !VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS,
NUM_CODE_LENGTH_CODES)) { code_length_code_lengths, NUM_CODE_LENGTH_CODES)) {
goto End; goto End;
} }
@ -277,7 +277,7 @@ static int ReadHuffmanCodeLengths(
int code_len; int code_len;
if (max_symbol-- == 0) break; if (max_symbol-- == 0) break;
VP8LFillBitWindow(br); VP8LFillBitWindow(br);
p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK]; p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
VP8LSetBitPos(br, br->bit_pos_ + p->bits); VP8LSetBitPos(br, br->bit_pos_ + p->bits);
code_len = p->value; code_len = p->value;
if (code_len < kCodeLengthLiterals) { if (code_len < kCodeLengthLiterals) {
@ -300,6 +300,7 @@ static int ReadHuffmanCodeLengths(
ok = 1; ok = 1;
End: End:
VP8LHuffmanTablesDeallocate(&tables);
if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR; if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
return ok; return ok;
} }
@ -307,7 +308,8 @@ static int ReadHuffmanCodeLengths(
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman // 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
// tree. // tree.
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec, static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
int* const code_lengths, HuffmanCode* const table) { int* const code_lengths,
HuffmanTables* const table) {
int ok = 0; int ok = 0;
int size = 0; int size = 0;
VP8LBitReader* const br = &dec->br_; VP8LBitReader* const br = &dec->br_;
@ -362,8 +364,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
VP8LMetadata* const hdr = &dec->hdr_; VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL; uint32_t* huffman_image = NULL;
HTreeGroup* htree_groups = NULL; HTreeGroup* htree_groups = NULL;
HuffmanCode* huffman_tables = NULL; HuffmanTables* huffman_tables = &hdr->huffman_tables_;
HuffmanCode* huffman_table = NULL;
int num_htree_groups = 1; int num_htree_groups = 1;
int num_htree_groups_max = 1; int num_htree_groups_max = 1;
int max_alphabet_size = 0; int max_alphabet_size = 0;
@ -372,6 +373,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int* mapping = NULL; int* mapping = NULL;
int ok = 0; int ok = 0;
// Check the table has been 0 initialized (through InitMetadata).
assert(huffman_tables->root.start == NULL);
assert(huffman_tables->curr_segment == NULL);
if (allow_recursion && VP8LReadBits(br, 1)) { if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes. // use meta Huffman codes.
const int huffman_precision = VP8LReadBits(br, 3) + 2; const int huffman_precision = VP8LReadBits(br, 3) + 2;
@ -434,16 +439,15 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size, code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
sizeof(*code_lengths)); sizeof(*code_lengths));
huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
sizeof(*huffman_tables));
htree_groups = VP8LHtreeGroupsNew(num_htree_groups); htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) { if (htree_groups == NULL || code_lengths == NULL ||
!VP8LHuffmanTablesAllocate(num_htree_groups * table_size,
huffman_tables)) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY; dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error; goto Error;
} }
huffman_table = huffman_tables;
for (i = 0; i < num_htree_groups_max; ++i) { for (i = 0; i < num_htree_groups_max; ++i) {
// If the index "i" is unused in the Huffman image, just make sure the // If the index "i" is unused in the Huffman image, just make sure the
// coefficients are valid but do not store them. // coefficients are valid but do not store them.
@ -468,19 +472,20 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int max_bits = 0; int max_bits = 0;
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int alphabet_size = kAlphabetSize[j]; int alphabet_size = kAlphabetSize[j];
htrees[j] = huffman_table;
if (j == 0 && color_cache_bits > 0) { if (j == 0 && color_cache_bits > 0) {
alphabet_size += (1 << color_cache_bits); alphabet_size += (1 << color_cache_bits);
} }
size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table); size =
ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables);
htrees[j] = huffman_tables->curr_segment->curr_table;
if (size == 0) { if (size == 0) {
goto Error; goto Error;
} }
if (is_trivial_literal && kLiteralMap[j] == 1) { if (is_trivial_literal && kLiteralMap[j] == 1) {
is_trivial_literal = (huffman_table->bits == 0); is_trivial_literal = (htrees[j]->bits == 0);
} }
total_size += huffman_table->bits; total_size += htrees[j]->bits;
huffman_table += size; huffman_tables->curr_segment->curr_table += size;
if (j <= ALPHA) { if (j <= ALPHA) {
int local_max_bits = code_lengths[0]; int local_max_bits = code_lengths[0];
int k; int k;
@ -515,14 +520,13 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
hdr->huffman_image_ = huffman_image; hdr->huffman_image_ = huffman_image;
hdr->num_htree_groups_ = num_htree_groups; hdr->num_htree_groups_ = num_htree_groups;
hdr->htree_groups_ = htree_groups; hdr->htree_groups_ = htree_groups;
hdr->huffman_tables_ = huffman_tables;
Error: Error:
WebPSafeFree(code_lengths); WebPSafeFree(code_lengths);
WebPSafeFree(mapping); WebPSafeFree(mapping);
if (!ok) { if (!ok) {
WebPSafeFree(huffman_image); WebPSafeFree(huffman_image);
WebPSafeFree(huffman_tables); VP8LHuffmanTablesDeallocate(huffman_tables);
VP8LHtreeGroupsFree(htree_groups); VP8LHtreeGroupsFree(htree_groups);
} }
return ok; return ok;
@ -1358,7 +1362,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
assert(hdr != NULL); assert(hdr != NULL);
WebPSafeFree(hdr->huffman_image_); WebPSafeFree(hdr->huffman_image_);
WebPSafeFree(hdr->huffman_tables_); VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_);
VP8LHtreeGroupsFree(hdr->htree_groups_); VP8LHtreeGroupsFree(hdr->htree_groups_);
VP8LColorCacheClear(&hdr->color_cache_); VP8LColorCacheClear(&hdr->color_cache_);
VP8LColorCacheClear(&hdr->saved_color_cache_); VP8LColorCacheClear(&hdr->saved_color_cache_);
@ -1673,7 +1677,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
if (dec == NULL) return 0; if (dec == NULL) return 0;
assert(dec->hdr_.huffman_tables_ != NULL); assert(dec->hdr_.huffman_tables_.root.start != NULL);
assert(dec->hdr_.htree_groups_ != NULL); assert(dec->hdr_.htree_groups_ != NULL);
assert(dec->hdr_.num_htree_groups_ > 0); assert(dec->hdr_.num_htree_groups_ > 0);

View File

@ -51,7 +51,7 @@ typedef struct {
uint32_t* huffman_image_; uint32_t* huffman_image_;
int num_htree_groups_; int num_htree_groups_;
HTreeGroup* htree_groups_; HTreeGroup* htree_groups_;
HuffmanCode* huffman_tables_; HuffmanTables huffman_tables_;
} VP8LMetadata; } VP8LMetadata;
typedef struct VP8LDecoder VP8LDecoder; typedef struct VP8LDecoder VP8LDecoder;

View File

@ -13,6 +13,6 @@ noinst_HEADERS =
noinst_HEADERS += ../webp/format_constants.h noinst_HEADERS += ../webp/format_constants.h
libwebpdemux_la_LIBADD = ../libwebp.la libwebpdemux_la_LIBADD = ../libwebp.la
libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:13:0 libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:14:0
libwebpdemuxincludedir = $(includedir)/webp libwebpdemuxincludedir = $(includedir)/webp
pkgconfig_DATA = libwebpdemux.pc pkgconfig_DATA = libwebpdemux.pc

View File

@ -25,7 +25,7 @@
#define DMUX_MAJ_VERSION 1 #define DMUX_MAJ_VERSION 1
#define DMUX_MIN_VERSION 3 #define DMUX_MIN_VERSION 3
#define DMUX_REV_VERSION 1 #define DMUX_REV_VERSION 2
typedef struct { typedef struct {
size_t start_; // start location of the data size_t start_; // start location of the data

View File

@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,1 FILEVERSION 1,0,3,2
PRODUCTVERSION 1,0,3,1 PRODUCTVERSION 1,0,3,2
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -24,12 +24,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Google, Inc." VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebpdemux DLL" VALUE "FileDescription", "libwebpdemux DLL"
VALUE "FileVersion", "1.3.1" VALUE "FileVersion", "1.3.2"
VALUE "InternalName", "libwebpdemux.dll" VALUE "InternalName", "libwebpdemux.dll"
VALUE "LegalCopyright", "Copyright (C) 2023" VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "libwebpdemux.dll" VALUE "OriginalFilename", "libwebpdemux.dll"
VALUE "ProductName", "WebP Image Demuxer" VALUE "ProductName", "WebP Image Demuxer"
VALUE "ProductVersion", "1.3.1" VALUE "ProductVersion", "1.3.2"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -32,7 +32,7 @@ extern "C" {
// version numbers // version numbers
#define ENC_MAJ_VERSION 1 #define ENC_MAJ_VERSION 1
#define ENC_MIN_VERSION 3 #define ENC_MIN_VERSION 3
#define ENC_REV_VERSION 1 #define ENC_REV_VERSION 2
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost

View File

@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,1 FILEVERSION 1,0,3,2
PRODUCTVERSION 1,0,3,1 PRODUCTVERSION 1,0,3,2
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -24,12 +24,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Google, Inc." VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebp DLL" VALUE "FileDescription", "libwebp DLL"
VALUE "FileVersion", "1.3.1" VALUE "FileVersion", "1.3.2"
VALUE "InternalName", "libwebp.dll" VALUE "InternalName", "libwebp.dll"
VALUE "LegalCopyright", "Copyright (C) 2023" VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "libwebp.dll" VALUE "OriginalFilename", "libwebp.dll"
VALUE "ProductName", "WebP Image Codec" VALUE "ProductName", "WebP Image Codec"
VALUE "ProductVersion", "1.3.1" VALUE "ProductVersion", "1.3.2"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,1 FILEVERSION 1,0,3,2
PRODUCTVERSION 1,0,3,1 PRODUCTVERSION 1,0,3,2
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -24,12 +24,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Google, Inc." VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebpdecoder DLL" VALUE "FileDescription", "libwebpdecoder DLL"
VALUE "FileVersion", "1.3.1" VALUE "FileVersion", "1.3.2"
VALUE "InternalName", "libwebpdecoder.dll" VALUE "InternalName", "libwebpdecoder.dll"
VALUE "LegalCopyright", "Copyright (C) 2023" VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "libwebpdecoder.dll" VALUE "OriginalFilename", "libwebpdecoder.dll"
VALUE "ProductName", "WebP Image Decoder" VALUE "ProductName", "WebP Image Decoder"
VALUE "ProductVersion", "1.3.1" VALUE "ProductVersion", "1.3.2"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -17,6 +17,6 @@ noinst_HEADERS =
noinst_HEADERS += ../webp/format_constants.h noinst_HEADERS += ../webp/format_constants.h
libwebpmux_la_LIBADD = ../libwebp.la libwebpmux_la_LIBADD = ../libwebp.la
libwebpmux_la_LDFLAGS = -no-undefined -version-info 3:12:0 -lm libwebpmux_la_LDFLAGS = -no-undefined -version-info 3:13:0 -lm
libwebpmuxincludedir = $(includedir)/webp libwebpmuxincludedir = $(includedir)/webp
pkgconfig_DATA = libwebpmux.pc pkgconfig_DATA = libwebpmux.pc

View File

@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,1 FILEVERSION 1,0,3,2
PRODUCTVERSION 1,0,3,1 PRODUCTVERSION 1,0,3,2
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -24,12 +24,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Google, Inc." VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebpmux DLL" VALUE "FileDescription", "libwebpmux DLL"
VALUE "FileVersion", "1.3.1" VALUE "FileVersion", "1.3.2"
VALUE "InternalName", "libwebpmux.dll" VALUE "InternalName", "libwebpmux.dll"
VALUE "LegalCopyright", "Copyright (C) 2023" VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "libwebpmux.dll" VALUE "OriginalFilename", "libwebpmux.dll"
VALUE "ProductName", "WebP Image Muxer" VALUE "ProductName", "WebP Image Muxer"
VALUE "ProductVersion", "1.3.1" VALUE "ProductVersion", "1.3.2"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -29,7 +29,7 @@ extern "C" {
#define MUX_MAJ_VERSION 1 #define MUX_MAJ_VERSION 1
#define MUX_MIN_VERSION 3 #define MUX_MIN_VERSION 3
#define MUX_REV_VERSION 1 #define MUX_REV_VERSION 2
// Chunk object. // Chunk object.
typedef struct WebPChunk WebPChunk; typedef struct WebPChunk WebPChunk;

View File

@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
if (num_open < 0) { if (num_open < 0) {
return 0; return 0;
} }
if (root_table == NULL) continue;
for (; count[len] > 0; --count[len]) { for (; count[len] > 0; --count[len]) {
HuffmanCode code; HuffmanCode code;
if ((key & mask) != low) { if ((key & mask) != low) {
table += table_size; if (root_table != NULL) table += table_size;
table_bits = NextTableBitSize(count, len, root_bits); table_bits = NextTableBitSize(count, len, root_bits);
table_size = 1 << table_bits; table_size = 1 << table_bits;
total_size += table_size; total_size += table_size;
low = key & mask; low = key & mask;
root_table[low].bits = (uint8_t)(table_bits + root_bits); if (root_table != NULL) {
root_table[low].value = (uint16_t)((table - root_table) - low); root_table[low].bits = (uint8_t)(table_bits + root_bits);
root_table[low].value = (uint16_t)((table - root_table) - low);
}
}
if (root_table != NULL) {
code.bits = (uint8_t)(len - root_bits);
code.value = (uint16_t)sorted[symbol++];
ReplicateValue(&table[key >> root_bits], step, table_size, code);
} }
code.bits = (uint8_t)(len - root_bits);
code.value = (uint16_t)sorted[symbol++];
ReplicateValue(&table[key >> root_bits], step, table_size, code);
key = GetNextKey(key, len); key = GetNextKey(key, len);
} }
} }
@ -211,25 +214,83 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES) ((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES)
// Cut-off value for switching between heap and stack allocation. // Cut-off value for switching between heap and stack allocation.
#define SORTED_SIZE_CUTOFF 512 #define SORTED_SIZE_CUTOFF 512
int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
const int code_lengths[], int code_lengths_size) { const int code_lengths[], int code_lengths_size) {
int total_size; const int total_size =
BuildHuffmanTable(NULL, root_bits, code_lengths, code_lengths_size, NULL);
assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE); assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE);
if (root_table == NULL) { if (total_size == 0 || root_table == NULL) return total_size;
total_size = BuildHuffmanTable(NULL, root_bits,
code_lengths, code_lengths_size, NULL); if (root_table->curr_segment->curr_table + total_size >=
} else if (code_lengths_size <= SORTED_SIZE_CUTOFF) { root_table->curr_segment->start + root_table->curr_segment->size) {
// If 'root_table' does not have enough memory, allocate a new segment.
// The available part of root_table->curr_segment is left unused because we
// need a contiguous buffer.
const int segment_size = root_table->curr_segment->size;
struct HuffmanTablesSegment* next =
(HuffmanTablesSegment*)WebPSafeMalloc(1, sizeof(*next));
if (next == NULL) return 0;
// Fill the new segment.
// We need at least 'total_size' but if that value is small, it is better to
// allocate a big chunk to prevent more allocations later. 'segment_size' is
// therefore chosen (any other arbitrary value could be chosen).
next->size = total_size > segment_size ? total_size : segment_size;
next->start =
(HuffmanCode*)WebPSafeMalloc(next->size, sizeof(*next->start));
if (next->start == NULL) {
WebPSafeFree(next);
return 0;
}
next->curr_table = next->start;
next->next = NULL;
// Point to the new segment.
root_table->curr_segment->next = next;
root_table->curr_segment = next;
}
if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
// use local stack-allocated array. // use local stack-allocated array.
uint16_t sorted[SORTED_SIZE_CUTOFF]; uint16_t sorted[SORTED_SIZE_CUTOFF];
total_size = BuildHuffmanTable(root_table, root_bits, BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
code_lengths, code_lengths_size, sorted); code_lengths, code_lengths_size, sorted);
} else { // rare case. Use heap allocation. } else { // rare case. Use heap allocation.
uint16_t* const sorted = uint16_t* const sorted =
(uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted)); (uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted));
if (sorted == NULL) return 0; if (sorted == NULL) return 0;
total_size = BuildHuffmanTable(root_table, root_bits, BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
code_lengths, code_lengths_size, sorted); code_lengths, code_lengths_size, sorted);
WebPSafeFree(sorted); WebPSafeFree(sorted);
} }
return total_size; return total_size;
} }
int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) {
// Have 'segment' point to the first segment for now, 'root'.
HuffmanTablesSegment* const root = &huffman_tables->root;
huffman_tables->curr_segment = root;
// Allocate root.
root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
if (root->start == NULL) return 0;
root->curr_table = root->start;
root->next = NULL;
root->size = size;
return 1;
}
void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables) {
HuffmanTablesSegment *current, *next;
if (huffman_tables == NULL) return;
// Free the root node.
current = &huffman_tables->root;
next = current->next;
WebPSafeFree(current->start);
current->start = NULL;
current->next = NULL;
current = next;
// Free the following nodes.
while (current != NULL) {
next = current->next;
WebPSafeFree(current->start);
WebPSafeFree(current);
current = next;
}
}

View File

@ -43,6 +43,29 @@ typedef struct {
// or non-literal symbol otherwise // or non-literal symbol otherwise
} HuffmanCode32; } HuffmanCode32;
// Contiguous memory segment of HuffmanCodes.
typedef struct HuffmanTablesSegment {
HuffmanCode* start;
// Pointer to where we are writing into the segment. Starts at 'start' and
// cannot go beyond 'start' + 'size'.
HuffmanCode* curr_table;
// Pointer to the next segment in the chain.
struct HuffmanTablesSegment* next;
int size;
} HuffmanTablesSegment;
// Chained memory segments of HuffmanCodes.
typedef struct HuffmanTables {
HuffmanTablesSegment root;
// Currently processed segment. At first, this is 'root'.
HuffmanTablesSegment* curr_segment;
} HuffmanTables;
// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on
// memory allocation error, 1 otherwise.
int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables);
void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables);
#define HUFFMAN_PACKED_BITS 6 #define HUFFMAN_PACKED_BITS 6
#define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS) #define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS)
@ -78,9 +101,7 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
// the huffman table. // the huffman table.
// Returns built table size or 0 in case of error (invalid tree or // Returns built table size or 0 in case of error (invalid tree or
// memory error). // memory error).
// If root_table is NULL, it returns 0 if a lookup cannot be built, something int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
// > 0 otherwise (but not the table size).
int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
const int code_lengths[], int code_lengths_size); const int code_lengths[], int code_lengths_size);
#ifdef __cplusplus #ifdef __cplusplus