aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/lz
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2008-08-28 22:53:15 +0300
committerLasse Collin <lasse.collin@tukaani.org>2008-08-28 22:53:15 +0300
commit3b34851de1eaf358cf9268922fa0eeed8278d680 (patch)
tree7bab212af647541df64227a8d350d17a2e789f6b /src/liblzma/lz
parentFix test_filter_flags to match the new restriction of lc+lp. (diff)
downloadxz-3b34851de1eaf358cf9268922fa0eeed8278d680.tar.xz
Sort of garbage collection commit. :-| Many things are still
broken. API has changed a lot and it will still change a little more here and there. The command line tool doesn't have all the required changes to reflect the API changes, so it's easy to get "internal error" or trigger assertions.
Diffstat (limited to '')
-rw-r--r--debug/crc32.c (renamed from src/liblzma/lz/lz_encoder_private.h)41
-rw-r--r--src/liblzma/lz/Makefile.am35
-rw-r--r--src/liblzma/lz/bt2.c27
-rw-r--r--src/liblzma/lz/bt2.h31
-rw-r--r--src/liblzma/lz/bt3.c29
-rw-r--r--src/liblzma/lz/bt3.h31
-rw-r--r--src/liblzma/lz/bt4.c30
-rw-r--r--src/liblzma/lz/bt4.h31
-rw-r--r--src/liblzma/lz/hc3.c30
-rw-r--r--src/liblzma/lz/hc3.h31
-rw-r--r--src/liblzma/lz/hc4.c31
-rw-r--r--src/liblzma/lz/hc4.h31
-rw-r--r--src/liblzma/lz/lz_decoder.c547
-rw-r--r--src/liblzma/lz/lz_decoder.h308
-rw-r--r--src/liblzma/lz/lz_encoder.c780
-rw-r--r--src/liblzma/lz/lz_encoder.h334
-rw-r--r--src/liblzma/lz/lz_encoder_hash.h104
-rw-r--r--src/liblzma/lz/lz_encoder_mf.c780
-rw-r--r--src/liblzma/lz/match_c.h412
-rw-r--r--src/liblzma/lz/match_h.h69
-rw-r--r--src/liblzma/lzma/Makefile.am37
-rw-r--r--src/liblzma/lzma/fastpos.h8
-rw-r--r--src/liblzma/lzma/lzma2_decoder.c318
-rw-r--r--src/liblzma/lzma/lzma2_decoder.h35
-rw-r--r--src/liblzma/lzma/lzma2_encoder.c406
-rw-r--r--src/liblzma/lzma/lzma2_encoder.h (renamed from src/liblzma/common/raw_common.h)22
-rw-r--r--src/liblzma/lzma/lzma_common.h208
-rw-r--r--src/liblzma/lzma/lzma_decoder.c1306
-rw-r--r--src/liblzma/lzma/lzma_decoder.h21
-rw-r--r--src/liblzma/lzma/lzma_encoder.c576
-rw-r--r--src/liblzma/lzma/lzma_encoder.h38
-rw-r--r--src/liblzma/lzma/lzma_encoder_features.c2
-rw-r--r--src/liblzma/lzma/lzma_encoder_getoptimum.c925
-rw-r--r--src/liblzma/lzma/lzma_encoder_getoptimumfast.c201
-rw-r--r--src/liblzma/lzma/lzma_encoder_init.c228
-rw-r--r--src/liblzma/lzma/lzma_encoder_optimum_fast.c193
-rw-r--r--src/liblzma/lzma/lzma_encoder_optimum_normal.c875
-rw-r--r--src/liblzma/lzma/lzma_encoder_presets.c52
-rw-r--r--src/liblzma/lzma/lzma_encoder_private.h174
-rw-r--r--src/liblzma/lzma/lzma_literal.c51
-rw-r--r--src/liblzma/lzma/lzma_literal.h71
41 files changed, 5292 insertions, 4167 deletions
diff --git a/src/liblzma/lz/lz_encoder_private.h b/debug/crc32.c
index 638fcb2d..4052a863 100644
--- a/src/liblzma/lz/lz_encoder_private.h
+++ b/debug/crc32.c
@@ -1,10 +1,9 @@
///////////////////////////////////////////////////////////////////////////////
//
-/// \file lz_encoder_private.h
-/// \brief Private definitions for LZ encoder
+/// \file crc32.c
+/// \brief Primitive CRC32 calculation tool
//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
+// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -18,23 +17,29 @@
//
///////////////////////////////////////////////////////////////////////////////
-#ifndef LZMA_LZ_ENCODER_PRIVATE_H
-#define LZMA_LZ_ENCODER_PRIVATE_H
+#include "sysdefs.h"
+#include <stdio.h>
-#include "lz_encoder.h"
-/// Value used to indicate unused slot
-#define EMPTY_HASH_VALUE 0
+int
+main(void)
+{
+ uint32_t crc = 0;
-/// When the dictionary and hash variables need to be adjusted to prevent
-/// integer overflows. Since we use uint32_t to store the offsets, half
-/// of it is the biggest safe limit.
-#define MAX_VAL_FOR_NORMALIZE (UINT32_MAX / 2)
+ do {
+ uint8_t buf[BUFSIZ];
+ const size_t size = fread(buf, 1, sizeof(buf), stdin);
+ crc = lzma_crc32(buf, size, crc);
+ } while (!ferror(stdin) && !feof(stdin));
+ //printf("%08" PRIX32 "\n", crc);
-struct lzma_coder_s {
- lzma_next_coder next;
- lzma_lz_encoder lz;
-};
+ // I want it little endian so it's easy to work with hex editor.
+ printf("%02" PRIX32 " ", crc & 0xFF);
+ printf("%02" PRIX32 " ", (crc >> 8) & 0xFF);
+ printf("%02" PRIX32 " ", (crc >> 16) & 0xFF);
+ printf("%02" PRIX32 " ", crc >> 24);
+ printf("\n");
-#endif
+ return 0;
+}
diff --git a/src/liblzma/lz/Makefile.am b/src/liblzma/lz/Makefile.am
index 5c27e2f2..bf41d8e6 100644
--- a/src/liblzma/lz/Makefile.am
+++ b/src/liblzma/lz/Makefile.am
@@ -20,43 +20,16 @@ liblz_la_CPPFLAGS = \
liblz_la_SOURCES =
-if COND_MAIN_ENCODER
+if COND_ENCODER_LZ
liblz_la_SOURCES += \
lz_encoder.c \
lz_encoder.h \
- lz_encoder_private.h \
- match_c.h \
- match_h.h
-
-if COND_MF_HC3
-liblz_la_SOURCES += hc3.c hc3.h
-liblz_la_CPPFLAGS += -DHAVE_HC3
-endif
-
-if COND_MF_HC4
-liblz_la_SOURCES += hc4.c hc4.h
-liblz_la_CPPFLAGS += -DHAVE_HC4
-endif
-
-if COND_MF_BT2
-liblz_la_SOURCES += bt2.c bt2.h
-liblz_la_CPPFLAGS += -DHAVE_BT2
-endif
-
-if COND_MF_BT3
-liblz_la_SOURCES += bt3.c bt3.h
-liblz_la_CPPFLAGS += -DHAVE_BT3
-endif
-
-if COND_MF_BT4
-liblz_la_SOURCES += bt4.c bt4.h
-liblz_la_CPPFLAGS += -DHAVE_BT4
-endif
-
+ lz_encoder_hash.h \
+ lz_encoder_mf.c
endif
-if COND_MAIN_DECODER
+if COND_DECODER_LZ
liblz_la_SOURCES += \
lz_decoder.c \
lz_decoder.h
diff --git a/src/liblzma/lz/bt2.c b/src/liblzma/lz/bt2.c
deleted file mode 100644
index 7dc4cb80..00000000
--- a/src/liblzma/lz/bt2.c
+++ /dev/null
@@ -1,27 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file bt2.c
-/// \brief Binary Tree 2
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#include "bt2.h"
-
-#undef IS_HASH_CHAIN
-#undef HASH_ARRAY_2
-#undef HASH_ARRAY_3
-
-#include "match_c.h"
diff --git a/src/liblzma/lz/bt2.h b/src/liblzma/lz/bt2.h
deleted file mode 100644
index 33cb52cd..00000000
--- a/src/liblzma/lz/bt2.h
+++ /dev/null
@@ -1,31 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file bt2.h
-/// \brief Binary Tree 2
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef LZMA_BT2_H
-#define LZMA_BT2_H
-
-#undef LZMA_MATCH_FINDER_NAME_LOWER
-#undef LZMA_MATCH_FINDER_NAME_UPPER
-#define LZMA_MATCH_FINDER_NAME_LOWER bt2
-#define LZMA_MATCH_FINDER_NAME_UPPER BT2
-
-#include "match_h.h"
-
-#endif
diff --git a/src/liblzma/lz/bt3.c b/src/liblzma/lz/bt3.c
deleted file mode 100644
index d44310f3..00000000
--- a/src/liblzma/lz/bt3.c
+++ /dev/null
@@ -1,29 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file bt3.c
-/// \brief Binary Tree 3
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#include "bt3.h"
-
-#undef IS_HASH_CHAIN
-#undef HASH_ARRAY_2
-#undef HASH_ARRAY_3
-
-#define HASH_ARRAY_2
-
-#include "match_c.h"
diff --git a/src/liblzma/lz/bt3.h b/src/liblzma/lz/bt3.h
deleted file mode 100644
index 247c7e5f..00000000
--- a/src/liblzma/lz/bt3.h
+++ /dev/null
@@ -1,31 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file bt3.h
-/// \brief Binary Tree 3
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef LZMA_BT3_H
-#define LZMA_BT3_H
-
-#undef LZMA_MATCH_FINDER_NAME_LOWER
-#undef LZMA_MATCH_FINDER_NAME_UPPER
-#define LZMA_MATCH_FINDER_NAME_LOWER bt3
-#define LZMA_MATCH_FINDER_NAME_UPPER BT3
-
-#include "match_h.h"
-
-#endif
diff --git a/src/liblzma/lz/bt4.c b/src/liblzma/lz/bt4.c
deleted file mode 100644
index 6e1042c9..00000000
--- a/src/liblzma/lz/bt4.c
+++ /dev/null
@@ -1,30 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file bt4.c
-/// \brief Binary Tree 4
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#include "bt4.h"
-
-#undef IS_HASH_CHAIN
-#undef HASH_ARRAY_2
-#undef HASH_ARRAY_3
-
-#define HASH_ARRAY_2
-#define HASH_ARRAY_3
-
-#include "match_c.h"
diff --git a/src/liblzma/lz/bt4.h b/src/liblzma/lz/bt4.h
deleted file mode 100644
index e3fcf6ac..00000000
--- a/src/liblzma/lz/bt4.h
+++ /dev/null
@@ -1,31 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file bt4.h
-/// \brief Binary Tree 4
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef LZMA_BT4_H
-#define LZMA_BT4_H
-
-#undef LZMA_MATCH_FINDER_NAME_LOWER
-#undef LZMA_MATCH_FINDER_NAME_UPPER
-#define LZMA_MATCH_FINDER_NAME_LOWER bt4
-#define LZMA_MATCH_FINDER_NAME_UPPER BT4
-
-#include "match_h.h"
-
-#endif
diff --git a/src/liblzma/lz/hc3.c b/src/liblzma/lz/hc3.c
deleted file mode 100644
index 22b5689b..00000000
--- a/src/liblzma/lz/hc3.c
+++ /dev/null
@@ -1,30 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file hc3.c
-/// \brief Hash Chain 3
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#include "hc3.h"
-
-#undef IS_HASH_CHAIN
-#undef HASH_ARRAY_2
-#undef HASH_ARRAY_3
-
-#define IS_HASH_CHAIN
-#define HASH_ARRAY_2
-
-#include "match_c.h"
diff --git a/src/liblzma/lz/hc3.h b/src/liblzma/lz/hc3.h
deleted file mode 100644
index 97be0b1d..00000000
--- a/src/liblzma/lz/hc3.h
+++ /dev/null
@@ -1,31 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file hc3.h
-/// \brief Hash Chain 3
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef LZMA_HC3_H
-#define LZMA_HC3_H
-
-#undef LZMA_MATCH_FINDER_NAME_LOWER
-#undef LZMA_MATCH_FINDER_NAME_UPPER
-#define LZMA_MATCH_FINDER_NAME_LOWER hc3
-#define LZMA_MATCH_FINDER_NAME_UPPER HC3
-
-#include "match_h.h"
-
-#endif
diff --git a/src/liblzma/lz/hc4.c b/src/liblzma/lz/hc4.c
deleted file mode 100644
index a55cfd09..00000000
--- a/src/liblzma/lz/hc4.c
+++ /dev/null
@@ -1,31 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file hc4.c
-/// \brief Hash Chain 4
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#include "hc4.h"
-
-#undef IS_HASH_CHAIN
-#undef HASH_ARRAY_2
-#undef HASH_ARRAY_3
-
-#define IS_HASH_CHAIN
-#define HASH_ARRAY_2
-#define HASH_ARRAY_3
-
-#include "match_c.h"
diff --git a/src/liblzma/lz/hc4.h b/src/liblzma/lz/hc4.h
deleted file mode 100644
index dc072e2f..00000000
--- a/src/liblzma/lz/hc4.h
+++ /dev/null
@@ -1,31 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file hc4.h
-/// \brief Hash Chain 4
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef LZMA_HC4_H
-#define LZMA_HC4_H
-
-#undef LZMA_MATCH_FINDER_NAME_LOWER
-#undef LZMA_MATCH_FINDER_NAME_UPPER
-#define LZMA_MATCH_FINDER_NAME_LOWER hc4
-#define LZMA_MATCH_FINDER_NAME_UPPER HC4
-
-#include "match_h.h"
-
-#endif
diff --git a/src/liblzma/lz/lz_decoder.c b/src/liblzma/lz/lz_decoder.c
index ae969d62..5c3f1d18 100644
--- a/src/liblzma/lz/lz_decoder.c
+++ b/src/liblzma/lz/lz_decoder.c
@@ -18,351 +18,142 @@
//
///////////////////////////////////////////////////////////////////////////////
-#include "lz_decoder.h"
+// liblzma supports multiple LZ77-based filters. The LZ part is shared
+// between these filters. The LZ code takes care of dictionary handling
+// and passing the data between filters in the chain. The filter-specific
+// part decodes from the input buffer to the dictionary.
-/// Minimum size of allocated dictionary
-#define DICT_SIZE_MIN 8192
+#include "lz_decoder.h"
-/// When there is less than this amount of data available for decoding,
-/// it is moved to the temporary buffer which
-/// - protects from reads past the end of the buffer; and
-/// - stored the incomplete data between lzma_code() calls.
-///
-/// \note TEMP_LIMIT must be at least as much as
-/// REQUIRED_IN_BUFFER_SIZE defined in lzma_decoder.c.
-#define TEMP_LIMIT 32
-// lzma_lz_decoder.dict[] must be three times the size of TEMP_LIMIT.
-// 2 * TEMP_LIMIT is used for the actual data, and the third TEMP_LIMIT
-// bytes is needed for safety to allow decode_dummy() in lzma_decoder.c
-// to read past end of the buffer. This way it should be both fast and simple.
-#if LZMA_BUFFER_SIZE < 3 * TEMP_LIMIT
-# error LZMA_BUFFER_SIZE < 3 * TEMP_LIMIT
-#endif
+struct lzma_coder_s {
+ /// Dictionary (history buffer)
+ lzma_dict dict;
+ /// The actual LZ-based decoder e.g. LZMA
+ lzma_lz_decoder lz;
-struct lzma_coder_s {
+ /// Next filter in the chain, if any. Note that LZMA and LZMA2 are
+ /// only allowed as the last filter, but the long-range filter in
+ /// future can be in the middle of the chain.
lzma_next_coder next;
- lzma_lz_decoder lz;
- // There are more members in this structure but they are not
- // visible in LZ coder.
+ /// True if the next filter in the chain has returned LZMA_STREAM_END.
+ bool next_finished;
+
+ /// True if the LZ decoder (e.g. LZMA) has detected end of payload
+ /// marker. This may become true before next_finished becomes true.
+ bool this_finished;
+
+ /// Temporary buffer needed when the LZ-based filter is not the last
+ /// filter in the chain. The output of the next filter is first
+ /// decoded into buffer[], which is then used as input for the actual
+ /// LZ-based decoder.
+ struct {
+ size_t pos;
+ size_t size;
+ uint8_t buffer[LZMA_BUFFER_SIZE];
+ } temp;
};
-/// - Copy as much data as possible from lz->dict[] to out[].
-/// - Update *out_pos, lz->start, and lz->end accordingly.
-/// - Wrap lz-pos to the beginning of lz->dict[] if there is a danger that
-/// it may go past the end of the buffer (lz->pos >= lz->must_flush_pos).
-static inline bool
-flush(lzma_lz_decoder *restrict lz, uint8_t *restrict out,
- size_t *restrict out_pos, size_t out_size)
-{
- // Flush uncompressed data from the history buffer to
- // the output buffer. This is done in two phases.
-
- assert(lz->start <= lz->end);
-
- // Flush if pos < start < end.
- if (lz->pos < lz->start && lz->start < lz->end) {
- bufcpy(lz->dict, &lz->start, lz->end, out, out_pos, out_size);
-
- // If we reached end of the data in history buffer,
- // wrap to the beginning.
- if (lz->start == lz->end)
- lz->start = 0;
- }
-
- // Flush if start start < pos <= end. This is not as `else' for
- // previous `if' because the previous one may make this one true.
- if (lz->start < lz->pos) {
- bufcpy(lz->dict, &lz->start,
- lz->pos, out, out_pos, out_size);
-
- if (lz->pos >= lz->must_flush_pos) {
- // Wrap the flushing position if we have
- // flushed the whole history buffer.
- if (lz->pos == lz->start)
- lz->start = 0;
-
- // Wrap the write position and store to lz.end
- // how much there is new data available.
- lz->end = lz->pos;
- lz->pos = 0;
- lz->is_full = true;
- }
- }
-
- assert(lz->pos < lz->must_flush_pos);
-
- return *out_pos == out_size;
-}
-
-
-/// Calculate safe value for lz->limit. If no safe value can be found,
-/// set lz->limit to zero. When flushing, only as little data will be
-/// decoded as is needed to fill the output buffer (lowers both latency
-/// and throughput).
-///
-/// \return true if there is no space for new uncompressed data.
-///
-static inline bool
-set_limit(lzma_lz_decoder *lz, size_t out_avail, bool flushing)
-{
- // Set the limit so that writing to dict[limit + match_max_len - 1]
- // doesn't overwrite any unflushed data and doesn't write past the
- // end of the dict buffer.
- if (lz->start <= lz->pos) {
- // We can fill the buffer from pos till the end
- // of the dict buffer.
- lz->limit = lz->must_flush_pos;
- } else if (lz->pos + lz->match_max_len < lz->start) {
- // There's some unflushed data between pos and end of the
- // buffer. Limit so that we don't overwrite the unflushed data.
- lz->limit = lz->start - lz->match_max_len;
- } else {
- // Buffer is too full.
- lz->limit = 0;
- return true;
- }
-
- // Finetune the limit a bit if it isn't zero.
-
- assert(lz->limit > lz->pos);
- const size_t dict_avail = lz->limit - lz->pos;
-
- if (lz->uncompressed_size < dict_avail) {
- // Finishing a stream that doesn't have
- // an end of stream marker.
- lz->limit = lz->pos + lz->uncompressed_size;
-
- } else if (flushing && out_avail < dict_avail) {
- // Flushing enabled, decoding only as little as needed to
- // fill the out buffer (if there's enough input, of course).
- lz->limit = lz->pos + out_avail;
- }
-
- return lz->limit == lz->pos;
-}
-
-
-/// Takes care of wrapping the data into temporary buffer when needed,
-/// and calls the actual decoder.
-///
-/// \return true if error occurred
-///
-static inline bool
-call_process(lzma_coder *restrict coder, const uint8_t *restrict in,
- size_t *restrict in_pos, size_t in_size)
-{
- // It would be nice and simple if we could just give in[] to the
- // decoder, but the requirement of zlib-like API forces us to be
- // able to make *in_pos == in_size whenever there is enough output
- // space. If needed, we will append a few bytes from in[] to
- // a temporary buffer and decode enough to reach the part that
- // was copied from in[]. Then we can continue with the real in[].
-
- bool error;
- const size_t dict_old_pos = coder->lz.pos;
- const size_t in_avail = in_size - *in_pos;
-
- if (coder->lz.temp_size + in_avail < 2 * TEMP_LIMIT) {
- // Copy all the available input from in[] to temp[].
- memcpy(coder->lz.temp + coder->lz.temp_size,
- in + *in_pos, in_avail);
- coder->lz.temp_size += in_avail;
- *in_pos += in_avail;
- assert(*in_pos == in_size);
-
- // Decode as much as possible.
- size_t temp_used = 0;
- error = coder->lz.process(coder, coder->lz.temp, &temp_used,
- coder->lz.temp_size, true);
- assert(temp_used <= coder->lz.temp_size);
-
- // Move the remaining data to the beginning of temp[].
- coder->lz.temp_size -= temp_used;
- memmove(coder->lz.temp, coder->lz.temp + temp_used,
- coder->lz.temp_size);
-
- } else if (coder->lz.temp_size > 0) {
- // Fill temp[] unless it is already full because we aren't
- // the last filter in the chain.
- size_t copy_size = 0;
- if (coder->lz.temp_size < 2 * TEMP_LIMIT) {
- assert(*in_pos < in_size);
- copy_size = 2 * TEMP_LIMIT - coder->lz.temp_size;
- memcpy(coder->lz.temp + coder->lz.temp_size,
- in + *in_pos, copy_size);
- // NOTE: We don't update lz.temp_size or *in_pos yet.
- }
-
- size_t temp_used = 0;
- error = coder->lz.process(coder, coder->lz.temp, &temp_used,
- coder->lz.temp_size + copy_size, false);
-
- if (temp_used < coder->lz.temp_size) {
- // Only very little input data was consumed. Move
- // the unprocessed data to the beginning temp[].
- coder->lz.temp_size += copy_size - temp_used;
- memmove(coder->lz.temp, coder->lz.temp + temp_used,
- coder->lz.temp_size);
- *in_pos += copy_size;
- assert(*in_pos <= in_size);
-
- } else {
- // We were able to decode so much data that next time
- // we can decode directly from in[]. That is, we can
- // consider temp[] to be empty now.
- *in_pos += temp_used - coder->lz.temp_size;
- coder->lz.temp_size = 0;
- assert(*in_pos <= in_size);
- }
-
- } else {
- // Decode directly from in[].
- error = coder->lz.process(coder, in, in_pos, in_size, false);
- assert(*in_pos <= in_size);
- }
-
- assert(coder->lz.pos >= dict_old_pos);
- if (coder->lz.uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
- // Update uncompressed size.
- coder->lz.uncompressed_size -= coder->lz.pos - dict_old_pos;
-
- // Check that End of Payload Marker hasn't been detected
- // since it must not be present because uncompressed size
- // is known.
- if (coder->lz.eopm_detected)
- error = true;
- }
-
- return error;
-}
-
-
static lzma_ret
decode_buffer(lzma_coder *coder,
const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out,
- size_t *restrict out_pos, size_t out_size,
- bool flushing)
+ size_t *restrict out_pos, size_t out_size)
{
- bool stop = false;
-
while (true) {
- // Flush from coder->lz.dict to out[].
- flush(&coder->lz, out, out_pos, out_size);
-
- // All done?
- if (*out_pos == out_size
- || stop
- || coder->lz.eopm_detected
- || coder->lz.uncompressed_size == 0)
- break;
-
- // Set write limit in the dictionary.
- if (set_limit(&coder->lz, out_size - *out_pos, flushing))
- break;
-
- // Decode more data.
- if (call_process(coder, in, in_pos, in_size))
- return LZMA_DATA_ERROR;
-
- // Set stop to true if we must not call call_process() again
- // during this function call.
- // FIXME: Can this make the loop exist too early? It wouldn't
- // cause data corruption so not a critical problem. It can
- // happen if dictionary gets full and lz.temp still contains
- // a few bytes data that we could decode right now.
- if (*in_pos == in_size && coder->lz.temp_size <= TEMP_LIMIT
- && coder->lz.pos < coder->lz.limit)
- stop = true;
+ // Wrap the dictionary if needed.
+ if (coder->dict.pos == coder->dict.size)
+ coder->dict.pos = 0;
+
+ // Store the current dictionary position. It is needed to know
+ // where to start copying to the out[] buffer.
+ const size_t dict_start = coder->dict.pos;
+
+ // Calculate how much we allow the process() function to
+ // decode. It must not decode past the end of the dictionary
+ // buffer, and we don't want it to decode more than is
+ // actually needed to fill the out[] buffer.
+ coder->dict.limit = coder->dict.pos + MIN(out_size - *out_pos,
+ coder->dict.size - coder->dict.pos);
+
+ // Call the process() function to do the actual decoding.
+ const lzma_ret ret = coder->lz.code(
+ coder->lz.coder, &coder->dict,
+ in, in_pos, in_size);
+
+ // Copy the decoded data from the dictionary to the out[]
+ // buffer.
+ const size_t copy_size = coder->dict.pos - dict_start;
+ assert(copy_size <= out_size - *out_pos);
+ memcpy(out + *out_pos, coder->dict.buf + dict_start,
+ copy_size);
+ *out_pos += copy_size;
+
+ // Return if everything got decoded or an error occurred, or
+ // if there's no more data to decode.
+ if (ret != LZMA_OK || *out_pos == out_size
+ || coder->dict.pos < coder->dict.size)
+ return ret;
}
-
- // If we have decoded everything (EOPM detected or uncompressed_size
- // bytes were processed) to the history buffer, and also flushed
- // everything from the history buffer, our job is done.
- if ((coder->lz.eopm_detected
- || coder->lz.uncompressed_size == 0)
- && coder->lz.start == coder->lz.pos)
- return LZMA_STREAM_END;
-
- return LZMA_OK;
}
-extern lzma_ret
-lzma_lz_decode(lzma_coder *coder,
+static lzma_ret
+lz_decode(lzma_coder *coder,
lzma_allocator *allocator lzma_attribute((unused)),
const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size,
lzma_action action)
{
- if (coder->next.code == NULL) {
- const lzma_ret ret = decode_buffer(coder, in, in_pos, in_size,
- out, out_pos, out_size,
- action == LZMA_SYNC_FLUSH);
-
- if (*out_pos == out_size || ret == LZMA_STREAM_END) {
- // Unread to make coder->temp[] empty. This is easy,
- // because we know that all the data currently in
- // coder->temp[] has been copied form in[] during this
- // call to the decoder.
- //
- // If we didn't do this, we could have data left in
- // coder->temp[] when end of stream is reached. That
- // data could be left there from *previous* call to
- // the decoder; in that case we wouldn't know where
- // to put that data.
- assert(*in_pos >= coder->lz.temp_size);
- *in_pos -= coder->lz.temp_size;
- coder->lz.temp_size = 0;
- }
-
- return ret;
- }
+ if (coder->next.code == NULL)
+ return decode_buffer(coder, in, in_pos, in_size,
+ out, out_pos, out_size);
// We aren't the last coder in the chain, we need to decode
// our input to a temporary buffer.
- const bool flushing = action == LZMA_SYNC_FLUSH;
while (*out_pos < out_size) {
- if (!coder->lz.next_finished
- && coder->lz.temp_size < LZMA_BUFFER_SIZE) {
+ // Fill the temporary buffer if it is empty.
+ if (!coder->next_finished
+ && coder->temp.pos == coder->temp.size) {
+ coder->temp.pos = 0;
+ coder->temp.size = 0;
+
const lzma_ret ret = coder->next.code(
coder->next.coder,
allocator, in, in_pos, in_size,
- coder->lz.temp, &coder->lz.temp_size,
+ coder->temp.buffer, &coder->temp.size,
LZMA_BUFFER_SIZE, action);
if (ret == LZMA_STREAM_END)
- coder->lz.next_finished = true;
- else if (coder->lz.temp_size < LZMA_BUFFER_SIZE
- || ret != LZMA_OK)
+ coder->next_finished = true;
+ else if (ret != LZMA_OK || coder->temp.size == 0)
return ret;
}
- if (coder->lz.this_finished) {
- if (coder->lz.temp_size != 0)
+ if (coder->this_finished) {
+ if (coder->temp.size != 0)
return LZMA_DATA_ERROR;
- if (coder->lz.next_finished)
+ if (coder->next_finished)
return LZMA_STREAM_END;
return LZMA_OK;
}
- size_t dummy = 0;
- const lzma_ret ret = decode_buffer(coder, NULL, &dummy, 0,
- out, out_pos, out_size, flushing);
+ const lzma_ret ret = decode_buffer(coder, coder->temp.buffer,
+ &coder->temp.pos, coder->temp.size,
+ out, out_pos, out_size);
if (ret == LZMA_STREAM_END)
- coder->lz.this_finished = true;
+ coder->this_finished = true;
else if (ret != LZMA_OK)
return ret;
- else if (coder->lz.next_finished && *out_pos < out_size)
+ else if (coder->next_finished && *out_pos < out_size)
return LZMA_DATA_ERROR;
}
@@ -370,94 +161,104 @@ lzma_lz_decode(lzma_coder *coder,
}
-/// \brief Initializes LZ part of the LZMA decoder or Inflate
-///
-/// \param history_size Number of bytes the LZ out window is
-/// supposed keep available from the output
-/// history.
-/// \param match_max_len Number of bytes a single decoding loop
-/// can advance the write position (lz->pos)
-/// in the history buffer (lz->dict).
-///
-/// \note This function is called by LZMA decoder and Inflate init()s.
-/// It's up to those functions allocate *lz and initialize it
-/// with LZMA_LZ_DECODER_INIT.
+static void
+lz_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_end(&coder->next, allocator);
+ lzma_free(coder->dict.buf, allocator);
+
+ if (coder->lz.end != NULL)
+ coder->lz.end(coder->lz.coder, allocator);
+ else
+ lzma_free(coder->lz.coder, allocator);
+
+ lzma_free(coder, allocator);
+ return;
+}
+
+
extern lzma_ret
-lzma_lz_decoder_reset(lzma_lz_decoder *lz, lzma_allocator *allocator,
- bool (*process)(lzma_coder *restrict coder,
- const uint8_t *restrict in, size_t *restrict in_pos,
- size_t in_size, bool has_safe_buffer),
- size_t history_size, size_t match_max_len)
+lzma_lz_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters,
+ lzma_ret (*lz_init)(lzma_lz_decoder *lz,
+ lzma_allocator *allocator, const void *options,
+ size_t *dict_size))
{
- // Known uncompressed size is used only with LZMA_Alone files so we
- // set it always to unknown by default.
- lz->uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
-
- // Limit the history size to roughly sane values. This is primarily
- // to prevent integer overflows.
- if (history_size > UINT32_MAX / 2)
- return LZMA_HEADER_ERROR;
-
- // Store the value actually requested. We use it for sanity checks
- // when repeating data from the history buffer.
- lz->requested_size = history_size;
-
- // Avoid tiny history buffer sizes for performance reasons.
- // TODO: Test if this actually helps...
- if (history_size < DICT_SIZE_MIN)
- history_size = DICT_SIZE_MIN;
-
- // The real size of the history buffer is a bit bigger than
- // requested by our caller. This allows us to do some optimizations,
- // which help not only speed but simplicity of the code; specifically,
- // we can make sure that there is always at least match_max_len
- // bytes immediatelly available for writing without a need to wrap
- // the history buffer.
- const size_t dict_real_size = history_size + 2 * match_max_len + 1;
-
- // Reallocate memory if needed.
- if (history_size != lz->size || match_max_len != lz->match_max_len) {
- // Destroy the old buffer.
- lzma_lz_decoder_end(lz, allocator);
-
- lz->size = history_size;
- lz->match_max_len = match_max_len;
- lz->must_flush_pos = history_size + match_max_len + 1;
-
- lz->dict = lzma_alloc(dict_real_size, allocator);
- if (lz->dict == NULL)
+ // Allocate the base structure if it isn't already allocated.
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
return LZMA_MEM_ERROR;
+
+ next->code = &lz_decode;
+ next->end = &lz_decoder_end;
+
+ next->coder->dict.buf = NULL;
+ next->coder->dict.size = 0;
+ next->coder->lz = LZMA_LZ_DECODER_INIT;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
}
- // Reset the variables so that lz_get_byte(lz, 0) will return '\0'.
- lz->pos = 0;
- lz->start = 0;
- lz->end = dict_real_size;
- lz->dict[dict_real_size - 1] = 0;
- lz->is_full = false;
- lz->eopm_detected = false;
- lz->next_finished = false;
- lz->this_finished = false;
- lz->temp_size = 0;
-
- // Clean up the temporary buffer to make it very sure that there are
- // no information leaks when multiple steams are decoded with the
- // same decoder structures.
- memzero(lz->temp, LZMA_BUFFER_SIZE);
-
- // Set the process function pointer.
- lz->process = process;
+ // Allocate and initialize the LZ-based decoder. It will also give
+ // us the dictionary size.
+ size_t dict_size;
+ return_if_error(lz_init(&next->coder->lz, allocator,
+ filters[0].options, &dict_size));
+
+ // If the dictionary size is very small, increase it to 4096 bytes.
+ // This is to prevent constant wrapping of the dictionary, which
+ // would slow things down. The downside is that since we don't check
+ // separately for the real dictionary size, we may happily accept
+ // corrupt files.
+ if (dict_size < 4096)
+ dict_size = 4096;
+
+ // Make dictionary size a multipe of 16. Some LZ-based decoders like
+ // LZMA use the lowest bits lzma_dict.pos to know the alignment of the
+ // data. Aligned buffer is also good when memcpying from the
+ // dictionary to the output buffer, since applications are
+ // recommended to give aligned buffers to liblzma.
+ //
+ // Avoid integer overflow. FIXME Should the return value be
+ // LZMA_HEADER_ERROR or LZMA_MEM_ERROR?
+ if (dict_size > SIZE_MAX - 15)
+ return LZMA_MEM_ERROR;
+
+ dict_size = (dict_size + 15) & (SIZE_MAX - 15);
+
+ // Allocate and initialize the dictionary.
+ if (next->coder->dict.size != dict_size) {
+ lzma_free(next->coder->dict.buf, allocator);
+ next->coder->dict.buf = lzma_alloc(dict_size, allocator);
+ if (next->coder->dict.buf == NULL)
+ return LZMA_MEM_ERROR;
- return LZMA_OK;
+ next->coder->dict.size = dict_size;
+ }
+
+ dict_reset(&next->coder->dict);
+
+ // Miscellaneous initializations
+ next->coder->next_finished = false;
+ next->coder->this_finished = false;
+ next->coder->temp.pos = 0;
+ next->coder->temp.size = 0;
+
+ // Initialize the next filter in the chain, if any.
+ return lzma_next_filter_init(&next->coder->next, allocator,
+ filters + 1);
+}
+
+
+extern uint64_t
+lzma_lz_decoder_memusage(size_t dictionary_size)
+{
+ return sizeof(lzma_coder) + (uint64_t)(dictionary_size);
}
extern void
-lzma_lz_decoder_end(lzma_lz_decoder *lz, lzma_allocator *allocator)
+lzma_lz_decoder_uncompressed(lzma_coder *coder, lzma_vli uncompressed_size)
{
- lzma_free(lz->dict, allocator);
- lz->dict = NULL;
- lz->size = 0;
- lz->match_max_len = 0;
- return;
+ coder->lz.set_uncompressed(coder->lz.coder, uncompressed_size);
}
diff --git a/src/liblzma/lz/lz_decoder.h b/src/liblzma/lz/lz_decoder.h
index 1acf9831..d2a77ba4 100644
--- a/src/liblzma/lz/lz_decoder.h
+++ b/src/liblzma/lz/lz_decoder.h
@@ -18,201 +18,215 @@
//
///////////////////////////////////////////////////////////////////////////////
-#ifndef LZMA_LZ_OUT_H
-#define LZMA_LZ_OUT_H
+#ifndef LZMA_LZ_DECODER_H
+#define LZMA_LZ_DECODER_H
#include "common.h"
-/// Get a byte from the history buffer.
-#define lz_get_byte(lz, distance) \
- ((distance) < (lz).pos \
- ? (lz).dict[(lz).pos - (distance) - 1] \
- : (lz).dict[(lz).pos - (distance) - 1 + (lz).end])
-
-
-/// Test if dictionary is empty.
-#define lz_is_empty(lz) \
- ((lz).pos == 0 && !(lz).is_full)
-
-
-#define LZMA_LZ_DECODER_INIT \
- (lzma_lz_decoder){ .dict = NULL, .size = 0, .match_max_len = 0 }
-
-
typedef struct {
- /// Function to do the actual decoding (LZMA or Inflate)
- bool (*process)(lzma_coder *restrict coder, const uint8_t *restrict in,
- size_t *restrict in_pos, size_t size_in,
- bool has_safe_buffer);
+ /// Pointer to the dictionary buffer. It can be an allocated buffer
+ /// internal to liblzma, or it can a be a buffer given by the
+ /// application when in single-call mode (not implemented yet).
+ uint8_t *buf;
- /// Pointer to dictionary (history) buffer.
- /// \note Not 'restrict' because can alias next_out.
- uint8_t *dict;
-
- /// Next write goes to dict[pos].
+ /// Write position in dictionary. The next byte will be written to
+ /// buf[pos].
size_t pos;
- /// Next byte to flush is buffer[start].
- size_t start;
-
- /// First byte to not flush is buffer[end].
- size_t end;
+ /// Indicates how full the dictionary is. This is used by
+ /// dict_is_distance_valid() to detect corrupt files that would
+ /// read beyond the beginning of the dictionary.
+ size_t full;
- /// First position to which data must not be written.
+ /// Write limit
size_t limit;
- /// True if dictionary has needed wrapping.
- bool is_full;
-
- /// True if process() has detected End of Payload Marker.
- bool eopm_detected;
+ /// Size of the dictionary
+ size_t size;
- /// True if the next coder in the chain has returned LZMA_STREAM_END.
- bool next_finished;
+} lzma_dict;
- /// True if the LZ decoder (e.g. LZMA) has detected End of Payload
- /// Marker. This may become true before next_finished becomes true.
- bool this_finished;
- /// When pos >= must_flush_pos, we must not call process().
- size_t must_flush_pos;
+typedef struct {
+ /// Data specific to the LZ-based decoder
+ lzma_coder *coder;
- /// Maximum number of bytes that a single decoding loop inside
- /// process() can produce data into dict. This amount is kept
- /// always available at dict + pos i.e. it is safe to write a byte
- /// to dict[pos + match_max_len - 1].
- size_t match_max_len;
+ /// Function to decode from in[] to *dict
+ lzma_ret (*code)(lzma_coder *restrict coder,
+ lzma_dict *restrict dict, const uint8_t *restrict in,
+ size_t *restrict in_pos, size_t in_size);
- /// Number of bytes allocated to dict.
- size_t size;
+ void (*reset)(lzma_coder *coder, const void *options);
- /// Requested size of the dictionary. This is needed because we avoid
- /// using extremely tiny history buffers.
- size_t requested_size;
+ /// Set the uncompressed size
+ void (*set_uncompressed)(lzma_coder *coder,
+ lzma_vli uncompressed_size);
- /// Uncompressed Size or LZMA_VLI_VALUE_UNKNOWN if unknown.
- lzma_vli uncompressed_size;
+ /// Free allocated resources
+ void (*end)(lzma_coder *coder, lzma_allocator *allocator);
- /// Number of bytes currently in temp[].
- size_t temp_size;
+} lzma_lz_decoder;
- /// Temporary buffer needed when
- /// 1) we cannot make the input buffer completely empty; or
- /// 2) we are not the last filter in the chain.
- uint8_t temp[LZMA_BUFFER_SIZE];
-} lzma_lz_decoder;
+#define LZMA_LZ_DECODER_INIT \
+ (lzma_lz_decoder){ \
+ .coder = NULL, \
+ .code = NULL, \
+ .reset = NULL, \
+ .set_uncompressed = NULL, \
+ .end = NULL, \
+ }
-/////////////////////////
-// Function prototypes //
-/////////////////////////
+extern lzma_ret lzma_lz_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters,
+ lzma_ret (*lz_init)(lzma_lz_decoder *lz,
+ lzma_allocator *allocator, const void *options,
+ size_t *dict_size));
-extern lzma_ret lzma_lz_decoder_reset(lzma_lz_decoder *lz,
- lzma_allocator *allocator, bool (*process)(
- lzma_coder *restrict coder, const uint8_t *restrict in,
- size_t *restrict in_pos, size_t in_size,
- bool has_safe_buffer),
- size_t history_size, size_t match_max_len);
+extern uint64_t lzma_lz_decoder_memusage(size_t dictionary_size);
-extern lzma_ret lzma_lz_decode(lzma_coder *coder, lzma_allocator *allocator,
- const uint8_t *restrict in, size_t *restrict in_pos,
- size_t in_size, uint8_t *restrict out,
- size_t *restrict out_pos, size_t out_size,
- lzma_action action);
+extern void lzma_lz_decoder_uncompressed(
+ lzma_coder *coder, lzma_vli uncompressed_size);
-/// Deallocates the history buffer if one exists.
-extern void lzma_lz_decoder_end(
- lzma_lz_decoder *lz, lzma_allocator *allocator);
//////////////////////
// Inline functions //
//////////////////////
-// Repeat a block of data from the history. Because memcpy() is faster
-// than copying byte by byte in a loop, the copying process gets split
-// into three cases:
-// 1. distance < length
-// Source and target areas overlap, thus we can't use memcpy()
-// (nor memmove()) safely.
-// TODO: If this is common enough, it might be worth optimizing this
-// more e.g. by checking if distance > sizeof(uint8_t*) and using
-// memcpy in small chunks.
-// 2. distance < pos
-// This is the easiest and the fastest case. The block being copied
-// is a contiguous piece in the history buffer. The buffer offset
-// doesn't need wrapping.
-// 3. distance >= pos
-// We need to wrap the position, because otherwise we would try copying
-// behind the first byte of the allocated buffer. It is possible that
-// the block is fragmeneted into two pieces, thus we might need to call
-// memcpy() twice.
-// NOTE: The function using this macro must ensure that length is positive
-// and that distance is FIXME
+/// Get a byte from the history buffer.
+static inline uint8_t
+dict_get(const lzma_dict *const dict, const uint32_t distance)
+{
+ return dict->buf[dict->pos - distance - 1
+ + (distance < dict->pos ? 0 : dict->size)];
+}
+
+
+/// Test if dictionary is empty.
+static inline bool
+dict_is_empty(const lzma_dict *const dict)
+{
+ return dict->full == 0;
+}
+
+
+/// Validate the match distance
+static inline bool
+dict_is_distance_valid(const lzma_dict *const dict, const size_t distance)
+{
+ return dict->full >= distance;
+}
+
+
+/// Repeat *len bytes at distance.
static inline bool
-lzma_lz_out_repeat(lzma_lz_decoder *lz, size_t distance, size_t length)
+dict_repeat(lzma_dict *dict, uint32_t distance, uint32_t *len)
{
- // Validate offset of the block to be repeated. It doesn't
- // make sense to copy data behind the beginning of the stream.
- // Leaving this check away would lead to a security problem,
- // in which e.g. the data of the previously decoded file(s)
- // would be leaked (or whatever happens to be in unused
- // part of the dictionary buffer).
- if (unlikely(distance >= lz->pos && !lz->is_full))
- return false;
-
- // It also doesn't make sense to copy data farer than
- // the dictionary size.
- if (unlikely(distance >= lz->requested_size))
- return false;
-
- // The caller must have checked these!
- assert(distance <= lz->size);
- assert(length > 0);
- assert(length <= lz->match_max_len);
-
- // Copy the amount of data requested by the decoder.
- if (distance < length) {
+ // Don't write past the end of the dictionary.
+ const size_t dict_avail = dict->limit - dict->pos;
+ uint32_t left = MIN(dict_avail, *len);
+ *len -= left;
+
+ // Repeat a block of data from the history. Because memcpy() is faster
+ // than copying byte by byte in a loop, the copying process gets split
+ // into three cases.
+ if (distance < left) {
// Source and target areas overlap, thus we can't use
- // memcpy() nor even memmove() safely. :-(
- // TODO: Copying byte by byte is slow. It might be
- // worth optimizing this more if this case is common.
+ // memcpy() nor even memmove() safely.
do {
- lz->dict[lz->pos] = lz_get_byte(*lz, distance);
- ++lz->pos;
- } while (--length > 0);
+ dict->buf[dict->pos] = dict_get(dict, distance);
+ ++dict->pos;
+ } while (--left > 0);
- } else if (distance < lz->pos) {
+ } else if (distance < dict->pos) {
// The easiest and fastest case
- memcpy(lz->dict + lz->pos,
- lz->dict + lz->pos - distance - 1,
- length);
- lz->pos += length;
+ memcpy(dict->buf + dict->pos,
+ dict->buf + dict->pos - distance - 1,
+ left);
+ dict->pos += left;
} else {
// The bigger the dictionary, the more rare this
// case occurs. We need to "wrap" the dict, thus
// we might need two memcpy() to copy all the data.
- assert(lz->is_full);
- const uint32_t copy_pos = lz->pos - distance - 1 + lz->end;
- uint32_t copy_size = lz->end - copy_pos;
+ assert(dict->full == dict->size);
+ const uint32_t copy_pos
+ = dict->pos - distance - 1 + dict->size;
+ uint32_t copy_size = dict->size - copy_pos;
- if (copy_size < length) {
- memcpy(lz->dict + lz->pos, lz->dict + copy_pos,
+ if (copy_size < left) {
+ memcpy(dict->buf + dict->pos, dict->buf + copy_pos,
copy_size);
- lz->pos += copy_size;
- copy_size = length - copy_size;
- memcpy(lz->dict + lz->pos, lz->dict, copy_size);
- lz->pos += copy_size;
+ dict->pos += copy_size;
+ copy_size = left - copy_size;
+ memcpy(dict->buf + dict->pos, dict->buf, copy_size);
+ dict->pos += copy_size;
} else {
- memcpy(lz->dict + lz->pos, lz->dict + copy_pos,
- length);
- lz->pos += length;
+ memcpy(dict->buf + dict->pos, dict->buf + copy_pos,
+ left);
+ dict->pos += left;
}
}
- return true;
+ // Update how full the dictionary is.
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
+
+ return unlikely(*len != 0);
+}
+
+
+/// Puts one byte into the dictionary. Returns true if the dictionary was
+/// already full and the byte couldn't be added.
+static inline bool
+dict_put(lzma_dict *dict, uint8_t byte)
+{
+ if (unlikely(dict->pos == dict->limit))
+ return true;
+
+ dict->buf[dict->pos++] = byte;
+
+ if (dict->pos > dict->full)
+ dict->full = dict->pos;
+
+ return false;
+}
+
+
+/// Copies arbitrary amount of data into the dictionary.
+static inline void
+dict_write(lzma_dict *restrict dict, const uint8_t *restrict in,
+ size_t *restrict in_pos, size_t in_size,
+ size_t *restrict left)
+{
+ // NOTE: If we are being given more data than the size of the
+ // dictionary, it could be possible to optimize the LZ decoder
+ // so that not everything needs to go through the dictionary.
+ // This shouldn't be very common thing in practice though, and
+ // the slowdown of one extra memcpy() isn't bad compared to how
+ // much time it would have taken if the data were compressed.
+
+ if (in_size - *in_pos > *left)
+ in_size = *in_pos + *left;
+
+ *left -= lzma_bufcpy(in, in_pos, in_size,
+ dict->buf, &dict->pos, dict->limit);
+
+ if (dict->pos > dict->full)
+ dict->full = dict->pos;
+
+ return;
+}
+
+
+static inline void
+dict_reset(lzma_dict *dict)
+{
+ dict->pos = 0;
+ dict->full = 0;
+ dict->buf[dict->size - 1] = '\0';
}
#endif
diff --git a/src/liblzma/lz/lz_encoder.c b/src/liblzma/lz/lz_encoder.c
index 82b9103f..d5f84826 100644
--- a/src/liblzma/lz/lz_encoder.c
+++ b/src/liblzma/lz/lz_encoder.c
@@ -3,8 +3,8 @@
/// \file lz_encoder.c
/// \brief LZ in window
//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
+// Copyright (C) 1999-2008 Igor Pavlov
+// Copyright (C) 2007-2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -18,496 +18,492 @@
//
///////////////////////////////////////////////////////////////////////////////
-#include "lz_encoder_private.h"
+#include "lz_encoder.h"
+#include "lz_encoder_hash.h"
-// Hash Chains
-#ifdef HAVE_HC3
-# include "hc3.h"
-#endif
-#ifdef HAVE_HC4
-# include "hc4.h"
-#endif
-// Binary Trees
-#ifdef HAVE_BT2
-# include "bt2.h"
-#endif
-#ifdef HAVE_BT3
-# include "bt3.h"
-#endif
-#ifdef HAVE_BT4
-# include "bt4.h"
-#endif
+struct lzma_coder_s {
+ /// LZ-based encoder e.g. LZMA
+ lzma_lz_encoder lz;
+ /// History buffer and match finder
+ lzma_mf mf;
-/// This is needed in two places so provide a macro.
-#define get_cyclic_buffer_size(history_size) ((history_size) + 1)
+ /// Next coder in the chain
+ lzma_next_coder next;
+};
-/// Calculate certain match finder properties and validate the calculated
-/// values. This is as its own function, because *num_items is needed to
-/// calculate memory requirements in common/memory.c.
-extern bool
-lzma_lz_encoder_hash_properties(lzma_match_finder match_finder,
- uint32_t history_size, uint32_t *restrict hash_mask,
- uint32_t *restrict hash_size_sum, uint32_t *restrict num_items)
+/// \brief Moves the data in the input window to free space for new data
+///
+/// mf->buffer is a sliding input window, which keeps mf->keep_size_before
+/// bytes of input history available all the time. Now and then we need to
+/// "slide" the buffer to make space for the new data to the end of the
+/// buffer. At the same time, data older than keep_size_before is dropped.
+///
+static void
+move_window(lzma_mf *mf)
{
- uint32_t fix_hash_size;
- uint32_t sons;
+ // Align the move to a multiple of 16 bytes. Some LZ-based encoders
+ // like LZMA use the lowest bits of mf->read_pos to know the
+ // alignment of the uncompressed data. We also get better speed
+ // for memmove() with aligned buffers.
+ assert(mf->read_pos > mf->keep_size_before);
+ const uint32_t move_offset
+ = (mf->read_pos - mf->keep_size_before) & ~UINT32_C(15);
- switch (match_finder) {
-#ifdef HAVE_HC3
- case LZMA_MF_HC3:
- fix_hash_size = LZMA_HC3_FIX_HASH_SIZE;
- sons = 1;
- break;
-#endif
-#ifdef HAVE_HC4
- case LZMA_MF_HC4:
- fix_hash_size = LZMA_HC4_FIX_HASH_SIZE;
- sons = 1;
- break;
-#endif
-#ifdef HAVE_BT2
- case LZMA_MF_BT2:
- fix_hash_size = LZMA_BT2_FIX_HASH_SIZE;
- sons = 2;
- break;
-#endif
-#ifdef HAVE_BT3
- case LZMA_MF_BT3:
- fix_hash_size = LZMA_BT3_FIX_HASH_SIZE;
- sons = 2;
- break;
-#endif
-#ifdef HAVE_BT4
- case LZMA_MF_BT4:
- fix_hash_size = LZMA_BT4_FIX_HASH_SIZE;
- sons = 2;
- break;
-#endif
- default:
- return true;
- }
+ assert(mf->write_pos > move_offset);
+ const size_t move_size = mf->write_pos - move_offset;
- uint32_t hs;
+ assert(move_offset + move_size <= mf->size);
-#ifdef HAVE_LZMA_BT2
- if (match_finder == LZMA_BT2) {
- // NOTE: hash_mask is not used by the BT2 match finder,
- // but it is initialized just in case.
- hs = LZMA_BT2_HASH_SIZE;
- *hash_mask = 0;
- } else
-#endif
- {
- hs = history_size - 1;
- hs |= (hs >> 1);
- hs |= (hs >> 2);
- hs |= (hs >> 4);
- hs |= (hs >> 8);
- hs >>= 1;
- hs |= 0xFFFF;
+ memmove(mf->buffer, mf->buffer + move_offset, move_size);
- if (hs > (UINT32_C(1) << 24)) {
- if (match_finder == LZMA_MF_HC4
- || match_finder == LZMA_MF_BT4)
- hs >>= 1;
- else
- hs = (1 << 24) - 1;
- }
+ mf->offset += move_offset;
+ mf->read_pos -= move_offset;
+ mf->read_limit -= move_offset;
+ mf->write_pos -= move_offset;
+
+ return;
+}
- *hash_mask = hs;
- ++hs;
- }
- *hash_size_sum = hs + fix_hash_size;
+/// \brief Tries to fill the input window (mf->buffer)
+///
+/// If we are the last encoder in the chain, our input data is in in[].
+/// Otherwise we call the next filter in the chain to process in[] and
+/// write its output to mf->buffer.
+///
+/// This function must not be called once it has returned LZMA_STREAM_END.
+///
+static lzma_ret
+fill_window(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *in,
+ size_t *in_pos, size_t in_size, lzma_action action)
+{
+ assert(coder->mf.read_pos <= coder->mf.write_pos);
- *num_items = *hash_size_sum
- + get_cyclic_buffer_size(history_size) * sons;
+ // Move the sliding window if needed.
+ if (coder->mf.read_pos >= coder->mf.size - coder->mf.keep_size_after)
+ move_window(&coder->mf);
- return false;
-}
+ size_t in_used;
+ lzma_ret ret;
+ if (coder->next.code == NULL) {
+ // Not using a filter, simply memcpy() as much as possible.
+ in_used = lzma_bufcpy(in, in_pos, in_size, coder->mf.buffer,
+ &coder->mf.write_pos, coder->mf.size);
+ ret = action != LZMA_RUN && *in_pos == in_size
+ ? LZMA_STREAM_END : LZMA_OK;
-extern lzma_ret
-lzma_lz_encoder_reset(lzma_lz_encoder *lz, lzma_allocator *allocator,
- bool (*process)(lzma_coder *coder, uint8_t *restrict out,
- size_t *restrict out_pos, size_t out_size),
- size_t history_size, size_t additional_buffer_before,
- size_t match_max_len, size_t additional_buffer_after,
- lzma_match_finder match_finder, uint32_t match_finder_cycles,
- const uint8_t *preset_dictionary,
- size_t preset_dictionary_size)
-{
- lz->sequence = SEQ_RUN;
+ } else {
+ const size_t in_start = *in_pos;
+ ret = coder->next.code(coder->next.coder, allocator,
+ in, in_pos, in_size,
+ coder->mf.buffer, &coder->mf.write_pos,
+ coder->mf.size, action);
+ in_used = *in_pos - in_start;
+ }
- ///////////////
- // In Window //
- ///////////////
+ // If end of stream has been reached or flushing completed, we allow
+ // the encoder to process all the input (that is, read_pos is allowed
+ // to reach write_pos). Otherwise we keep keep_size_after bytes
+ // available as prebuffer.
+ if (ret == LZMA_STREAM_END) {
+ assert(*in_pos == in_size);
+ ret = LZMA_OK;
+ coder->mf.action = action;
+ coder->mf.read_limit = coder->mf.write_pos;
- // Validate history size.
- if (history_size < LZMA_DICTIONARY_SIZE_MIN
- || history_size > LZMA_DICTIONARY_SIZE_MAX) {
- lzma_lz_encoder_end(lz, allocator);
- return LZMA_HEADER_ERROR;
+ } else if (coder->mf.write_pos > coder->mf.keep_size_after) {
+ // This needs to be done conditionally, because if we got
+ // only little new input, there may be too little input
+ // to do any encoding yet.
+ coder->mf.read_limit = coder->mf.write_pos
+ - coder->mf.keep_size_after;
}
- assert(history_size <= MAX_VAL_FOR_NORMALIZE - 256);
- assert(LZMA_DICTIONARY_SIZE_MAX <= MAX_VAL_FOR_NORMALIZE - 256);
+ // Restart the match finder after finished LZMA_SYNC_FLUSH.
+ if (coder->mf.pending > 0
+ && coder->mf.read_pos < coder->mf.read_limit) {
+ // Match finder may update coder->pending and expects it to
+ // start from zero, so use a temporary variable.
+ const size_t pending = coder->mf.pending;
+ coder->mf.pending = 0;
- // Calculate the size of the history buffer to allocate.
- // TODO: Get a reason for magic constant of 256.
- const size_t size_reserv = (history_size + additional_buffer_before
- + match_max_len + additional_buffer_after) / 2 + 256;
+ // Rewind read_pos so that the match finder can hash
+ // the pending bytes.
+ assert(coder->mf.read_pos >= pending);
+ coder->mf.read_pos -= pending;
- lz->keep_size_before = history_size + additional_buffer_before;
- lz->keep_size_after = match_max_len + additional_buffer_after;
+ // Call the skip function directly instead of using
+ // lz_dict_skip(), since we don't want to touch
+ // mf->read_ahead.
+ coder->mf.skip(&coder->mf, pending);
+ }
- const size_t buffer_size = lz->keep_size_before + lz->keep_size_after
- + size_reserv;
+ return ret;
+}
- // Allocate history buffer if its size has changed.
- if (buffer_size != lz->size) {
- lzma_free(lz->buffer, allocator);
- lz->buffer = lzma_alloc(buffer_size, allocator);
- if (lz->buffer == NULL) {
- lzma_lz_encoder_end(lz, allocator);
- return LZMA_MEM_ERROR;
+
+static lzma_ret
+lz_encode(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *restrict in, size_t *restrict in_pos,
+ size_t in_size,
+ uint8_t *restrict out, size_t *restrict out_pos,
+ size_t out_size, lzma_action action)
+{
+ while (*out_pos < out_size
+ && (*in_pos < in_size || action != LZMA_RUN)) {
+ // Read more data to coder->mf.buffer if needed.
+ if (coder->mf.action == LZMA_RUN && coder->mf.read_pos
+ >= coder->mf.read_limit)
+ return_if_error(fill_window(coder, allocator,
+ in, in_pos, in_size, action));
+
+ // Encode
+ const lzma_ret ret = coder->lz.code(coder->lz.coder,
+ &coder->mf, out, out_pos, out_size);
+ if (ret != LZMA_OK) {
+ // Setting this to LZMA_RUN for cases when we are
+ // flushing. It doesn't matter when finishing or if
+ // an error occurred.
+ coder->mf.action = LZMA_RUN;
+ return ret;
}
}
- // Allocation successful. Store the new size.
- lz->size = buffer_size;
+ return LZMA_OK;
+}
+
+
+static bool
+lz_encoder_prepare(lzma_mf *mf, lzma_allocator *allocator,
+ const lzma_lz_options *lz_options)
+{
+ if (lz_options->dictionary_size < LZMA_DICTIONARY_SIZE_MIN
+ || lz_options->dictionary_size
+ > LZMA_DICTIONARY_SIZE_MAX
+ || lz_options->find_len_max
+ > lz_options->match_len_max)
+ return true;
+
+ mf->keep_size_before = lz_options->before_size
+ + lz_options->dictionary_size;
- // Reset in window variables.
- lz->offset = 0;
- lz->read_pos = 0;
- lz->read_limit = 0;
- lz->write_pos = 0;
- lz->pending = 0;
+ mf->keep_size_after = lz_options->after_size
+ + lz_options->match_len_max;
+ // To avoid constant memmove()s, allocate some extra space. Since
+ // memmove()s become more expensive when the size of the buffer
+ // increases, we reserve more space when a large dictionary is
+ // used to make the memmove() calls rarer.
+ uint32_t reserve = lz_options->dictionary_size / 2;
+ if (reserve > (UINT32_C(1) << 30))
+ reserve /= 2;
- //////////////////
- // Match Finder //
- //////////////////
+ reserve += (lz_options->before_size + lz_options->match_len_max
+ + lz_options->after_size) / 2 + (UINT32_C(1) << 19);
- // Validate match_finder, set function pointers and a few match
- // finder specific variables.
- switch (match_finder) {
-#ifdef HAVE_HC3
+ const uint32_t old_size = mf->size;
+ mf->size = mf->keep_size_before + reserve + mf->keep_size_after;
+
+ // FIXME Integer overflows
+
+ // Deallocate the old history buffer if it exists but has different
+ // size than what is needed now.
+ if (mf->buffer != NULL && old_size != mf->size) {
+ lzma_free(mf->buffer, allocator);
+ mf->buffer = NULL;
+ }
+
+ // Match finder options
+ mf->match_len_max = lz_options->match_len_max;
+ mf->find_len_max = lz_options->find_len_max;
+ mf->cyclic_buffer_size = lz_options->dictionary_size + 1;
+
+ // Validate the match finder ID and setup the function pointers.
+ switch (lz_options->match_finder) {
+#ifdef HAVE_MF_HC3
case LZMA_MF_HC3:
- lz->get_matches = &lzma_hc3_get_matches;
- lz->skip = &lzma_hc3_skip;
- lz->cut_value = 8 + (match_max_len >> 2);
+ mf->find = &lzma_mf_hc3_find;
+ mf->skip = &lzma_mf_hc3_skip;
break;
#endif
-#ifdef HAVE_HC4
+#ifdef HAVE_MF_HC4
case LZMA_MF_HC4:
- lz->get_matches = &lzma_hc4_get_matches;
- lz->skip = &lzma_hc4_skip;
- lz->cut_value = 8 + (match_max_len >> 2);
+ mf->find = &lzma_mf_hc4_find;
+ mf->skip = &lzma_mf_hc4_skip;
break;
#endif
-#ifdef HAVE_BT2
+#ifdef HAVE_MF_BT2
case LZMA_MF_BT2:
- lz->get_matches = &lzma_bt2_get_matches;
- lz->skip = &lzma_bt2_skip;
- lz->cut_value = 16 + (match_max_len >> 1);
+ mf->find = &lzma_mf_bt2_find;
+ mf->skip = &lzma_mf_bt2_skip;
break;
#endif
-#ifdef HAVE_BT3
+#ifdef HAVE_MF_BT3
case LZMA_MF_BT3:
- lz->get_matches = &lzma_bt3_get_matches;
- lz->skip = &lzma_bt3_skip;
- lz->cut_value = 16 + (match_max_len >> 1);
+ mf->find = &lzma_mf_bt3_find;
+ mf->skip = &lzma_mf_bt3_skip;
break;
#endif
-#ifdef HAVE_BT4
+#ifdef HAVE_MF_BT4
case LZMA_MF_BT4:
- lz->get_matches = &lzma_bt4_get_matches;
- lz->skip = &lzma_bt4_skip;
- lz->cut_value = 16 + (match_max_len >> 1);
+ mf->find = &lzma_mf_bt4_find;
+ mf->skip = &lzma_mf_bt4_skip;
break;
#endif
+
default:
- lzma_lz_encoder_end(lz, allocator);
- return LZMA_HEADER_ERROR;
+ return true;
}
- // Check if we have been requested to use a non-default cut_value.
- if (match_finder_cycles > 0)
- lz->cut_value = match_finder_cycles;
-
- lz->match_max_len = match_max_len;
- lz->cyclic_buffer_size = get_cyclic_buffer_size(history_size);
+ // Calculate the sizes of mf->hash and mf->son.
+ const uint32_t hash_bytes = lz_options->match_finder & 0x0F;
+ const bool is_bt = (lz_options->match_finder & 0x10) != 0;
+ uint32_t hs;
- uint32_t hash_size_sum;
- uint32_t num_items;
- if (lzma_lz_encoder_hash_properties(match_finder, history_size,
- &lz->hash_mask, &hash_size_sum, &num_items)) {
- lzma_lz_encoder_end(lz, allocator);
- return LZMA_HEADER_ERROR;
- }
+ if (hash_bytes == 2) {
+ hs = 0xFFFF;
+ } else {
+ // Round dictionary size up to the next 2^n - 1 so it can
+ // be used as a hash mask.
+ hs = lz_options->dictionary_size - 1;
+ hs |= hs >> 1;
+ hs |= hs >> 2;
+ hs |= hs >> 4;
+ hs |= hs >> 8;
+ hs >>= 1;
+ hs |= 0xFFFF;
- if (num_items != lz->num_items) {
-#if UINT32_MAX >= SIZE_MAX / 4
- // Check for integer overflow. (Huge dictionaries are not
- // possible on 32-bit CPU.)
- if (num_items > SIZE_MAX / sizeof(uint32_t)) {
- lzma_lz_encoder_end(lz, allocator);
- return LZMA_MEM_ERROR;
+ if (hs > (UINT32_C(1) << 24)) {
+ if (hash_bytes == 3)
+ hs = (UINT32_C(1) << 24) - 1;
+ else
+ hs >>= 1;
}
-#endif
-
- const size_t size_in_bytes
- = (size_t)(num_items) * sizeof(uint32_t);
+ }
- lzma_free(lz->hash, allocator);
- lz->hash = lzma_alloc(size_in_bytes, allocator);
- if (lz->hash == NULL) {
- lzma_lz_encoder_end(lz, allocator);
- return LZMA_MEM_ERROR;
- }
+ mf->hash_mask = hs;
+
+ ++hs;
+ if (hash_bytes > 2)
+ hs += HASH_2_SIZE;
+ if (hash_bytes > 3)
+ hs += HASH_3_SIZE;
+/*
+ No match finder uses this at the moment.
+ if (mf->hash_bytes > 4)
+ hs += HASH_4_SIZE;
+*/
+
+ const uint32_t old_count = mf->hash_size_sum + mf->sons_count;
+ mf->hash_size_sum = hs;
+ mf->sons_count = mf->cyclic_buffer_size;
+ if (is_bt)
+ mf->sons_count *= 2;
+
+ const uint32_t new_count = mf->hash_size_sum + mf->sons_count;
+
+ // Deallocate the old hash array if it exists and has different size
+ // than what is needed now.
+ if (mf->hash != NULL && old_count != new_count) {
+ lzma_free(mf->hash, allocator);
+ mf->hash = NULL;
+ }
- lz->num_items = num_items;
+ // Maximum number of match finder cycles
+ mf->loops = lz_options->match_finder_cycles;
+ if (mf->loops == 0) {
+ mf->loops = 16 + (lz_options->find_len_max / 2);
+ if (!is_bt)
+ mf->loops /= 2;
}
- lz->son = lz->hash + hash_size_sum;
+ return false;
+}
- // Reset the hash table to empty hash values.
- {
- uint32_t *restrict items = lz->hash;
- for (uint32_t i = 0; i < hash_size_sum; ++i)
- items[i] = EMPTY_HASH_VALUE;
+static bool
+lz_encoder_init(lzma_mf *mf, lzma_allocator *allocator)
+{
+ // Allocate the history buffer.
+ if (mf->buffer == NULL) {
+ mf->buffer = lzma_alloc(mf->size, allocator);
+ if (mf->buffer == NULL)
+ return true;
}
- lz->cyclic_buffer_pos = 0;
+ // Use cyclic_buffer_size as initial mf->offset. This allows
+ // avoiding a few branches in the match finders. The downside is
+ // that match finder needs to be normalized more often, which may
+ // hurt performance with huge dictionaries.
+ mf->offset = mf->cyclic_buffer_size;
+ mf->read_pos = 0;
+ mf->read_ahead = 0;
+ mf->read_limit = 0;
+ mf->write_pos = 0;
+ mf->pending = 0;
- // Because zero is used as empty hash value, make the first byte
- // appear at buffer[1 - offset].
- ++lz->offset;
+ // Allocate match finder's hash array.
+ const size_t alloc_count = mf->hash_size_sum + mf->sons_count;
- // If we are using a preset dictionary, read it now.
- // TODO: This isn't implemented yet so return LZMA_HEADER_ERROR.
- if (preset_dictionary != NULL && preset_dictionary_size > 0) {
- lzma_lz_encoder_end(lz, allocator);
- return LZMA_HEADER_ERROR;
+#if UINT32_MAX >= SIZE_MAX / 4
+ // Check for integer overflow. (Huge dictionaries are not
+ // possible on 32-bit CPU.)
+ if (alloc_count > SIZE_MAX / sizeof(uint32_t))
+ return true;
+#endif
+
+ if (mf->hash == NULL) {
+ mf->hash = lzma_alloc(alloc_count * sizeof(uint32_t),
+ allocator);
+ if (mf->hash == NULL)
+ return true;
}
- // Set the process function pointer.
- lz->process = process;
+ mf->son = mf->hash + mf->hash_size_sum;
+ mf->cyclic_buffer_pos = 0;
+
+ // Initialize the hash table. Since EMPTY_HASH_VALUE is zero, we
+ // can use memset().
+/*
+ for (uint32_t i = 0; i < hash_size_sum; ++i)
+ mf->hash[i] = EMPTY_HASH_VALUE;
+*/
+ memzero(mf->hash, (size_t)(mf->hash_size_sum) * sizeof(uint32_t));
+
+ // We don't need to initialize mf->son, but not doing that will
+ // make Valgrind complain in normalization (see normalize() in
+ // lz_encoder_mf.c).
+ //
+ // Skipping this initialization is *very* good when big dictionary is
+ // used but only small amount of data gets actually compressed: most
+ // of the mf->hash won't get actually allocated by the kernel, so
+ // we avoid wasting RAM and improve initialization speed a lot.
+ //memzero(mf->son, (size_t)(mf->sons_count) * sizeof(uint32_t));
+
+ mf->action = LZMA_RUN;
- return LZMA_OK;
+ return false;
}
-extern void
-lzma_lz_encoder_end(lzma_lz_encoder *lz, lzma_allocator *allocator)
+extern uint64_t
+lzma_lz_encoder_memusage(const lzma_lz_options *lz_options)
{
- lzma_free(lz->hash, allocator);
- lz->hash = NULL;
- lz->num_items = 0;
-
- lzma_free(lz->buffer, allocator);
- lz->buffer = NULL;
- lz->size = 0;
-
- return;
+ // Old buffers must not exist when calling lz_encoder_prepare().
+ lzma_mf mf = {
+ .buffer = NULL,
+ .hash = NULL,
+ };
+
+ // Setup the size information into mf.
+ if (lz_encoder_prepare(&mf, NULL, lz_options))
+ return UINT64_MAX;
+
+ // Calculate the memory usage.
+ return (uint64_t)(mf.hash_size_sum + mf.sons_count)
+ * sizeof(uint32_t)
+ + (uint64_t)(mf.size) + sizeof(lzma_coder);
}
-/// \brief Moves the data in the input window to free space for new data
-///
-/// lz->buffer is a sliding input window, which keeps lz->keep_size_before
-/// bytes of input history available all the time. Now and then we need to
-/// "slide" the buffer to make space for the new data to the end of the
-/// buffer. At the same time, data older than keep_size_before is dropped.
-///
static void
-move_window(lzma_lz_encoder *lz)
+lz_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
{
- // buffer[move_offset] will become buffer[0].
- assert(lz->read_pos > lz->keep_size_after);
- size_t move_offset = lz->read_pos - lz->keep_size_before;
-
- // We need one additional byte, since move_pos() moves on 1 byte.
- // TODO: Clean up? At least document more.
- if (move_offset > 0)
- --move_offset;
-
- assert(lz->write_pos > move_offset);
- const size_t move_size = lz->write_pos - move_offset;
+ lzma_next_end(&coder->next, allocator);
- assert(move_offset + move_size <= lz->size);
+ lzma_free(coder->mf.hash, allocator);
+ lzma_free(coder->mf.buffer, allocator);
- memmove(lz->buffer, lz->buffer + move_offset, move_size);
-
- lz->offset += move_offset;
- lz->read_pos -= move_offset;
- lz->read_limit -= move_offset;
- lz->write_pos -= move_offset;
+ if (coder->lz.end != NULL)
+ coder->lz.end(coder->lz.coder, allocator);
+ else
+ lzma_free(coder->lz.coder, allocator);
+ lzma_free(coder, allocator);
return;
}
-/// \brief Tries to fill the input window (lz->buffer)
-///
-/// If we are the last encoder in the chain, our input data is in in[].
-/// Otherwise we call the next filter in the chain to process in[] and
-/// write its output to lz->buffer.
-///
-/// This function must not be called once it has returned LZMA_STREAM_END.
-///
-static lzma_ret
-fill_window(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *in,
- size_t *in_pos, size_t in_size, lzma_action action)
+extern lzma_ret
+lzma_lz_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters,
+ lzma_ret (*lz_init)(lzma_lz_encoder *lz,
+ lzma_allocator *allocator, const void *options,
+ lzma_lz_options *lz_options))
{
- assert(coder->lz.read_pos <= coder->lz.write_pos);
+ // Allocate and initialize the base data structure.
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
- // Move the sliding window if needed.
- if (coder->lz.read_pos >= coder->lz.size - coder->lz.keep_size_after)
- move_window(&coder->lz);
+ next->code = &lz_encode;
+ next->end = &lz_encoder_end;
- size_t in_used;
- lzma_ret ret;
- if (coder->next.code == NULL) {
- // Not using a filter, simply memcpy() as much as possible.
- in_used = bufcpy(in, in_pos, in_size, coder->lz.buffer,
- &coder->lz.write_pos, coder->lz.size);
+ next->coder->lz.coder = NULL;
+ next->coder->lz.code = NULL;
+ next->coder->lz.end = NULL;
- if (action != LZMA_RUN && *in_pos == in_size)
- ret = LZMA_STREAM_END;
- else
- ret = LZMA_OK;
+ next->coder->mf.buffer = NULL;
+ next->coder->mf.hash = NULL;
- } else {
- const size_t in_start = *in_pos;
- ret = coder->next.code(coder->next.coder, allocator,
- in, in_pos, in_size,
- coder->lz.buffer, &coder->lz.write_pos,
- coder->lz.size, action);
- in_used = *in_pos - in_start;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
}
- // If end of stream has been reached or flushing completed, we allow
- // the encoder to process all the input (that is, read_pos is allowed
- // to reach write_pos). Otherwise we keep keep_size_after bytes
- // available as prebuffer.
- if (ret == LZMA_STREAM_END) {
- assert(*in_pos == in_size);
- coder->lz.read_limit = coder->lz.write_pos;
- ret = LZMA_OK;
+ // Initialize the LZ-based encoder.
+ lzma_lz_options lz_options;
+ return_if_error(lz_init(&next->coder->lz, allocator,
+ filters[0].options, &lz_options));
- switch (action) {
- case LZMA_SYNC_FLUSH:
- coder->lz.sequence = SEQ_FLUSH;
- break;
-
- case LZMA_FINISH:
- coder->lz.sequence = SEQ_FINISH;
- break;
-
- default:
- assert(0);
- ret = LZMA_PROG_ERROR;
- break;
- }
-
- } else if (coder->lz.write_pos > coder->lz.keep_size_after) {
- // This needs to be done conditionally, because if we got
- // only little new input, there may be too little input
- // to do any encoding yet.
- coder->lz.read_limit = coder->lz.write_pos
- - coder->lz.keep_size_after;
- }
-
- // Restart the match finder after finished LZMA_SYNC_FLUSH.
- if (coder->lz.pending > 0
- && coder->lz.read_pos < coder->lz.read_limit) {
- // Match finder may update coder->pending and expects it to
- // start from zero, so use a temporary variable.
- const size_t pending = coder->lz.pending;
- coder->lz.pending = 0;
+ // Setup the size information into next->coder->mf and deallocate
+ // old buffers if they have wrong size.
+ if (lz_encoder_prepare(&next->coder->mf, allocator, &lz_options))
+ return LZMA_HEADER_ERROR;
- // Rewind read_pos so that the match finder can hash
- // the pending bytes.
- assert(coder->lz.read_pos >= pending);
- coder->lz.read_pos -= pending;
- coder->lz.skip(&coder->lz, pending);
- }
+ // Allocate new buffers if needed, and do the rest of
+ // the initialization.
+ if (lz_encoder_init(&next->coder->mf, allocator))
+ return LZMA_MEM_ERROR;
- return ret;
+ // Initialize the next filter in the chain, if any.
+ return lzma_next_filter_init(&next->coder->next, allocator,
+ filters + 1);
}
-extern lzma_ret
-lzma_lz_encode(lzma_coder *coder, lzma_allocator *allocator,
- const uint8_t *restrict in, size_t *restrict in_pos,
- size_t in_size,
- uint8_t *restrict out, size_t *restrict out_pos,
- size_t out_size, lzma_action action)
+extern LZMA_API lzma_bool
+lzma_mf_is_supported(lzma_match_finder mf)
{
- while (*out_pos < out_size
- && (*in_pos < in_size || action != LZMA_RUN)) {
- // Read more data to coder->lz.buffer if needed.
- if (coder->lz.sequence == SEQ_RUN
- && coder->lz.read_pos >= coder->lz.read_limit)
- return_if_error(fill_window(coder, allocator,
- in, in_pos, in_size, action));
+ bool ret = false;
- // Encode
- if (coder->lz.process(coder, out, out_pos, out_size)) {
- // Setting this to SEQ_RUN for cases when we are
- // flushing. It doesn't matter when finishing.
- coder->lz.sequence = SEQ_RUN;
- return action != LZMA_RUN ? LZMA_STREAM_END : LZMA_OK;
- }
- }
+#ifdef HAVE_MF_HC3
+ if (mf == LZMA_MF_HC3)
+ ret = true;
+#endif
- return LZMA_OK;
-}
+#ifdef HAVE_MF_HC4
+ if (mf == LZMA_MF_HC4)
+ ret = true;
+#endif
+#ifdef HAVE_MF_BT2
+ if (mf == LZMA_MF_BT2)
+ ret = true;
+#endif
-/// \brief Normalizes hash values
-///
-/// lzma_lz_normalize is called when lz->pos hits MAX_VAL_FOR_NORMALIZE,
-/// which currently happens once every 2 GiB of input data (to be exact,
-/// after the first 2 GiB it happens once every 2 GiB minus dictionary_size
-/// bytes). lz->pos is incremented by lzma_lz_move_pos().
-///
-/// lz->hash contains big amount of offsets relative to lz->buffer.
-/// The offsets are stored as uint32_t, which is the only reasonable
-/// datatype for these offsets; uint64_t would waste far too much RAM
-/// and uint16_t would limit the dictionary to 64 KiB (far too small).
-///
-/// When compressing files over 2 GiB, lz->buffer needs to be moved forward
-/// to avoid integer overflows. We scan the lz->hash array and fix every
-/// value to match the updated lz->buffer.
-extern void
-lzma_lz_encoder_normalize(lzma_lz_encoder *lz)
-{
- const uint32_t subvalue = lz->read_pos - lz->cyclic_buffer_size;
- assert(subvalue <= INT32_MAX);
-
- {
- const uint32_t num_items = lz->num_items;
- uint32_t *restrict items = lz->hash;
-
- for (uint32_t i = 0; i < num_items; ++i) {
- // If the distance is greater than the dictionary
- // size, we can simply mark the item as empty.
- if (items[i] <= subvalue)
- items[i] = EMPTY_HASH_VALUE;
- else
- items[i] -= subvalue;
- }
- }
+#ifdef HAVE_MF_BT3
+ if (mf == LZMA_MF_BT3)
+ ret = true;
+#endif
- // Update offset to match the new locations.
- lz->offset -= subvalue;
+#ifdef HAVE_MF_BT4
+ if (mf == LZMA_MF_BT4)
+ ret = true;
+#endif
- return;
+ return ret;
}
diff --git a/src/liblzma/lz/lz_encoder.h b/src/liblzma/lz/lz_encoder.h
index da0e0804..45bb8462 100644
--- a/src/liblzma/lz/lz_encoder.h
+++ b/src/liblzma/lz/lz_encoder.h
@@ -3,8 +3,8 @@
/// \file lz_encoder.h
/// \brief LZ in window and match finder API
//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
+// Copyright (C) 1999-2008 Igor Pavlov
+// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -24,19 +24,16 @@
#include "common.h"
-typedef struct lzma_lz_encoder_s lzma_lz_encoder;
-struct lzma_lz_encoder_s {
- enum {
- SEQ_RUN,
- SEQ_FLUSH,
- SEQ_FINISH,
- } sequence;
+/// A table of these is used by the LZ-based encoder to hold
+/// the length-distance pairs found by the match finder.
+typedef struct {
+ uint32_t len;
+ uint32_t dist;
+} lzma_match;
- /// Function to do the actual encoding from the sliding input window
- /// to the output stream.
- bool (*process)(lzma_coder *coder, uint8_t *restrict out,
- size_t *restrict out_pos, size_t out_size);
+typedef struct lzma_mf_s lzma_mf;
+struct lzma_mf_s {
///////////////
// In Window //
///////////////
@@ -46,17 +43,33 @@ struct lzma_lz_encoder_s {
/// Total size of the allocated buffer (that is, including all
/// the extra space)
- size_t size;
+ uint32_t size;
+
+ /// Number of bytes that must be kept available in our input history.
+ /// That is, once keep_size_before bytes have been processed,
+ /// buffer[read_pos - keep_size_before] is the oldest byte that
+ /// must be available for reading.
+ uint32_t keep_size_before;
+
+ /// Number of bytes that must be kept in buffer after read_pos.
+ /// That is, read_pos <= write_pos - keep_size_after as long as
+ /// stream_end_was_reached is false (once it is true, read_pos
+ /// is allowed to reach write_pos).
+ uint32_t keep_size_after;
/// Match finders store locations of matches using 32-bit integers.
/// To avoid adjusting several megabytes of integers every time the
/// input window is moved with move_window(), we only adjust the
/// offset of the buffer. Thus, buffer[match_finder_pos - offset]
/// is the byte pointed by match_finder_pos.
- size_t offset;
+ uint32_t offset;
/// buffer[read_pos] is the current byte.
- size_t read_pos;
+ uint32_t read_pos;
+
+ /// Number of bytes that have been ran through the match finder, but
+ /// which haven't been encoded by the LZ-based encoder yet.
+ uint32_t read_ahead;
/// As long as read_pos is less than read_limit, there is enough
/// input available in buffer for at least one encoding loop.
@@ -64,92 +77,253 @@ struct lzma_lz_encoder_s {
/// Because of the stateful API, read_limit may and will get greater
/// than read_pos quite often. This is taken into account when
/// calculating the value for keep_size_after.
- size_t read_limit;
+ uint32_t read_limit;
/// buffer[write_pos] is the first byte that doesn't contain valid
/// uncompressed data; that is, the next input byte will be copied
/// to buffer[write_pos].
- size_t write_pos;
+ uint32_t write_pos;
/// Number of bytes not hashed before read_pos. This is needed to
/// restart the match finder after LZMA_SYNC_FLUSH.
- size_t pending;
-
- /// Number of bytes that must be kept available in our input history.
- /// That is, once keep_size_before bytes have been processed,
- /// buffer[read_pos - keep_size_before] is the oldest byte that
- /// must be available for reading.
- size_t keep_size_before;
-
- /// Number of bytes that must be kept in buffer after read_pos.
- /// That is, read_pos <= write_pos - keep_size_after as long as
- /// stream_end_was_reached is false (once it is true, read_pos
- /// is allowed to reach write_pos).
- size_t keep_size_after;
+ uint32_t pending;
//////////////////
// Match Finder //
//////////////////
- // Pointers to match finder functions
- void (*get_matches)(lzma_lz_encoder *restrict lz,
- uint32_t *restrict distances);
- void (*skip)(lzma_lz_encoder *restrict lz, uint32_t num);
+ /// Find matches. Returns the number of distance-length pairs written
+ /// to the matches array. This is called only via lzma_mf_find.
+ uint32_t (*find)(lzma_mf *mf, lzma_match *matches);
+
+ /// Skips num bytes. This is like find() but doesn't make the
+ /// distance-length pairs available, thus being a little faster.
+ /// This is called only via mf_skip function.
+ void (*skip)(lzma_mf *mf, uint32_t num);
- // Match finder data
- uint32_t *hash; // TODO: Check if hash aliases son
- uint32_t *son; // and add 'restrict' if possible.
+ uint32_t *hash;
+ uint32_t *son;
uint32_t cyclic_buffer_pos;
uint32_t cyclic_buffer_size; // Must be dictionary_size + 1.
uint32_t hash_mask;
- uint32_t cut_value;
+
+ /// Maximum number of loops in the match finder
+ uint32_t loops;
+
+ /// Maximum length of a match that the match finder will try to find.
+ uint32_t find_len_max;
+
+ /// Maximum length of a match supported by the LZ-based encoder.
+ /// If the longest match found by the match finder is find_len_max,
+ /// lz_dict_find() tries to expand it up to match_len_max bytes.
+ uint32_t match_len_max;
+
+ /// When running out of input, binary tree match finders need to know
+ /// if it is due to flushing or finishing. The action is used also
+ /// by the LZ-based encoders themselves.
+ lzma_action action;
+
+ /// Number of elements in hash[]
uint32_t hash_size_sum;
- uint32_t num_items;
- uint32_t match_max_len;
+
+ /// Number of elements in son[]
+ uint32_t sons_count;
};
-#define LZMA_LZ_ENCODER_INIT \
- (lzma_lz_encoder){ \
- .buffer = NULL, \
- .size = 0, \
- .hash = NULL, \
- .num_items = 0, \
+typedef struct {
+ /// Extra amount of data to keep available before the "actual"
+ /// dictionary.
+ size_t before_size;
+
+ /// Size of the history buffer
+ size_t dictionary_size;
+
+ /// Extra amount of data to keep available after the "actual"
+ /// dictionary.
+ size_t after_size;
+
+ /// Maximum length of a match that the LZ-based encoder can accept.
+ /// This is used to extend matches of length find_len_max to the
+ /// maximum possible length.
+ size_t match_len_max;
+
+ /// Match finder will search matches of at maximum of this length.
+ /// This must be less than or equal to match_len_max.
+ size_t find_len_max;
+
+ /// Type of the match finder to use
+ lzma_match_finder match_finder;
+
+ /// TODO: Comment
+ uint32_t match_finder_cycles;
+
+ /// TODO: Comment
+ const uint8_t *preset_dictionary;
+
+ uint32_t preset_dictionary_size;
+
+} lzma_lz_options;
+
+
+// The total usable buffer space at any moment outside the match finder:
+// before_size + dictionary_size + after_size + match_len_max
+//
+// In reality, there's some extra space allocated to prevent the number of
+// memmove() calls reasonable. The bigger the dictionary_size is, the bigger
+// this extra buffer will be since with bigger dictionaries memmove() would
+// also take longer.
+//
+// A single encoder loop in the LZ-based encoder may call the match finder
+// (lz_dict_find() or lz_dict_skip()) at maximum of after_size times.
+// In other words, a single encoder loop may advance lz_dict.read_pos at
+// maximum of after_size times. Since matches are looked up to
+// lz_dict.buffer[lz_dict.read_pos + match_len_max - 1], the total
+// amount of extra buffer needed after dictionary_size becomes
+// after_size + match_len_max.
+//
+// before_size has two uses. The first one is to keep literals available
+// in cases when the LZ-based encoder has made some read ahead.
+// TODO: Maybe this could be changed by making the LZ-based encoders to
+// store the actual literals as they do with length-distance pairs.
+//
+// Alrogithms such as LZMA2 first try to compress a chunk, and then check
+// if the encoded result is smaller than the uncompressed one. If the chunk
+// was uncompressible, it is better to store it in uncompressed form in
+// the output stream. To do this, the whole uncompressed chunk has to be
+// still available in the history buffer. before_size achieves that.
+
+
+typedef struct {
+ /// Data specific to the LZ-based encoder
+ lzma_coder *coder;
+
+ /// Function to encode from *dict to out[]
+ lzma_ret (*code)(lzma_coder *restrict coder,
+ lzma_mf *restrict mf, uint8_t *restrict out,
+ size_t *restrict out_pos, size_t out_size);
+
+ /// Free allocated resources
+ void (*end)(lzma_coder *coder, lzma_allocator *allocator);
+
+} lzma_lz_encoder;
+
+
+// Basic steps:
+// 1. Input gets copied into the dictionary.
+// 2. Data in dictionary gets run through the match finder byte by byte.
+// 3. The literals and matches are encoded using e.g. LZMA.
+//
+// The bytes that have been ran through the match finder, but not encoded yet,
+// are called `read ahead'.
+
+
+/// Get pointer to the first byte not ran through the match finder
+static inline const uint8_t *
+mf_ptr(const lzma_mf *mf)
+{
+ return mf->buffer + mf->read_pos;
+}
+
+
+/// Get the number of bytes that haven't been ran through the match finder yet.
+static inline uint32_t
+mf_avail(const lzma_mf *mf)
+{
+ return mf->write_pos - mf->read_pos;
+}
+
+
+/// Get the number of bytes that haven't been encoded yet (some of these
+/// bytes may have been ran through the match finder though).
+static inline uint32_t
+mf_unencoded(const lzma_mf *mf)
+{
+ return mf->write_pos - mf->read_pos - mf->read_ahead;
+}
+
+
+/// Calculate the absolute offset from the beginning of the most recent
+/// dictionary reset. Only the lowest four bits are important, so there's no
+/// problem that we don't know the 64-bit size of the data encoded so far.
+///
+/// NOTE: When moving the input window, we need to do it so that the lowest
+/// bits of dict->read_pos are not modified to keep this macro working
+/// as intended.
+static inline uint32_t
+mf_position(const lzma_mf *mf)
+{
+ return mf->read_pos - mf->read_ahead;
+}
+
+
+/// Since everything else begins with mf_, use it also for lzma_mf_find().
+#define mf_find lzma_mf_find
+
+
+/// Skip the given number of bytes. This is used when a good match was found.
+/// For example, if mf_find() finds a match of 200 bytes long, the first byte
+/// of that match was already consumed by mf_find(), and the rest 199 bytes
+/// have to be skipped with mf_skip(mf, 199).
+static inline void
+mf_skip(lzma_mf *mf, uint32_t amount)
+{
+ if (amount != 0) {
+ mf->skip(mf, amount);
+ mf->read_ahead += amount;
}
+}
+
+
+/// Copies at maximum of *left amount of bytes from the history buffer
+/// to out[]. This is needed by LZMA2 to encode uncompressed chunks.
+static inline void
+mf_read(lzma_mf *mf, uint8_t *out, size_t *out_pos, size_t out_size,
+ size_t *left)
+{
+ const size_t out_avail = out_size - *out_pos;
+ const size_t copy_size = MIN(out_avail, *left);
+
+ assert(mf->read_ahead == 0);
+ assert(mf->read_pos >= *left);
+
+ memcpy(out + *out_pos, mf->buffer + mf->read_pos - *left,
+ copy_size);
+
+ *out_pos += copy_size;
+ *left -= copy_size;
+ return;
+}
+
+
+extern lzma_ret lzma_lz_encoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters,
+ lzma_ret (*lz_init)(lzma_lz_encoder *lz,
+ lzma_allocator *allocator, const void *options,
+ lzma_lz_options *lz_options));
+
+
+extern uint64_t lzma_lz_encoder_memusage(const lzma_lz_options *lz_options);
+
+
+// These are only for LZ encoder's internal use.
+extern uint32_t lzma_mf_find(
+ lzma_mf *mf, uint32_t *count, lzma_match *matches);
+
+extern uint32_t lzma_mf_hc3_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_hc3_skip(lzma_mf *dict, uint32_t amount);
+
+extern uint32_t lzma_mf_hc4_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_hc4_skip(lzma_mf *dict, uint32_t amount);
+
+extern uint32_t lzma_mf_bt2_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_bt2_skip(lzma_mf *dict, uint32_t amount);
+extern uint32_t lzma_mf_bt3_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_bt3_skip(lzma_mf *dict, uint32_t amount);
-/// Calculates
-extern bool lzma_lz_encoder_hash_properties(lzma_match_finder match_finder,
- uint32_t history_size, uint32_t *restrict hash_mask,
- uint32_t *restrict hash_size_sum,
- uint32_t *restrict num_items);
-
-// NOTE: liblzma doesn't use callback API like LZMA SDK does. The caller
-// must make sure that keep_size_after is big enough for single encoding pass
-// i.e. keep_size_after >= maximum number of bytes possibly needed after
-// the current position between calls to lzma_lz_read().
-extern lzma_ret lzma_lz_encoder_reset(lzma_lz_encoder *lz,
- lzma_allocator *allocator,
- bool (*process)(lzma_coder *coder, uint8_t *restrict out,
- size_t *restrict out_pos, size_t out_size),
- size_t history_size, size_t additional_buffer_before,
- size_t match_max_len, size_t additional_buffer_after,
- lzma_match_finder match_finder, uint32_t match_finder_cycles,
- const uint8_t *preset_dictionary,
- size_t preset_dictionary_size);
-
-/// Frees memory allocated for in window and match finder buffers.
-extern void lzma_lz_encoder_end(
- lzma_lz_encoder *lz, lzma_allocator *allocator);
-
-extern lzma_ret lzma_lz_encode(lzma_coder *coder,
- lzma_allocator *allocator lzma_attribute((unused)),
- const uint8_t *restrict in, size_t *restrict in_pos,
- size_t in_size, uint8_t *restrict out,
- size_t *restrict out_pos, size_t out_size,
- lzma_action action);
-
-/// This should not be called directly, but only via move_pos() macro.
-extern void lzma_lz_encoder_normalize(lzma_lz_encoder *lz);
+extern uint32_t lzma_mf_bt4_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_bt4_skip(lzma_mf *dict, uint32_t amount);
#endif
diff --git a/src/liblzma/lz/lz_encoder_hash.h b/src/liblzma/lz/lz_encoder_hash.h
new file mode 100644
index 00000000..0841c38f
--- /dev/null
+++ b/src/liblzma/lz/lz_encoder_hash.h
@@ -0,0 +1,104 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lz_encoder_hash.h
+/// \brief Hash macros for match finders
+//
+// Copyright (C) 1999-2008 Igor Pavlov
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZ_ENCODER_HASH_H
+#define LZMA_LZ_ENCODER_HASH_H
+
+#define HASH_2_SIZE (UINT32_C(1) << 10)
+#define HASH_3_SIZE (UINT32_C(1) << 16)
+#define HASH_4_SIZE (UINT32_C(1) << 20)
+
+#define HASH_2_MASK (HASH_2_SIZE - 1)
+#define HASH_3_MASK (HASH_3_SIZE - 1)
+#define HASH_4_MASK (HASH_4_SIZE - 1)
+
+#define FIX_3_HASH_SIZE (HASH_2_SIZE)
+#define FIX_4_HASH_SIZE (HASH_2_SIZE + HASH_3_SIZE)
+#define FIX_5_HASH_SIZE (HASH_2_SIZE + HASH_3_SIZE + HASH_4_SIZE)
+
+// TODO Benchmark, and probably doesn't need to be endian dependent.
+#if !defined(WORDS_BIGENDIAN) && defined(HAVE_FAST_UNALIGNED_ACCESS)
+# define hash_2_calc() \
+ const uint32_t hash_value = *(const uint16_t *)(cur);
+#else
+# define hash_2_calc() \
+ const uint32_t hash_value \
+ = (uint32_t)(cur[0]) | ((uint32_t)(cur[1]) << 8)
+#endif
+
+#define hash_3_calc() \
+ const uint32_t temp = lzma_crc32_table[0][cur[0]] ^ cur[1]; \
+ const uint32_t hash_2_value = temp & HASH_2_MASK; \
+ const uint32_t hash_value \
+ = (temp ^ ((uint32_t)(cur[2]) << 8)) & mf->hash_mask
+
+#define hash_4_calc() \
+ const uint32_t temp = lzma_crc32_table[0][cur[0]] ^ cur[1]; \
+ const uint32_t hash_2_value = temp & HASH_2_MASK; \
+ const uint32_t hash_3_value \
+ = (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
+ const uint32_t hash_value = (temp ^ ((uint32_t)(cur[2]) << 8) \
+ ^ (lzma_crc32_table[0][cur[3]] << 5)) & mf->hash_mask
+
+
+// The following are not currently used.
+
+#define hash_5_calc() \
+ const uint32_t temp = lzma_crc32_table[0][cur[0]] ^ cur[1]; \
+ const uint32_t hash_2_value = temp & HASH_2_MASK; \
+ const uint32_t hash_3_value \
+ = (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
+ uint32_t hash_4_value = (temp ^ ((uint32_t)(cur[2]) << 8) ^ \
+ ^ lzma_crc32_table[0][cur[3]] << 5); \
+ const uint32_t hash_value \
+ = (hash_4_value ^ (lzma_crc32_table[0][cur[4]] << 3)) \
+ & mf->hash_mask; \
+ hash_4_value &= HASH_4_MASK
+
+/*
+#define hash_zip_calc() \
+ const uint32_t hash_value \
+ = (((uint32_t)(cur[0]) | ((uint32_t)(cur[1]) << 8)) \
+ ^ lzma_crc32_table[0][cur[2]]) & 0xFFFF
+*/
+
+#define hash_zip_calc() \
+ const uint32_t hash_value \
+ = (((uint32_t)(cur[2]) | ((uint32_t)(cur[0]) << 8)) \
+ ^ lzma_crc32_table[0][cur[1]]) & 0xFFFF
+
+#define mt_hash_2_calc() \
+ const uint32_t hash_2_value \
+ = (lzma_crc32_table[0][cur[0]] ^ cur[1]) & HASH_2_MASK
+
+#define mt_hash_3_calc() \
+ const uint32_t temp = lzma_crc32_table[0][cur[0]] ^ cur[1]; \
+ const uint32_t hash_2_value = temp & HASH_2_MASK; \
+ const uint32_t hash_3_value \
+ = (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK
+
+#define mt_hash_4_calc() \
+ const uint32_t temp = lzma_crc32_table[0][cur[0]] ^ cur[1]; \
+ const uint32_t hash_2_value = temp & HASH_2_MASK; \
+ const uint32_t hash_3_value \
+ = (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
+ const uint32_t hash_4_value = (temp ^ ((uint32_t)(cur[2]) << 8) ^ \
+ (lzma_crc32_table[0][cur[3]] << 5)) & HASH_4_MASK
+
+#endif
diff --git a/src/liblzma/lz/lz_encoder_mf.c b/src/liblzma/lz/lz_encoder_mf.c
new file mode 100644
index 00000000..b1c20f50
--- /dev/null
+++ b/src/liblzma/lz/lz_encoder_mf.c
@@ -0,0 +1,780 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lz_encoder_mf.c
+/// \brief Match finders
+//
+// Copyright (C) 1999-2008 Igor Pavlov
+// Copyright (C) 2008 Lasse Collin
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lz_encoder.h"
+#include "lz_encoder_hash.h"
+#include "check.h"
+
+
+/// \brief Find matches starting from the current byte
+///
+/// \return The length of the longest match found
+extern uint32_t
+lzma_mf_find(lzma_mf *mf, uint32_t *count_ptr, lzma_match *matches)
+{
+ // Call the match finder. It returns the number of length-distance
+ // pairs found.
+ // FIXME: Minimum count is zero, what _exactly_ is the maximum?
+ const uint32_t count = mf->find(mf, matches);
+
+ // Length of the longest match; assume that no matches were found
+ // and thus the maximum length is zero.
+ uint32_t len_best = 0;
+
+ if (count > 0) {
+#ifndef NDEBUG
+ // Validate the matches.
+ for (uint32_t i = 0; i < count; ++i) {
+ assert(matches[i].len <= mf->find_len_max);
+ assert(matches[i].dist < mf->read_pos);
+ assert(memcmp(mf_ptr(mf) - 1,
+ mf_ptr(mf) - matches[i].dist - 2,
+ matches[i].len) == 0);
+ }
+#endif
+
+ // The last used element in the array contains
+ // the longest match.
+ len_best = matches[count - 1].len;
+
+ // If a match of maximum search length was found, try to
+ // extend the match to maximum possible length.
+ if (len_best == mf->find_len_max) {
+ // The limit for the match length is either the
+ // maximum match length supported by the LZ-based
+ // encoder or the number of bytes left in the
+ // dictionary, whichever is smaller.
+ uint32_t limit = mf_avail(mf) + 1;
+ if (limit > mf->match_len_max)
+ limit = mf->match_len_max;
+
+ // Pointer to the byte we just ran through
+ // the match finder.
+ const uint8_t *p1 = mf_ptr(mf) - 1;
+
+ // Pointer to the beginning of the match. We need -1
+ // here because the match distances are zero based.
+ const uint8_t *p2 = p1 - matches[count - 1].dist - 1;
+
+ while (len_best < limit
+ && p1[len_best] == p2[len_best])
+ ++len_best;
+ }
+ }
+
+ *count_ptr = count;
+
+ // Finally update the read position to indicate that match finder was
+ // run for this dictionary offset.
+ ++mf->read_ahead;
+
+ return len_best;
+}
+
+
+/// Hash value to indicate unused element in the hash. Since we start the
+/// positions from dictionary_size + 1, zero is always too far to qualify
+/// as usable match position.
+#define EMPTY_HASH_VALUE 0
+
+
+/// Normalization must be done when lzma_mf.offset + lzma_mf.read_pos
+/// reaches MUST_NORMALIZE_POS.
+#define MUST_NORMALIZE_POS UINT32_MAX
+
+
+/// \brief Normalizes hash values
+///
+/// The hash arrays store positions of match candidates. The positions are
+/// relative to an arbitrary offset that is not the same as the absolute
+/// offset in the input stream. The relative position of the current byte
+/// is lzma_mf.offset + lzma_mf.read_pos. The distances of the matches are
+/// the differences of the current read position and the position found from
+/// the hash.
+///
+/// To prevent integer overflows of the offsets stored in the hash arrays,
+/// we need to "normalize" the stored values now and then. During the
+/// normalization, we drop values that indicate distance greater than the
+/// dictionary size, thus making space for new values.
+static void
+normalize(lzma_mf *mf)
+{
+ assert(mf->read_pos + mf->offset == MUST_NORMALIZE_POS);
+
+ // In future we may not want to touch the lowest bits, because there
+ // may be match finders that use larger resolution than one byte.
+ const uint32_t subvalue
+ = (MUST_NORMALIZE_POS - mf->cyclic_buffer_size);
+ // & (~(UINT32_C(1) << 10) - 1);
+
+ const uint32_t count = mf->hash_size_sum + mf->sons_count;
+ uint32_t *hash = mf->hash;
+
+ for (uint32_t i = 0; i < count; ++i) {
+ // If the distance is greater than the dictionary size,
+ // we can simply mark the hash element as empty.
+ //
+ // NOTE: Only the first mf->hash_size_sum elements are
+ // initialized for sure. There may be uninitialized elements
+ // in mf->son. Since we go through both mf->hash and
+ // mf->son here in normalization, Valgrind may complain
+ // that the "if" below depends on uninitialized value. In
+ // this case it is safe to ignore the warning. See also the
+ // comments in lz_encoder_init() in lz_encoder.c.
+ if (hash[i] <= subvalue)
+ hash[i] = EMPTY_HASH_VALUE;
+ else
+ hash[i] -= subvalue;
+ }
+
+ // Update offset to match the new locations.
+ mf->offset -= subvalue;
+
+ return;
+}
+
+
+/// Mark the current byte as processed from point of view of the match finder.
+static void
+move_pos(lzma_mf *mf)
+{
+ if (++mf->cyclic_buffer_pos == mf->cyclic_buffer_size)
+ mf->cyclic_buffer_pos = 0;
+
+ ++mf->read_pos;
+ assert(mf->read_pos <= mf->write_pos);
+
+ if (unlikely(mf->read_pos + mf->offset == UINT32_MAX))
+ normalize(mf);
+}
+
+
+/// When flushing, we cannot run the match finder unless there is find_len_max
+/// bytes available in the dictionary. Instead, we skip running the match
+/// finder (indicating that no match was found), and count how many bytes we
+/// have ignored this way.
+///
+/// When new data is given after the flushing was completed, the match finder
+/// is restarted by rewinding mf->read_pos backwards by mf->pending. Then
+/// the missed bytes are added to the hash using the match finder's skip
+/// function (with small amount of input, it may start using mf->pending
+/// again if flushing).
+///
+/// Due to this rewinding, we don't touch cyclic_buffer_pos or test for
+/// normalization. It will be done when the match finder's skip function
+/// catches up after a flush.
+static void
+move_pending(lzma_mf *mf)
+{
+ ++mf->read_pos;
+ assert(mf->read_pos <= mf->write_pos);
+ ++mf->pending;
+}
+
+
+/// Calculate len_limit and determine if there is enough input to run
+/// the actual match finder code. Sets up "cur" and "pos". This macro
+/// is used by all find functions and binary tree skip functions. Hash
+/// chain skip function doesn't need len_limit so a simpler code is used
+/// in them.
+#define header(is_bt, len_min, ret_op) \
+ uint32_t len_limit = mf_avail(mf); \
+ if (mf->find_len_max <= len_limit) { \
+ len_limit = mf->find_len_max; \
+ } else if (len_limit < (len_min) \
+ || (is_bt && mf->action == LZMA_SYNC_FLUSH)) { \
+ assert(mf->action != LZMA_RUN); \
+ move_pending(mf); \
+ ret_op; \
+ } \
+ const uint8_t *cur = mf_ptr(mf); \
+ const uint32_t pos = mf->read_pos + mf->offset
+
+
+/// Header for find functions. "return 0" indicates that zero matches
+/// were found.
+#define header_find(is_bt, len_min) \
+ header(is_bt, len_min, return 0); \
+ uint32_t matches_count = 0
+
+
+/// Header for a loop in a skip function. "continue" tells to skip the rest
+/// of the code in the loop.
+#define header_skip(is_bt, len_min) \
+ header(is_bt, len_min, continue)
+
+
+/// Calls hc_find_func() or bt_find_func() and calculates the total number
+/// of matches found. Updates the dictionary position and returns the number
+/// of matches found.
+#define call_find(func, len_best) \
+do { \
+ matches_count = func(len_limit, pos, cur, cur_match, mf->loops, \
+ mf->son, mf->cyclic_buffer_pos, \
+ mf->cyclic_buffer_size, \
+ matches + matches_count, len_best) \
+ - matches; \
+ move_pos(mf); \
+ return matches_count; \
+} while (0)
+
+
+////////////////
+// Hash Chain //
+////////////////
+
+#if defined(HAVE_MF_HC3) || defined(HAVE_MF_HC4)
+///
+///
+/// \param len_limit Don't look for matches longer than len_limit.
+/// \param pos lzma_mf.read_pos + lzma_mf.offset
+/// \param cur Pointer to current byte (lzma_dict_ptr(mf))
+/// \param cur_match Start position of the current match candidate
+/// \param loops Maximum length of the hash chain
+/// \param son lzma_mf.son (contains the hash chain)
+/// \param cyclic_buffer_pos
+/// \param cyclic_buffer_size
+/// \param matches Array to hold the matches.
+/// \param len_best The length of the longest match found so far.
+static lzma_match *
+hc_find_func(
+ const uint32_t len_limit,
+ const uint32_t pos,
+ const uint8_t *const cur,
+ uint32_t cur_match,
+ uint32_t loops,
+ uint32_t *const son,
+ const uint32_t cyclic_buffer_pos,
+ const uint32_t cyclic_buffer_size,
+ lzma_match *matches,
+ uint32_t len_best)
+{
+ son[cyclic_buffer_pos] = cur_match;
+
+ while (true) {
+ const uint32_t delta = pos - cur_match;
+ if (loops-- == 0 || delta >= cyclic_buffer_size)
+ return matches;
+
+ const uint8_t *const pb = cur - delta;
+ cur_match = son[cyclic_buffer_pos - delta
+ + (delta > cyclic_buffer_pos
+ ? cyclic_buffer_size : 0)];
+
+ if (pb[len_best] == cur[len_best] && pb[0] == cur[0]) {
+ uint32_t len = 0;
+ while (++len != len_limit)
+ if (pb[len] != cur[len])
+ break;
+
+ if (len_best < len) {
+ len_best = len;
+ matches->len = len;
+ matches->dist = delta - 1;
+ ++matches;
+
+ if (len == len_limit)
+ return matches;
+ }
+ }
+ }
+}
+
+/*
+#define hc_header_find(len_min, ret_op) \
+ uint32_t len_limit = mf_avail(mf); \
+ if (mf->find_len_max <= len_limit) { \
+ len_limit = mf->find_len_max; \
+ } else if (len_limit < (len_min)) { \
+ move_pending(mf); \
+ ret_op; \
+ } \
+#define header_hc(len_min, ret_op) \
+do { \
+ if (mf_avail(mf) < (len_min)) { \
+ move_pending(mf); \
+ ret_op; \
+ } \
+} while (0)
+*/
+
+#define hc_find(len_best) \
+ call_find(hc_find_func, len_best)
+
+
+#define hc_skip() \
+do { \
+ mf->son[mf->cyclic_buffer_pos] = cur_match; \
+ move_pos(mf); \
+} while (0)
+
+#endif
+
+
+#ifdef HAVE_MF_HC3
+extern uint32_t
+lzma_mf_hc3_find(lzma_mf *mf, lzma_match *matches)
+{
+ header_find(false, 3);
+
+ hash_3_calc();
+
+ const uint32_t delta2 = pos - mf->hash[hash_2_value];
+ const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+ uint32_t len_best = 2;
+
+ if (delta2 < mf->cyclic_buffer_size && *(cur - delta2) == *cur) {
+ for ( ; len_best != len_limit; ++len_best)
+ if (*(cur + len_best - delta2) != cur[len_best])
+ break;
+
+ matches[0].len = len_best;
+ matches[0].dist = delta2 - 1;
+ matches_count = 1;
+
+ if (len_best == len_limit) {
+ hc_skip();
+ return 1; // matches_count
+ }
+ }
+
+ hc_find(len_best);
+}
+
+
+extern void
+lzma_mf_hc3_skip(lzma_mf *mf, uint32_t amount)
+{
+ do {
+ if (mf_avail(mf) < 3) {
+ move_pending(mf);
+ continue;
+ }
+
+ const uint8_t *cur = mf_ptr(mf);
+ const uint32_t pos = mf->read_pos + mf->offset;
+
+ hash_3_calc();
+
+ const uint32_t cur_match
+ = mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+ hc_skip();
+
+ } while (--amount != 0);
+}
+#endif
+
+
+#ifdef HAVE_MF_HC4
+extern uint32_t
+lzma_mf_hc4_find(lzma_mf *mf, lzma_match *matches)
+{
+ header_find(false, 4);
+
+ hash_4_calc();
+
+ uint32_t delta2 = pos - mf->hash[hash_2_value];
+ const uint32_t delta3
+ = pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
+ const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value ] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+ mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+ uint32_t len_best = 1;
+
+ if (delta2 < mf->cyclic_buffer_size && *(cur - delta2) == *cur) {
+ len_best = 2;
+ matches[0].len = 2;
+ matches[0].dist = delta2 - 1;
+ matches_count = 1;
+ }
+
+ if (delta2 != delta3 && delta3 < mf->cyclic_buffer_size
+ && *(cur - delta3) == *cur) {
+ len_best = 3;
+ matches[matches_count++].dist = delta3 - 1;
+ delta2 = delta3;
+ }
+
+ if (matches_count != 0) {
+ for ( ; len_best != len_limit; ++len_best)
+ if (*(cur + len_best - delta2) != cur[len_best])
+ break;
+
+ matches[matches_count - 1].len = len_best;
+
+ if (len_best == len_limit) {
+ hc_skip();
+ return matches_count;
+ }
+ }
+
+ if (len_best < 3)
+ len_best = 3;
+
+ hc_find(len_best);
+}
+
+
+extern void
+lzma_mf_hc4_skip(lzma_mf *mf, uint32_t amount)
+{
+ do {
+ if (mf_avail(mf) < 4) {
+ move_pending(mf);
+ continue;
+ }
+
+ const uint8_t *cur = mf_ptr(mf);
+ const uint32_t pos = mf->read_pos + mf->offset;
+
+ hash_4_calc();
+
+ const uint32_t cur_match
+ = mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+ mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+ hc_skip();
+
+ } while (--amount != 0);
+}
+#endif
+
+
+/////////////////
+// Binary Tree //
+/////////////////
+
+#if defined(HAVE_MF_BT2) || defined(HAVE_MF_BT3) || defined(HAVE_MF_BT4)
+static lzma_match *
+bt_find_func(
+ const uint32_t len_limit,
+ const uint32_t pos,
+ const uint8_t *const cur,
+ uint32_t cur_match,
+ uint32_t loops,
+ uint32_t *const son,
+ const uint32_t cyclic_buffer_pos,
+ const uint32_t cyclic_buffer_size,
+ lzma_match *matches,
+ uint32_t len_best)
+{
+ uint32_t *ptr0 = son + (cyclic_buffer_pos << 1) + 1;
+ uint32_t *ptr1 = son + (cyclic_buffer_pos << 1);
+
+ uint32_t len0 = 0;
+ uint32_t len1 = 0;
+
+ while (true) {
+ const uint32_t delta = pos - cur_match;
+ if (loops-- == 0 || delta >= cyclic_buffer_size) {
+ *ptr0 = EMPTY_HASH_VALUE;
+ *ptr1 = EMPTY_HASH_VALUE;
+ return matches;
+ }
+
+ uint32_t *const pair = son + ((cyclic_buffer_pos - delta
+ + (delta > cyclic_buffer_pos
+ ? cyclic_buffer_size : 0)) << 1);
+
+ const uint8_t *const pb = cur - delta;
+ uint32_t len = MIN(len0, len1);
+
+ if (pb[len] == cur[len]) {
+ while (++len != len_limit)
+ if (pb[len] != cur[len])
+ break;
+
+ if (len_best < len) {
+ len_best = len;
+ matches->len = len;
+ matches->dist = delta - 1;
+ ++matches;
+
+ if (len == len_limit) {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return matches;
+ }
+ }
+ }
+
+ if (pb[len] < cur[len]) {
+ *ptr1 = cur_match;
+ ptr1 = pair + 1;
+ cur_match = *ptr1;
+ len1 = len;
+ } else {
+ *ptr0 = cur_match;
+ ptr0 = pair;
+ cur_match = *ptr0;
+ len0 = len;
+ }
+ }
+}
+
+
+static void
+bt_skip_func(
+ const uint32_t len_limit,
+ const uint32_t pos,
+ const uint8_t *const cur,
+ uint32_t cur_match,
+ uint32_t loops,
+ uint32_t *const son,
+ const uint32_t cyclic_buffer_pos,
+ const uint32_t cyclic_buffer_size)
+{
+ uint32_t *ptr0 = son + (cyclic_buffer_pos << 1) + 1;
+ uint32_t *ptr1 = son + (cyclic_buffer_pos << 1);
+
+ uint32_t len0 = 0;
+ uint32_t len1 = 0;
+
+ while (true) {
+ const uint32_t delta = pos - cur_match;
+ if (loops-- == 0 || delta >= cyclic_buffer_size) {
+ *ptr0 = EMPTY_HASH_VALUE;
+ *ptr1 = EMPTY_HASH_VALUE;
+ return;
+ }
+
+ uint32_t *pair = son + ((cyclic_buffer_pos - delta
+ + (delta > cyclic_buffer_pos
+ ? cyclic_buffer_size : 0)) << 1);
+ const uint8_t *pb = cur - delta;
+ uint32_t len = MIN(len0, len1);
+
+ if (pb[len] == cur[len]) {
+ while (++len != len_limit)
+ if (pb[len] != cur[len])
+ break;
+
+ if (len == len_limit) {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return;
+ }
+ }
+
+ if (pb[len] < cur[len]) {
+ *ptr1 = cur_match;
+ ptr1 = pair + 1;
+ cur_match = *ptr1;
+ len1 = len;
+ } else {
+ *ptr0 = cur_match;
+ ptr0 = pair;
+ cur_match = *ptr0;
+ len0 = len;
+ }
+ }
+}
+
+
+#define bt_find(len_best) \
+ call_find(bt_find_func, len_best)
+
+#define bt_skip() \
+do { \
+ bt_skip_func(len_limit, pos, cur, cur_match, mf->loops, \
+ mf->son, mf->cyclic_buffer_pos, \
+ mf->cyclic_buffer_size); \
+ move_pos(mf); \
+} while (0)
+
+#endif
+
+
+#ifdef HAVE_MF_BT2
+extern uint32_t
+lzma_mf_bt2_find(lzma_mf *mf, lzma_match *matches)
+{
+ header_find(true, 2);
+
+ hash_2_calc();
+
+ const uint32_t cur_match = mf->hash[hash_value];
+ mf->hash[hash_value] = pos;
+
+ bt_find(1);
+}
+
+
+extern void
+lzma_mf_bt2_skip(lzma_mf *mf, uint32_t amount)
+{
+ do {
+ header_skip(true, 2);
+
+ hash_2_calc();
+
+ const uint32_t cur_match = mf->hash[hash_value];
+ mf->hash[hash_value] = pos;
+
+ bt_skip();
+
+ } while (--amount != 0);
+}
+#endif
+
+
+#ifdef HAVE_MF_BT3
+extern uint32_t
+lzma_mf_bt3_find(lzma_mf *mf, lzma_match *matches)
+{
+ header_find(true, 3);
+
+ hash_3_calc();
+
+ const uint32_t delta2 = pos - mf->hash[hash_2_value];
+ const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+ uint32_t len_best = 2;
+
+ if (delta2 < mf->cyclic_buffer_size && *(cur - delta2) == *cur) {
+ for ( ; len_best != len_limit; ++len_best)
+ if (*(cur + len_best - delta2) != cur[len_best])
+ break;
+
+ matches[0].len = len_best;
+ matches[0].dist = delta2 - 1;
+ matches_count = 1;
+
+ if (len_best == len_limit) {
+ bt_skip();
+ return 1; // matches_count
+ }
+ }
+
+ bt_find(len_best);
+}
+
+
+extern void
+lzma_mf_bt3_skip(lzma_mf *mf, uint32_t amount)
+{
+ do {
+ header_skip(true, 3);
+
+ hash_3_calc();
+
+ const uint32_t cur_match
+ = mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+ bt_skip();
+
+ } while (--amount != 0);
+}
+#endif
+
+
+#ifdef HAVE_MF_BT4
+extern uint32_t
+lzma_mf_bt4_find(lzma_mf *mf, lzma_match *matches)
+{
+ header_find(true, 4);
+
+ hash_4_calc();
+
+ uint32_t delta2 = pos - mf->hash[hash_2_value];
+ const uint32_t delta3
+ = pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
+ const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+ mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+ uint32_t len_best = 1;
+
+ if (delta2 < mf->cyclic_buffer_size && *(cur - delta2) == *cur) {
+ len_best = 2;
+ matches[0].len = 2;
+ matches[0].dist = delta2 - 1;
+ matches_count = 1;
+ }
+
+ if (delta2 != delta3 && delta3 < mf->cyclic_buffer_size
+ && *(cur - delta3) == *cur) {
+ len_best = 3;
+ matches[matches_count++].dist = delta3 - 1;
+ delta2 = delta3;
+ }
+
+ if (matches_count != 0) {
+ for ( ; len_best != len_limit; ++len_best)
+ if (*(cur + len_best - delta2) != cur[len_best])
+ break;
+
+ matches[matches_count - 1].len = len_best;
+
+ if (len_best == len_limit) {
+ bt_skip();
+ return matches_count;
+ }
+ }
+
+ if (len_best < 3)
+ len_best = 3;
+
+ bt_find(len_best);
+}
+
+
+extern void
+lzma_mf_bt4_skip(lzma_mf *mf, uint32_t amount)
+{
+ do {
+ header_skip(true, 4);
+
+ hash_4_calc();
+
+ const uint32_t cur_match
+ = mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+ mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+ bt_skip();
+
+ } while (--amount != 0);
+}
+#endif
diff --git a/src/liblzma/lz/match_c.h b/src/liblzma/lz/match_c.h
deleted file mode 100644
index 664db290..00000000
--- a/src/liblzma/lz/match_c.h
+++ /dev/null
@@ -1,412 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file match_c.h
-/// \brief Template for different match finders
-///
-/// This file is included by hc3.c, hc4, bt2.c, bt3.c and bt4.c. Each file
-/// sets slighly different #defines, resulting the different match finders.
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-//////////////
-// Includes //
-//////////////
-
-#include "check.h"
-
-
-///////////////
-// Constants //
-///////////////
-
-#define START_MAX_LEN 1
-
-#ifdef HASH_ARRAY_2
-# define NUM_HASH_DIRECT_BYTES 0
-# define HASH_2_SIZE (1 << 10)
-# ifdef HASH_ARRAY_3
-# define NUM_HASH_BYTES 4
-# define HASH_3_SIZE (1 << 16)
-# define HASH_3_OFFSET HASH_2_SIZE
-# define FIX_HASH_SIZE (HASH_2_SIZE + HASH_3_SIZE)
-# else
-# define NUM_HASH_BYTES 3
-# define FIX_HASH_SIZE HASH_2_SIZE
-# endif
-# define HASH_SIZE 0
-# define MIN_MATCH_CHECK NUM_HASH_BYTES
-#else
-# define NUM_HASH_DIRECT_BYTES 2
-# define NUM_HASH_BYTES 2
-# define HASH_SIZE (1 << (8 * NUM_HASH_BYTES))
-# define MIN_MATCH_CHECK (NUM_HASH_BYTES + 1)
-# define FIX_HASH_SIZE 0
-#endif
-
-
-////////////
-// Macros //
-////////////
-
-#ifdef HASH_ARRAY_2
-# ifdef HASH_ARRAY_3
-# define HASH_CALC() \
- do { \
- const uint32_t temp = lzma_crc32_table[0][ \
- cur[0]] ^ cur[1]; \
- hash_2_value = temp & (HASH_2_SIZE - 1); \
- hash_3_value = (temp ^ ((uint32_t)(cur[2]) << 8)) \
- & (HASH_3_SIZE - 1); \
- hash_value = (temp ^ ((uint32_t)(cur[2]) << 8) \
- ^ (lzma_crc32_table[0][cur[3]] << 5)) \
- & lz->hash_mask; \
- } while (0)
-# else
-# define HASH_CALC() \
- do { \
- const uint32_t temp = lzma_crc32_table[0][ \
- cur[0]] ^ cur[1]; \
- hash_2_value = temp & (HASH_2_SIZE - 1); \
- hash_value = (temp ^ ((uint32_t)(cur[2]) << 8)) \
- & lz->hash_mask; \
- } while (0)
-# endif
-#else
-# define HASH_CALC() hash_value = cur[0] ^ ((uint32_t)(cur[1]) << 8)
-#endif
-
-
-// Moves the current read position forward by one byte. In LZMA SDK,
-// CLZInWindow::MovePos() can read more input data if needed, because of
-// the callback style API. In liblzma we must have ensured earlier, that
-// there is enough data available in lz->buffer.
-#define move_pos() \
-do { \
- if (++lz->cyclic_buffer_pos == lz->cyclic_buffer_size) \
- lz->cyclic_buffer_pos = 0; \
- ++lz->read_pos; \
- assert(lz->read_pos <= lz->write_pos); \
- if (lz->read_pos == MAX_VAL_FOR_NORMALIZE) \
- lzma_lz_encoder_normalize(lz); \
-} while (0)
-
-
-#define move_pending() \
-do { \
- ++lz->read_pos; \
- assert(lz->read_pos <= lz->write_pos); \
- ++lz->pending; \
-} while (0)
-
-
-//////////////////////
-// Global constants //
-//////////////////////
-
-LZMA_HASH_SIZE(LZMA_MATCH_FINDER_NAME_UPPER) = HASH_SIZE;
-LZMA_FIX_HASH_SIZE(LZMA_MATCH_FINDER_NAME_UPPER) = FIX_HASH_SIZE;
-
-
-///////////////////
-// API functions //
-///////////////////
-
-LZMA_GET_MATCHES(LZMA_MATCH_FINDER_NAME_LOWER)
-{
- uint32_t len_limit;
- if (lz->read_pos + lz->match_max_len <= lz->write_pos) {
- len_limit = lz->match_max_len;
- } else {
- len_limit = lz->write_pos - lz->read_pos;
- if (len_limit < MIN_MATCH_CHECK || lz->sequence == SEQ_FLUSH) {
- distances[0] = 0;
- move_pending();
- return;
- }
- }
-
- assert(lz->pending == 0);
-
- int32_t offset = 1;
- const uint32_t match_min_pos
- = lz->read_pos + lz->offset > lz->cyclic_buffer_size
- ? lz->read_pos + lz->offset - lz->cyclic_buffer_size
- : 0;
- const uint8_t *cur = lz->buffer + lz->read_pos;
- uint32_t max_len = START_MAX_LEN; // to avoid items for len < hash_size
-
-#ifdef HASH_ARRAY_2
- uint32_t hash_2_value;
-# ifdef HASH_ARRAY_3
- uint32_t hash_3_value;
-# endif
-#endif
- uint32_t hash_value;
- HASH_CALC();
-
- uint32_t cur_match = lz->hash[FIX_HASH_SIZE + hash_value];
-#ifdef HASH_ARRAY_2
- uint32_t cur_match2 = lz->hash[hash_2_value];
-# ifdef HASH_ARRAY_3
- uint32_t cur_match3 = lz->hash[HASH_3_OFFSET + hash_3_value];
-# endif
- lz->hash[hash_2_value] = lz->read_pos + lz->offset;
-
- if (cur_match2 > match_min_pos) {
- if (lz->buffer[cur_match2 - lz->offset] == cur[0]) {
- max_len = 2;
- distances[offset++] = 2;
- distances[offset++] = lz->read_pos + lz->offset
- - cur_match2 - 1;
- }
- }
-
-# ifdef HASH_ARRAY_3
- lz->hash[HASH_3_OFFSET + hash_3_value] = lz->read_pos + lz->offset;
- if (cur_match3 > match_min_pos) {
- if (lz->buffer[cur_match3 - lz->offset] == cur[0]) {
- if (cur_match3 == cur_match2)
- offset -= 2;
-
- max_len = 3;
- distances[offset++] = 3;
- distances[offset++] = lz->read_pos + lz->offset
- - cur_match3 - 1;
- cur_match2 = cur_match3;
- }
- }
-# endif
-
- if (offset != 1 && cur_match2 == cur_match) {
- offset -= 2;
- max_len = START_MAX_LEN;
- }
-#endif
-
- lz->hash[FIX_HASH_SIZE + hash_value] = lz->read_pos + lz->offset;
-
-#ifdef IS_HASH_CHAIN
- lz->son[lz->cyclic_buffer_pos] = cur_match;
-#else
- uint32_t *ptr0 = lz->son + (lz->cyclic_buffer_pos << 1) + 1;
- uint32_t *ptr1 = lz->son + (lz->cyclic_buffer_pos << 1);
-
- uint32_t len0 = NUM_HASH_DIRECT_BYTES;
- uint32_t len1 = NUM_HASH_DIRECT_BYTES;
-#endif
-
-#if NUM_HASH_DIRECT_BYTES != 0
- if (cur_match > match_min_pos) {
- if (lz->buffer[cur_match + NUM_HASH_DIRECT_BYTES - lz->offset]
- != cur[NUM_HASH_DIRECT_BYTES]) {
- max_len = NUM_HASH_DIRECT_BYTES;
- distances[offset++] = NUM_HASH_DIRECT_BYTES;
- distances[offset++] = lz->read_pos + lz->offset
- - cur_match - 1;
- }
- }
-#endif
-
- uint32_t count = lz->cut_value;
-
- while (true) {
- if (cur_match <= match_min_pos || count-- == 0) {
-#ifndef IS_HASH_CHAIN
- *ptr0 = EMPTY_HASH_VALUE;
- *ptr1 = EMPTY_HASH_VALUE;
-#endif
- break;
- }
-
- const uint32_t delta = lz->read_pos + lz->offset - cur_match;
- const uint32_t cyclic_pos = delta <= lz->cyclic_buffer_pos
- ? lz->cyclic_buffer_pos - delta
- : lz->cyclic_buffer_pos - delta
- + lz->cyclic_buffer_size;
- uint32_t *pair = lz->son +
-#ifdef IS_HASH_CHAIN
- cyclic_pos;
-#else
- (cyclic_pos << 1);
-#endif
-
- const uint8_t *pb = lz->buffer + cur_match - lz->offset;
- uint32_t len =
-#ifdef IS_HASH_CHAIN
- NUM_HASH_DIRECT_BYTES;
- if (pb[max_len] == cur[max_len])
-#else
- MIN(len0, len1);
-#endif
-
- if (pb[len] == cur[len]) {
- while (++len != len_limit)
- if (pb[len] != cur[len])
- break;
-
- if (max_len < len) {
- max_len = len;
- distances[offset++] = len;
- distances[offset++] = delta - 1;
- if (len == len_limit) {
-#ifndef IS_HASH_CHAIN
- *ptr1 = pair[0];
- *ptr0 = pair[1];
-#endif
- break;
- }
- }
- }
-
-#ifdef IS_HASH_CHAIN
- cur_match = *pair;
-#else
- if (pb[len] < cur[len]) {
- *ptr1 = cur_match;
- ptr1 = pair + 1;
- cur_match = *ptr1;
- len1 = len;
- } else {
- *ptr0 = cur_match;
- ptr0 = pair;
- cur_match = *ptr0;
- len0 = len;
- }
-#endif
- }
-
- distances[0] = offset - 1;
-
- move_pos();
-
- return;
-}
-
-
-LZMA_SKIP(LZMA_MATCH_FINDER_NAME_LOWER)
-{
- do {
-#ifdef IS_HASH_CHAIN
- if (lz->write_pos - lz->read_pos < NUM_HASH_BYTES) {
- move_pending();
- continue;
- }
-#else
- uint32_t len_limit;
- if (lz->read_pos + lz->match_max_len <= lz->write_pos) {
- len_limit = lz->match_max_len;
- } else {
- len_limit = lz->write_pos - lz->read_pos;
- if (len_limit < MIN_MATCH_CHECK
- || lz->sequence == SEQ_FLUSH) {
- move_pending();
- continue;
- }
- }
- const uint32_t match_min_pos
- = lz->read_pos + lz->offset > lz->cyclic_buffer_size
- ? lz->read_pos + lz->offset - lz->cyclic_buffer_size
- : 0;
-#endif
-
- assert(lz->pending == 0);
-
- const uint8_t *cur = lz->buffer + lz->read_pos;
-
-#ifdef HASH_ARRAY_2
- uint32_t hash_2_value;
-# ifdef HASH_ARRAY_3
- uint32_t hash_3_value;
- uint32_t hash_value;
- HASH_CALC();
- lz->hash[HASH_3_OFFSET + hash_3_value]
- = lz->read_pos + lz->offset;
-# else
- uint32_t hash_value;
- HASH_CALC();
-# endif
- lz->hash[hash_2_value] = lz->read_pos + lz->offset;
-#else
- uint32_t hash_value;
- HASH_CALC();
-#endif
-
- uint32_t cur_match = lz->hash[FIX_HASH_SIZE + hash_value];
- lz->hash[FIX_HASH_SIZE + hash_value]
- = lz->read_pos + lz->offset;
-
-#ifdef IS_HASH_CHAIN
- lz->son[lz->cyclic_buffer_pos] = cur_match;
-#else
- uint32_t *ptr0 = lz->son + (lz->cyclic_buffer_pos << 1) + 1;
- uint32_t *ptr1 = lz->son + (lz->cyclic_buffer_pos << 1);
-
- uint32_t len0 = NUM_HASH_DIRECT_BYTES;
- uint32_t len1 = NUM_HASH_DIRECT_BYTES;
- uint32_t count = lz->cut_value;
-
- while (true) {
- if (cur_match <= match_min_pos || count-- == 0) {
- *ptr0 = EMPTY_HASH_VALUE;
- *ptr1 = EMPTY_HASH_VALUE;
- break;
- }
-
- const uint32_t delta = lz->read_pos
- + lz->offset - cur_match;
- const uint32_t cyclic_pos
- = delta <= lz->cyclic_buffer_pos
- ? lz->cyclic_buffer_pos - delta
- : lz->cyclic_buffer_pos - delta
- + lz->cyclic_buffer_size;
- uint32_t *pair = lz->son + (cyclic_pos << 1);
-
- const uint8_t *pb = lz->buffer + cur_match
- - lz->offset;
- uint32_t len = MIN(len0, len1);
-
- if (pb[len] == cur[len]) {
- while (++len != len_limit)
- if (pb[len] != cur[len])
- break;
-
- if (len == len_limit) {
- *ptr1 = pair[0];
- *ptr0 = pair[1];
- break;
- }
- }
-
- if (pb[len] < cur[len]) {
- *ptr1 = cur_match;
- ptr1 = pair + 1;
- cur_match = *ptr1;
- len1 = len;
- } else {
- *ptr0 = cur_match;
- ptr0 = pair;
- cur_match = *ptr0;
- len0 = len;
- }
- }
-#endif
-
- move_pos();
-
- } while (--num != 0);
-
- return;
-}
diff --git a/src/liblzma/lz/match_h.h b/src/liblzma/lz/match_h.h
deleted file mode 100644
index 2eae90ba..00000000
--- a/src/liblzma/lz/match_h.h
+++ /dev/null
@@ -1,69 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file match_h.h
-/// \brief Header template for different match finders
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#include "lz_encoder_private.h"
-
-
-//////////////////////
-// Global constants //
-//////////////////////
-
-#undef LZMA_HASH_SIZE
-#undef LZMA_FIX_HASH_SIZE
-#undef LZMA_HASH_SIZE_C
-#undef LZMA_FIX_HASH_SIZE_C
-
-#define LZMA_HASH_SIZE(mf_name) LZMA_HASH_SIZE_C(mf_name)
-#define LZMA_FIX_HASH_SIZE(mf_name) LZMA_FIX_HASH_SIZE_C(mf_name)
-
-#define LZMA_HASH_SIZE_C(mf_name) \
- const uint32_t LZMA_ ## mf_name ## _HASH_SIZE
-
-#define LZMA_FIX_HASH_SIZE_C(mf_name) \
- const uint32_t LZMA_ ## mf_name ## _FIX_HASH_SIZE
-
-extern LZMA_HASH_SIZE(LZMA_MATCH_FINDER_NAME_UPPER);
-extern LZMA_FIX_HASH_SIZE(LZMA_MATCH_FINDER_NAME_UPPER);
-
-
-///////////////
-// Functions //
-///////////////
-
-#undef LZMA_GET_MATCHES
-#undef LZMA_SKIP
-#undef LZMA_GET_MATCHES_C
-#undef LZMA_SKIP_C
-
-#define LZMA_GET_MATCHES(mf_name) LZMA_GET_MATCHES_C(mf_name)
-#define LZMA_SKIP(mf_name) LZMA_SKIP_C(mf_name)
-
-#define LZMA_GET_MATCHES_C(mf_name) \
- extern void lzma_ ## mf_name ## _get_matches( \
- lzma_lz_encoder *restrict lz, \
- uint32_t *restrict distances)
-
-#define LZMA_SKIP_C(mf_name) \
- extern void lzma_ ## mf_name ## _skip( \
- lzma_lz_encoder *lz, uint32_t num)
-
-LZMA_GET_MATCHES(LZMA_MATCH_FINDER_NAME_LOWER);
-
-LZMA_SKIP(LZMA_MATCH_FINDER_NAME_LOWER);
diff --git a/src/liblzma/lzma/Makefile.am b/src/liblzma/lzma/Makefile.am
index 59ded214..7aeceb63 100644
--- a/src/liblzma/lzma/Makefile.am
+++ b/src/liblzma/lzma/Makefile.am
@@ -14,37 +14,46 @@
EXTRA_DIST = fastpos_tablegen.c
-noinst_LTLIBRARIES = liblzma4.la
-liblzma4_la_CPPFLAGS = \
+## Using liblzma2 since liblzma is already used for the final library.
+noinst_LTLIBRARIES = liblzma2.la
+liblzma2_la_CPPFLAGS = \
-I@top_srcdir@/src/liblzma/api \
-I@top_srcdir@/src/liblzma/common \
-I@top_srcdir@/src/liblzma/lz \
-I@top_srcdir@/src/liblzma/rangecoder
-liblzma4_la_SOURCES = \
- lzma_common.h \
- lzma_literal.c \
- lzma_literal.h
+liblzma2_la_SOURCES = lzma_common.h
-if COND_MAIN_ENCODER
-liblzma4_la_SOURCES += \
+if COND_ENCODER_LZMA
+liblzma2_la_SOURCES += \
fastpos.h \
lzma_encoder.h \
lzma_encoder.c \
lzma_encoder_presets.c \
lzma_encoder_private.h \
- lzma_encoder_init.c \
lzma_encoder_features.c \
- lzma_encoder_getoptimum.c \
- lzma_encoder_getoptimumfast.c
+ lzma_encoder_optimum_fast.c \
+ lzma_encoder_optimum_normal.c
if !COND_SMALL
-liblzma4_la_SOURCES += fastpos_table.c
+liblzma2_la_SOURCES += fastpos_table.c
endif
endif
-if COND_MAIN_DECODER
-liblzma4_la_SOURCES += \
+if COND_DECODER_LZMA
+liblzma2_la_SOURCES += \
lzma_decoder.c \
lzma_decoder.h
endif
+
+if COND_ENCODER_LZMA2
+liblzma2_la_SOURCES += \
+ lzma2_encoder.c \
+ lzma2_encoder.h
+endif
+
+if COND_DECODER_LZMA2
+liblzma2_la_SOURCES += \
+ lzma2_decoder.c \
+ lzma2_decoder.h
+endif
diff --git a/src/liblzma/lzma/fastpos.h b/src/liblzma/lzma/fastpos.h
index 57a94556..503be275 100644
--- a/src/liblzma/lzma/fastpos.h
+++ b/src/liblzma/lzma/fastpos.h
@@ -81,8 +81,6 @@
// I'm making the table version the default, because that has good speed
// on all systems I have tried. The size optimized version is sometimes
// slightly faster, but sometimes it is a lot slower.
-//
-// Finally, this code isn't a major bottle neck in LZMA encoding anyway.
#ifdef HAVE_SMALL
# include "bsr.h"
@@ -135,11 +133,7 @@ get_pos_slot(uint32_t pos)
static inline uint32_t
get_pos_slot_2(uint32_t pos)
{
- // FIXME: This assert() cannot be enabled at the moment, because
- // lzma_getoptimum.c calls this function so that this assertion
- // fails; however, it ignores the result of this function when
- // this assert() would have failed.
- // assert(pos >= FULL_DISTANCES);
+ assert(pos >= FULL_DISTANCES);
if (pos < fastpos_limit(FULL_DISTANCES_BITS - 1, 0))
return fastpos_result(pos, FULL_DISTANCES_BITS - 1, 0);
diff --git a/src/liblzma/lzma/lzma2_decoder.c b/src/liblzma/lzma/lzma2_decoder.c
new file mode 100644
index 00000000..b16c40ce
--- /dev/null
+++ b/src/liblzma/lzma/lzma2_decoder.c
@@ -0,0 +1,318 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma2_decoder.c
+/// \brief LZMA2 decoder
+//
+// Copyright (C) 1999-2008 Igor Pavlov
+// Copyright (C) 2008 Lasse Collin
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma2_decoder.h"
+#include "lz_decoder.h"
+#include "lzma_decoder.h"
+
+
+struct lzma_coder_s {
+ enum sequence {
+ SEQ_CONTROL,
+ SEQ_UNCOMPRESSED_1,
+ SEQ_UNCOMPRESSED_2,
+ SEQ_COMPRESSED_0,
+ SEQ_COMPRESSED_1,
+ SEQ_PROPERTIES,
+ SEQ_LZMA,
+ SEQ_COPY,
+ } sequence;
+
+ /// Sequence after the size fields have been decoded.
+ enum sequence next_sequence;
+
+ /// LZMA decoder
+ lzma_lz_decoder lzma;
+
+ /// Uncompressed size of LZMA chunk
+ size_t uncompressed_size;
+
+ /// Compressed size of the chunk (naturally equals to uncompressed
+ /// size of uncompressed chunk)
+ size_t compressed_size;
+
+ /// True if properties are needed. This is false before the
+ /// first LZMA chunk.
+ bool need_properties;
+
+ /// True if dictionary reset is needed. This is false before the
+ /// first chunk (LZMA or uncompressed).
+ bool need_dictionary_reset;
+
+ lzma_options_lzma options;
+};
+
+
+static lzma_ret
+lzma2_decode(lzma_coder *restrict coder, lzma_dict *restrict dict,
+ const uint8_t *restrict in, size_t *restrict in_pos,
+ size_t in_size)
+{
+ // With SEQ_LZMA it is possible that no new input is needed to do
+ // some progress. The rest of the sequences assume that there is
+ // at least one byte of input.
+ while (*in_pos < in_size || coder->sequence == SEQ_LZMA)
+ switch (coder->sequence) {
+ case SEQ_CONTROL:
+ if (in[*in_pos] & 0x80) {
+ // Get the highest five bits of uncompressed size.
+ coder->uncompressed_size
+ = (uint32_t)(in[*in_pos] & 0x1F) << 16;
+ coder->sequence = SEQ_UNCOMPRESSED_1;
+
+ // See if we need to reset dictionary or state.
+ switch ((in[(*in_pos)++] >> 5) & 3) {
+ case 3:
+ dict_reset(dict);
+ coder->need_dictionary_reset = false;
+
+ // Fall through
+
+ case 2:
+ if (coder->need_dictionary_reset)
+ return LZMA_DATA_ERROR;
+
+ coder->need_properties = false;
+ coder->next_sequence = SEQ_PROPERTIES;
+ break;
+
+ case 1:
+ if (coder->need_properties)
+ return LZMA_DATA_ERROR;
+
+ coder->lzma.reset(coder->lzma.coder,
+ &coder->options);
+
+ coder->next_sequence = SEQ_LZMA;
+ break;
+
+ case 0:
+ if (coder->need_properties)
+ return LZMA_DATA_ERROR;
+
+ coder->next_sequence = SEQ_LZMA;
+ break;
+ }
+
+ } else {
+ switch (in[(*in_pos)++]) {
+ case 0:
+ // End of payload marker
+ return LZMA_STREAM_END;
+
+ case 1:
+ // Dictionary reset
+ dict_reset(dict);
+ coder->need_dictionary_reset = false;
+
+ // Fall through
+
+ case 2:
+ if (coder->need_dictionary_reset)
+ return LZMA_DATA_ERROR;
+
+ // Uncompressed chunk; we need to read total
+ // size first.
+ coder->sequence = SEQ_COMPRESSED_0;
+ coder->next_sequence = SEQ_COPY;
+ break;
+
+ default:
+ return LZMA_DATA_ERROR;
+ }
+ }
+
+ break;
+
+ case SEQ_UNCOMPRESSED_1:
+ coder->uncompressed_size += (uint32_t)(in[(*in_pos)++]) << 8;
+ coder->sequence = SEQ_UNCOMPRESSED_2;
+ break;
+
+ case SEQ_UNCOMPRESSED_2:
+ coder->uncompressed_size += in[(*in_pos)++] + 1;
+ coder->sequence = SEQ_COMPRESSED_0;
+ coder->lzma.set_uncompressed(coder->lzma.coder,
+ coder->uncompressed_size);
+ break;
+
+ case SEQ_COMPRESSED_0:
+ coder->compressed_size = (uint32_t)(in[(*in_pos)++]) << 8;
+ coder->sequence = SEQ_COMPRESSED_1;
+ break;
+
+ case SEQ_COMPRESSED_1:
+ coder->compressed_size += in[(*in_pos)++] + 1;
+ coder->sequence = coder->next_sequence;
+ break;
+
+ case SEQ_PROPERTIES:
+ if (lzma_lzma_lclppb_decode(&coder->options, in[(*in_pos)++]))
+ return LZMA_DATA_ERROR;
+
+ coder->lzma.reset(coder->lzma.coder, &coder->options);
+
+ coder->sequence = SEQ_LZMA;
+ break;
+
+ case SEQ_LZMA: {
+ // Store the start offset so that we can update
+ // coder->compressed_size later.
+ const size_t in_start = *in_pos;
+
+ // Decode from in[] to *dict.
+ const lzma_ret ret = coder->lzma.code(coder->lzma.coder,
+ dict, in, in_pos, in_size);
+
+ // Validate and update coder->compressed_size.
+ const size_t in_used = *in_pos - in_start;
+ if (in_used > coder->compressed_size)
+ return LZMA_DATA_ERROR;
+
+ coder->compressed_size -= in_used;
+
+ // Return if we didn't finish the chunk, or an error occurred.
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ // The LZMA decoder must have consumed the whole chunk now.
+ // We don't need to worry about uncompressed size since it
+ // is checked by the LZMA decoder.
+ if (coder->compressed_size != 0)
+ return LZMA_DATA_ERROR;
+
+ coder->sequence = SEQ_CONTROL;
+ break;
+ }
+
+ case SEQ_COPY: {
+ // Copy from input to the dictionary as is.
+ // FIXME Can copy too much?
+ dict_write(dict, in, in_pos, in_size, &coder->compressed_size);
+ if (coder->compressed_size != 0)
+ return LZMA_OK;
+
+ coder->sequence = SEQ_CONTROL;
+ break;
+ }
+
+ default:
+ assert(0);
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+lzma2_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ assert(coder->lzma.end == NULL);
+ lzma_free(coder->lzma.coder, allocator);
+
+ lzma_free(coder, allocator);
+
+ return;
+}
+
+
+static lzma_ret
+lzma2_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator,
+ const void *options, size_t *dict_size)
+{
+ if (lz->coder == NULL) {
+ lz->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (lz->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ lz->code = &lzma2_decode;
+ lz->end = &lzma2_decoder_end;
+
+ lz->coder->lzma = LZMA_LZ_DECODER_INIT;
+ }
+
+ lz->coder->sequence = SEQ_CONTROL;
+ lz->coder->need_properties = true;
+ lz->coder->need_dictionary_reset = true;
+
+ return lzma_lzma_decoder_create(&lz->coder->lzma,
+ allocator, options, dict_size);
+}
+
+
+extern lzma_ret
+lzma_lzma2_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ // LZMA2 can only be the last filter in the chain. This is enforced
+ // by the raw_decoder initialization.
+ assert(filters[1].init == NULL);
+
+ return lzma_lz_decoder_init(next, allocator, filters,
+ &lzma2_decoder_init);
+}
+
+
+extern uint64_t
+lzma_lzma2_decoder_memusage(const void *options)
+{
+ const uint64_t lzma_memusage = lzma_lzma_decoder_memusage(options);
+ if (lzma_memusage == UINT64_MAX)
+ return UINT64_MAX;
+
+ return sizeof(lzma_coder) + lzma_memusage;
+}
+
+
+extern lzma_ret
+lzma_lzma2_props_decode(void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size)
+{
+ if (props_size != 1)
+ return LZMA_HEADER_ERROR;
+
+ // Check that reserved bits are unset.
+ if (props[0] & 0xC0)
+ return LZMA_HEADER_ERROR;
+
+ // Decode the dictionary size.
+ if (props[0] > 40)
+ return LZMA_HEADER_ERROR;
+
+ lzma_options_lzma *opt = lzma_alloc(
+ sizeof(lzma_options_lzma), allocator);
+ if (opt == NULL)
+ return LZMA_MEM_ERROR;
+
+ if (props[0] == 40) {
+ opt->dictionary_size = UINT32_MAX;
+ } else {
+ opt->dictionary_size = 2 | (props[0] & 1);
+ opt->dictionary_size <<= props[0] / 2 + 11;
+ }
+
+ opt->preset_dictionary = NULL;
+ opt->preset_dictionary_size = 0;
+
+ *options = opt;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/lzma/lzma2_decoder.h b/src/liblzma/lzma/lzma2_decoder.h
new file mode 100644
index 00000000..a7504863
--- /dev/null
+++ b/src/liblzma/lzma/lzma2_decoder.h
@@ -0,0 +1,35 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma2_decoder.h
+/// \brief LZMA2 decoder
+//
+// Copyright (C) 1999-2008 Igor Pavlov
+// Copyright (C) 2008 Lasse Collin
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA2_DECODER_H
+#define LZMA_LZMA2_DECODER_H
+
+#include "common.h"
+
+extern lzma_ret lzma_lzma2_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern uint64_t lzma_lzma2_decoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma2_props_decode(
+ void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size);
+
+#endif
diff --git a/src/liblzma/lzma/lzma2_encoder.c b/src/liblzma/lzma/lzma2_encoder.c
new file mode 100644
index 00000000..b2cd176b
--- /dev/null
+++ b/src/liblzma/lzma/lzma2_encoder.c
@@ -0,0 +1,406 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma2_encoder.c
+/// \brief LZMA2 encoder
+//
+// Copyright (C) 1999-2008 Igor Pavlov
+// Copyright (C) 2008 Lasse Collin
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lz_encoder.h"
+#include "lzma_encoder.h"
+#include "fastpos.h"
+#include "lzma2_encoder.h"
+
+
+/// Maximum number of bytes of actual data per chunk (no headers)
+#define LZMA2_CHUNK_MAX (UINT32_C(1) << 16)
+
+/// Maximum uncompressed size of LZMA chunk (no headers)
+#define LZMA2_UNCOMPRESSED_MAX (UINT32_C(1) << 21)
+
+/// Maximum size of LZMA2 headers
+#define LZMA2_HEADER_MAX 6
+
+/// Size of a header for uncompressed chunk
+#define LZMA2_HEADER_UNCOMPRESSED 3
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_INIT,
+ SEQ_LZMA_ENCODE,
+ SEQ_LZMA_COPY,
+ SEQ_UNCOMPRESSED_HEADER,
+ SEQ_UNCOMPRESSED_COPY,
+ } sequence;
+
+ /// LZMA encoder
+ lzma_coder *lzma;
+
+ /// If this is not NULL, we will check new options from this
+ /// structure when starting a new chunk.
+ const lzma_options_lzma *opt_new;
+
+ /// LZMA options currently in use.
+ lzma_options_lzma opt_cur;
+
+ bool need_properties;
+ bool need_state_reset;
+ bool need_dictionary_reset;
+
+ /// Uncompressed size of a chunk
+ size_t uncompressed_size;
+
+ /// Compressed size of a chunk (excluding headers); this is also used
+ /// to indicate the end of buf[] in SEQ_LZMA_COPY.
+ size_t compressed_size;
+
+ /// Read position in buf[]
+ size_t buf_pos;
+
+ /// Buffer to hold the chunk header and LZMA compressed data
+ uint8_t buf[LZMA2_HEADER_MAX + LZMA2_CHUNK_MAX];
+};
+
+
+static void
+lzma2_header_lzma(lzma_coder *coder)
+{
+ assert(coder->uncompressed_size > 0);
+ assert(coder->uncompressed_size <= LZMA2_UNCOMPRESSED_MAX);
+ assert(coder->compressed_size > 0);
+ assert(coder->compressed_size <= LZMA2_CHUNK_MAX);
+
+ size_t pos;
+
+ if (coder->need_properties) {
+ pos = 0;
+
+ if (coder->need_dictionary_reset)
+ coder->buf[pos] = 0x80 + (3 << 5);
+ else
+ coder->buf[pos] = 0x80 + (2 << 5);
+ } else {
+ pos = 1;
+
+ if (coder->need_state_reset)
+ coder->buf[pos] = 0x80 + (1 << 5);
+ else
+ coder->buf[pos] = 0x80;
+ }
+
+ // Set the start position for copying.
+ coder->buf_pos = pos;
+
+ // Uncompressed size
+ size_t size = coder->uncompressed_size - 1;
+ coder->buf[pos++] += size >> 16;
+ coder->buf[pos++] = (size >> 8) & 0xFF;
+ coder->buf[pos++] = size & 0xFF;
+
+ // Compressed size
+ size = coder->compressed_size - 1;
+ coder->buf[pos++] = size >> 8;
+ coder->buf[pos++] = size & 0xFF;
+
+ // Properties, if needed
+ if (coder->need_properties)
+ lzma_lzma_lclppb_encode(&coder->opt_cur, coder->buf + pos);
+
+ coder->need_properties = false;
+ coder->need_state_reset = false;
+ coder->need_dictionary_reset = false;
+
+ // The copying code uses coder->compressed_size to indicate the end
+ // of coder->buf[], so we need add the maximum size of the header here.
+ coder->compressed_size += LZMA2_HEADER_MAX;
+
+ return;
+}
+
+
+static void
+lzma2_header_uncompressed(lzma_coder *coder)
+{
+ assert(coder->uncompressed_size > 0);
+ assert(coder->uncompressed_size <= LZMA2_CHUNK_MAX);
+
+ // If this is the first chunk, we need to include dictionary
+ // reset indicator.
+ if (coder->need_dictionary_reset)
+ coder->buf[0] = 1;
+ else
+ coder->buf[0] = 2;
+
+ coder->need_dictionary_reset = false;
+
+ // "Compressed" size
+ coder->buf[1] = (coder->uncompressed_size - 1) >> 8;
+ coder->buf[2] = (coder->uncompressed_size - 1) & 0xFF;
+
+ // Set the start position for copying.
+ coder->buf_pos = 0;
+ return;
+}
+
+
+static lzma_ret
+lzma2_encode(lzma_coder *restrict coder, lzma_mf *restrict mf,
+ uint8_t *restrict out, size_t *restrict out_pos,
+ size_t out_size)
+{
+ while (*out_pos < out_size)
+ switch (coder->sequence) {
+ case SEQ_INIT:
+ // If there's no input left and we are flushing or finishing,
+ // don't start a new chunk.
+ if (mf_unencoded(mf) == 0) {
+ // Write end of payload marker if finishing.
+ if (mf->action == LZMA_FINISH)
+ out[(*out_pos)++] = 0;
+
+ return mf->action == LZMA_RUN
+ ? LZMA_OK : LZMA_STREAM_END;
+ }
+
+ // Look if there are new options. At least for now,
+ // only lc/lp/pb can be changed.
+ if (coder->opt_new != NULL
+ && (coder->opt_cur.literal_context_bits
+ != coder->opt_new->literal_context_bits
+ || coder->opt_cur.literal_pos_bits
+ != coder->opt_new->literal_pos_bits
+ || coder->opt_cur.pos_bits
+ != coder->opt_new->pos_bits)) {
+ // Options have been changed, copy them to opt_cur.
+ coder->opt_cur.literal_context_bits
+ = coder->opt_new->literal_context_bits;
+ coder->opt_cur.literal_pos_bits
+ = coder->opt_new->literal_pos_bits;
+ coder->opt_cur.pos_bits
+ = coder->opt_new->pos_bits;
+
+ // We need to write the new options and reset
+ // the encoder state.
+ coder->need_properties = true;
+ coder->need_state_reset = true;
+ }
+
+ if (coder->need_state_reset)
+ lzma_lzma_encoder_reset(coder->lzma, &coder->opt_cur);
+
+ coder->uncompressed_size = 0;
+ coder->compressed_size = 0;
+ coder->sequence = SEQ_LZMA_ENCODE;
+
+ // Fall through
+
+ case SEQ_LZMA_ENCODE: {
+ // Calculate how much more uncompressed data this chunk
+ // could accept.
+ const uint32_t left = LZMA2_UNCOMPRESSED_MAX
+ - coder->uncompressed_size;
+ uint32_t limit;
+
+ if (left < mf->match_len_max) {
+ // Must flush immediatelly since the next LZMA symbol
+ // could make the uncompressed size of the chunk too
+ // big.
+ limit = 0;
+ } else {
+ // Calculate maximum read_limit that is OK from point
+ // of view of LZMA2 chunk size.
+ limit = mf->read_pos - mf->read_ahead
+ + left - mf->match_len_max;
+ }
+
+ // Save the start position so that we can update
+ // coder->uncompressed_size.
+ const uint32_t read_start = mf->read_pos - mf->read_ahead;
+
+ // Call the LZMA encoder until the chunk is finished.
+ const lzma_ret ret = lzma_lzma_encode(coder->lzma, mf,
+ coder->buf + LZMA2_HEADER_MAX,
+ &coder->compressed_size,
+ LZMA2_CHUNK_MAX, limit);
+
+ coder->uncompressed_size += mf->read_pos - mf->read_ahead
+ - read_start;
+
+ assert(coder->compressed_size <= LZMA2_CHUNK_MAX);
+ assert(coder->uncompressed_size <= LZMA2_UNCOMPRESSED_MAX);
+
+ if (ret != LZMA_STREAM_END)
+ return LZMA_OK;
+
+ // See if the chunk compressed. If it didn't, we encode it
+ // as uncompressed chunk. This saves a few bytes of space
+ // and makes decoding faster.
+ if (coder->compressed_size >= coder->uncompressed_size) {
+ coder->uncompressed_size += mf->read_ahead;
+ assert(coder->uncompressed_size
+ <= LZMA2_UNCOMPRESSED_MAX);
+ mf->read_ahead = 0;
+ lzma2_header_uncompressed(coder);
+ coder->need_state_reset = true;
+ coder->sequence = SEQ_UNCOMPRESSED_HEADER;
+ break;
+ }
+
+ // The chunk did compress at least by one byte, so we store
+ // the chunk as LZMA.
+ lzma2_header_lzma(coder);
+
+ coder->sequence = SEQ_LZMA_COPY;
+ }
+
+ // Fall through
+
+ case SEQ_LZMA_COPY:
+ // Copy the compressed chunk along its headers to the
+ // output buffer.
+ lzma_bufcpy(coder->buf, &coder->buf_pos,
+ coder->compressed_size,
+ out, out_pos, out_size);
+ if (coder->buf_pos != coder->compressed_size)
+ return LZMA_OK;
+
+ coder->sequence = SEQ_INIT;
+ break;
+
+ case SEQ_UNCOMPRESSED_HEADER:
+ // Copy the three-byte header to indicate uncompressed chunk.
+ lzma_bufcpy(coder->buf, &coder->buf_pos,
+ LZMA2_HEADER_UNCOMPRESSED,
+ out, out_pos, out_size);
+ if (coder->buf_pos != LZMA2_HEADER_UNCOMPRESSED)
+ return LZMA_OK;
+
+ coder->sequence = SEQ_UNCOMPRESSED_COPY;
+
+ // Fall through
+
+ case SEQ_UNCOMPRESSED_COPY:
+ // Copy the uncompressed data as is from the dictionary
+ // to the output buffer.
+ mf_read(mf, out, out_pos, out_size, &coder->uncompressed_size);
+ if (coder->uncompressed_size != 0)
+ return LZMA_OK;
+
+ coder->sequence = SEQ_INIT;
+ break;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+lzma2_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_free(coder->lzma, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+lzma2_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator,
+ const void *options, lzma_lz_options *lz_options)
+{
+ if (options == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (lz->coder == NULL) {
+ lz->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (lz->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ lz->code = &lzma2_encode;
+ lz->end = &lzma2_encoder_end;
+
+ lz->coder->lzma = NULL;
+ }
+
+ lz->coder->sequence = SEQ_INIT;
+ lz->coder->need_properties = true;
+ lz->coder->need_state_reset = false;
+ lz->coder->need_dictionary_reset = true;
+
+ lz->coder->opt_cur = *(const lzma_options_lzma *)(options);
+ lz->coder->opt_new = lz->coder->opt_cur.persistent
+ ? options : NULL;
+
+ // Initialize LZMA encoder
+ return_if_error(lzma_lzma_encoder_create(&lz->coder->lzma, allocator,
+ &lz->coder->opt_cur, lz_options));
+
+ // Make sure that we will always have enough history available in
+ // case we need to use uncompressed chunks. They are used when the
+ // compressed size of a chunk is not smaller than the uncompressed
+ // size, so we need to have at least LZMA2_COMPRESSED_MAX bytes
+ // history available.
+ if (lz_options->before_size + lz_options->dictionary_size
+ < LZMA2_CHUNK_MAX)
+ lz_options->before_size = LZMA2_CHUNK_MAX
+ - lz_options->dictionary_size;
+
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_lzma2_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ return lzma_lz_encoder_init(
+ next, allocator, filters, &lzma2_encoder_init);
+}
+
+
+extern uint64_t
+lzma_lzma2_encoder_memusage(const void *options)
+{
+ const uint64_t lzma_memusage = lzma_lzma_encoder_memusage(options);
+ if (lzma_memusage == UINT64_MAX)
+ return UINT64_MAX;
+
+ return sizeof(lzma_coder) + lzma_memusage;
+}
+
+
+extern lzma_ret
+lzma_lzma2_props_encode(const void *options, uint8_t *out)
+{
+ const lzma_options_lzma *const opt = options;
+ uint32_t d = MAX(opt->dictionary_size, LZMA_DICTIONARY_SIZE_MIN);
+
+ // Round up to to the next 2^n - 1 or 2^n + 2^(n - 1) - 1 depending
+ // on which one is the next:
+ --d;
+ d |= d >> 2;
+ d |= d >> 3;
+ d |= d >> 4;
+ d |= d >> 8;
+ d |= d >> 16;
+
+ // Get the highest two bits using the proper encoding:
+ if (d == UINT32_MAX)
+ out[0] = 40;
+ else
+ out[0] = get_pos_slot(d + 1) - 24;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/raw_common.h b/src/liblzma/lzma/lzma2_encoder.h
index 0a27f3dc..3e27f680 100644
--- a/src/liblzma/common/raw_common.h
+++ b/src/liblzma/lzma/lzma2_encoder.h
@@ -1,9 +1,10 @@
///////////////////////////////////////////////////////////////////////////////
//
-/// \file raw_common.h
-/// \brief Stuff shared between raw encoder and raw decoder
+/// \file lzma2_encoder.h
+/// \brief LZMA2 encoder
//
-// Copyright (C) 2007 Lasse Collin
+// Copyright (C) 1999-2008 Igor Pavlov
+// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -17,14 +18,17 @@
//
///////////////////////////////////////////////////////////////////////////////
-#ifndef LZMA_RAW_COMMON_H
-#define LZMA_RAW_COMMON_H
+#ifndef LZMA_LZMA2_ENCODER_H
+#define LZMA_LZMA2_ENCODER_H
#include "common.h"
-extern lzma_ret lzma_raw_coder_init(lzma_next_coder *next,
- lzma_allocator *allocator, const lzma_options_filter *options,
- lzma_init_function (*get_function)(lzma_vli id),
- bool is_encoder);
+extern lzma_ret lzma_lzma2_encoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters);
+
+extern uint64_t lzma_lzma2_encoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma2_props_encode(const void *options, uint8_t *out);
#endif
diff --git a/src/liblzma/lzma/lzma_common.h b/src/liblzma/lzma/lzma_common.h
index f677fcce..6909969b 100644
--- a/src/liblzma/lzma/lzma_common.h
+++ b/src/liblzma/lzma/lzma_common.h
@@ -22,81 +22,31 @@
#define LZMA_LZMA_COMMON_H
#include "common.h"
-#include "lzma_literal.h"
#include "range_common.h"
-///////////////
-// Constants //
-///////////////
-
-#define REP_DISTANCES 4
-
-#define POS_SLOT_BITS 6
-#define DICT_LOG_SIZE_MAX 30
-#define DIST_TABLE_SIZE_MAX (DICT_LOG_SIZE_MAX * 2)
-#if (UINT32_C(1) << DICT_LOG_SIZE_MAX) != LZMA_DICTIONARY_SIZE_MAX
-# error DICT_LOG_SIZE_MAX is inconsistent with LZMA_DICTIONARY_SIZE_MAX
-#endif
-
-// 2 is for speed optimization
-#define LEN_TO_POS_STATES_BITS 2
-#define LEN_TO_POS_STATES (1 << LEN_TO_POS_STATES_BITS)
-
-#define MATCH_MIN_LEN 2
-
-#define ALIGN_BITS 4
-#define ALIGN_TABLE_SIZE (1 << ALIGN_BITS)
-#define ALIGN_MASK (ALIGN_TABLE_SIZE - 1)
-
-#define START_POS_MODEL_INDEX 4
-#define END_POS_MODEL_INDEX 14
-#define POS_MODELS (END_POS_MODEL_INDEX - START_POS_MODEL_INDEX)
-
-#define FULL_DISTANCES_BITS (END_POS_MODEL_INDEX / 2)
-#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
+///////////////////
+// Miscellaneous //
+///////////////////
+/// Maximum number of position states. A position state is the lowest pos bits
+/// number of bits of the current uncompressed offset. In some places there
+/// are different sets of probabilities for different pos states.
#define POS_STATES_MAX (1 << LZMA_POS_BITS_MAX)
-// Length coder & Length price table encoder
-#define LEN_LOW_BITS 3
-#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
-#define LEN_MID_BITS 3
-#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
-#define LEN_HIGH_BITS 8
-#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
-#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
-#define LEN_SPEC_SYMBOLS (LOW_LOW_SYMBOLS + LEN_MID_LEN_SYMBOLS)
-#define MATCH_MAX_LEN (MATCH_MIN_LEN + LEN_SYMBOLS - 1)
-
-// Total number of probs in a Len Encoder
-#define LEN_CODER_TOTAL_PROBS (LEN_HIGH_CODER + LEN_HIGH_SYMBOLS)
-
-// Price table size of Len Encoder
-#define LEN_PRICES (LEN_SYMBOLS << LZMA_POS_BITS_MAX)
-
-// Special lengths used together with distance == UINT32_MAX
-#define LEN_SPECIAL_EOPM MATCH_MIN_LEN
-#define LEN_SPECIAL_FLUSH (LEN_SPECIAL_EOPM + 1)
-
-
-// Optimal - Number of entries in the optimum array.
-#define OPTS (1 << 12)
-
-
-// Miscellaneous
-#define INFINITY_PRICE 0x0FFFFFFF
-
-
-////////////
-// Macros //
-////////////
-
-#define get_len_to_pos_state(len) \
- ((len) < LEN_TO_POS_STATES + MATCH_MIN_LEN \
- ? (len) - MATCH_MIN_LEN \
- : LEN_TO_POS_STATES - 1)
+/// Validates literal_context_bits, literal_pos_bits, and pos_bits.
+static inline bool
+is_lclppb_valid(const lzma_options_lzma *options)
+{
+ return options->literal_context_bits <= LZMA_LITERAL_CONTEXT_BITS_MAX
+ && options->literal_pos_bits
+ <= LZMA_LITERAL_POS_BITS_MAX
+ && options->literal_context_bits
+ + options->literal_pos_bits
+ <= LZMA_LITERAL_BITS_MAX
+ && options->pos_bits <= LZMA_POS_BITS_MAX;
+}
///////////
@@ -161,4 +111,126 @@ typedef enum {
#define is_literal_state(state) \
((state) < LIT_STATES)
+
+/////////////
+// Literal //
+/////////////
+
+/// Each literal coder is divided in three sections:
+/// - 0x001-0x0FF: Without match byte
+/// - 0x101-0x1FF: With match byte; match bit is 0
+/// - 0x201-0x2FF: With match byte; match bit is 1
+///
+/// Match byte is used when the previous LZMA symbol was something else than
+/// a literal (that is, it was some kind of match).
+#define LITERAL_CODER_SIZE 0x300
+
+/// Maximum number of literal coders
+#define LITERAL_CODERS_MAX (1 << LZMA_LITERAL_BITS_MAX)
+
+/// Locate the literal coder for the next literal byte. The choice depends on
+/// - the lowest literal_pos_bits bits of the position of the current
+/// byte; and
+/// - the highest literal_context_bits bits of the previous byte.
+#define literal_subcoder(probs, lc, lp_mask, pos, prev_byte) \
+ ((probs)[(((pos) & lp_mask) << lc) + ((prev_byte) >> (8 - lc))])
+
+
+static inline void
+literal_init(probability (*probs)[LITERAL_CODER_SIZE],
+ uint32_t literal_context_bits, uint32_t literal_pos_bits)
+{
+ assert(literal_context_bits + literal_pos_bits
+ <= LZMA_LITERAL_BITS_MAX);
+
+ const uint32_t coders
+ = 1U << (literal_context_bits + literal_pos_bits);
+
+ for (uint32_t i = 0; i < coders; ++i)
+ for (uint32_t j = 0; j < LITERAL_CODER_SIZE; ++j)
+ bit_reset(probs[i][j]);
+
+ return;
+}
+
+
+//////////////////
+// Match length //
+//////////////////
+
+// Minimum length of a match is two bytes.
+#define MATCH_LEN_MIN 2
+
+// Match length is encoded with 4, 5, or 10 bits.
+//
+// Length Bits
+// 2-9 4 = Choice=0 + 3 bits
+// 10-17 5 = Choice=1 + Choice2=0 + 3 bits
+// 18-273 10 = Choice=1 + Choice2=1 + 8 bits
+#define LEN_LOW_BITS 3
+#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
+#define LEN_MID_BITS 3
+#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
+#define LEN_HIGH_BITS 8
+#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
+#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
+
+// Maximum length of a match is 273 which is a result of the encoding
+// described above.
+#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
+
+
+////////////////////
+// Match distance //
+////////////////////
+
+// Different set of probabilities is used for match distances that have very
+// short match length: Lengths of 2, 3, and 4 bytes have a separate set of
+// probabilities for each length. The matches with longer length use a shared
+// set of probabilities.
+#define LEN_TO_POS_STATES 4
+
+// Macro to get the index of the appropriate probability array.
+#define get_len_to_pos_state(len) \
+ ((len) < LEN_TO_POS_STATES + MATCH_LEN_MIN \
+ ? (len) - MATCH_LEN_MIN \
+ : LEN_TO_POS_STATES - 1)
+
+// The highest two bits of a match distance (pos slot) are encoded using six
+// bits. See fastpos.h for more explanation.
+#define POS_SLOT_BITS 6
+#define POS_SLOTS (1 << POS_SLOT_BITS)
+
+// Match distances up to 127 are fully encoded using probabilities. Since
+// the highest two bits (pos slot) are always encoded using six bits, the
+// distances 0-3 don't need any additional bits to encode, since the pos
+// slot itself is the same as the actual distance. START_POS_MODEL_INDEX
+// indicates the first pos slot where at least one additional bit is needed.
+#define START_POS_MODEL_INDEX 4
+
+// Match distances greater than 127 are encoded in three pieces:
+// - pos slot: the highest two bits
+// - direct bits: 2-26 bits below the highest two bits
+// - alignment bits: four lowest bits
+//
+// Direct bits don't use any probabilities.
+//
+// The pos slot value of 14 is for distances 128-191 (see the table in
+// fastpos.h to understand why).
+#define END_POS_MODEL_INDEX 14
+
+// Seven-bit distances use the full FIXME
+#define FULL_DISTANCES_BITS (END_POS_MODEL_INDEX / 2)
+#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
+
+// For match distances greater than 127, only the highest two bits and the
+// lowest four bits (alignment) is encoded using probabilities.
+#define ALIGN_BITS 4
+#define ALIGN_TABLE_SIZE (1 << ALIGN_BITS)
+#define ALIGN_MASK (ALIGN_TABLE_SIZE - 1)
+
+// LZMA remembers the four most recent match distances. Reusing these distances
+// tends to take less space than re-encoding the actual distance value.
+#define REP_DISTANCES 4
+
#endif
diff --git a/src/liblzma/lzma/lzma_decoder.c b/src/liblzma/lzma/lzma_decoder.c
index 68941021..e9d047d3 100644
--- a/src/liblzma/lzma/lzma_decoder.c
+++ b/src/liblzma/lzma/lzma_decoder.c
@@ -4,7 +4,7 @@
/// \brief LZMA decoder
//
// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
+// Copyright (C) 2007-2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -18,74 +18,147 @@
//
///////////////////////////////////////////////////////////////////////////////
-// NOTE: If you want to keep the line length in 80 characters, set
-// tab width to 4 or less in your editor when editing this file.
-
+#include "lz_decoder.h"
#include "lzma_common.h"
#include "lzma_decoder.h"
-#include "lz_decoder.h"
#include "range_decoder.h"
-/// REQUIRED_IN_BUFFER_SIZE is the number of required input bytes
-/// for the worst case: longest match with longest distance.
-/// LZMA_IN_BUFFER_SIZE must be larger than REQUIRED_IN_BUFFER_SIZE.
-/// 23 bits = 2 (match select) + 10 (len) + 6 (distance) + 4 (align)
-/// + 1 (rc_normalize)
-///
-/// \todo Is this correct for sure?
-///
-#define REQUIRED_IN_BUFFER_SIZE \
- ((23 * (BIT_MODEL_TOTAL_BITS - MOVE_BITS + 1) + 26 + 9) / 8)
+#ifdef HAVE_SMALL
+// Macros for (somewhat) size-optimized code.
+#define seq_4(seq) seq
-// Length decoders are easiest to have as macros, because they use range
-// decoder macros, which use local variables rc_range and rc_code.
+#define seq_6(seq) seq
-#define length_decode(target, len_decoder, pos_state) \
+#define seq_8(seq) seq
+
+#define seq_len(seq) \
+ seq ## _CHOICE, \
+ seq ## _CHOICE2, \
+ seq ## _BITTREE
+
+#define len_decode(target, ld, pos_state, seq) \
do { \
- if_bit_0(len_decoder.choice) { \
- update_bit_0(len_decoder.choice); \
- target = MATCH_MIN_LEN; \
- bittree_decode(target, len_decoder.low[pos_state], LEN_LOW_BITS); \
+case seq ## _CHOICE: \
+ rc_if_0(ld.choice, seq ## _CHOICE) { \
+ rc_update_0(ld.choice); \
+ probs = ld.low[pos_state];\
+ limit = LEN_LOW_SYMBOLS; \
+ target = MATCH_LEN_MIN; \
} else { \
- update_bit_1(len_decoder.choice); \
- if_bit_0(len_decoder.choice2) { \
- update_bit_0(len_decoder.choice2); \
- target = MATCH_MIN_LEN + LEN_LOW_SYMBOLS; \
- bittree_decode(target, len_decoder.mid[pos_state], LEN_MID_BITS); \
+ rc_update_1(ld.choice); \
+case seq ## _CHOICE2: \
+ rc_if_0(ld.choice2, seq ## _CHOICE2) { \
+ rc_update_0(ld.choice2); \
+ probs = ld.mid[pos_state]; \
+ limit = LEN_MID_SYMBOLS; \
+ target = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; \
} else { \
- update_bit_1(len_decoder.choice2); \
- target = MATCH_MIN_LEN + LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; \
- bittree_decode(target, len_decoder.high, LEN_HIGH_BITS); \
+ rc_update_1(ld.choice2); \
+ probs = ld.high; \
+ limit = LEN_HIGH_SYMBOLS; \
+ target = MATCH_LEN_MIN + LEN_LOW_SYMBOLS \
+ + LEN_MID_SYMBOLS; \
} \
} \
+ symbol = 1; \
+case seq ## _BITTREE: \
+ do { \
+ rc_bit(probs[symbol], , , seq ## _BITTREE); \
+ } while (symbol < limit); \
+ target += symbol - limit; \
} while (0)
-
-#define length_decode_dummy(target, len_decoder, pos_state) \
+#else // HAVE_SMALL
+
+// Unrolled versions
+#define seq_4(seq) \
+ seq ## 0, \
+ seq ## 1, \
+ seq ## 2, \
+ seq ## 3
+
+#define seq_6(seq) \
+ seq ## 0, \
+ seq ## 1, \
+ seq ## 2, \
+ seq ## 3, \
+ seq ## 4, \
+ seq ## 5
+
+#define seq_8(seq) \
+ seq ## 0, \
+ seq ## 1, \
+ seq ## 2, \
+ seq ## 3, \
+ seq ## 4, \
+ seq ## 5, \
+ seq ## 6, \
+ seq ## 7
+
+#define seq_len(seq) \
+ seq ## _CHOICE, \
+ seq ## _LOW0, \
+ seq ## _LOW1, \
+ seq ## _LOW2, \
+ seq ## _CHOICE2, \
+ seq ## _MID0, \
+ seq ## _MID1, \
+ seq ## _MID2, \
+ seq ## _HIGH0, \
+ seq ## _HIGH1, \
+ seq ## _HIGH2, \
+ seq ## _HIGH3, \
+ seq ## _HIGH4, \
+ seq ## _HIGH5, \
+ seq ## _HIGH6, \
+ seq ## _HIGH7
+
+#define len_decode(target, ld, pos_state, seq) \
do { \
- if_bit_0(len_decoder.choice) { \
- update_bit_0_dummy(); \
- target = MATCH_MIN_LEN; \
- bittree_decode_dummy(target, \
- len_decoder.low[pos_state], LEN_LOW_BITS); \
+ symbol = 1; \
+case seq ## _CHOICE: \
+ rc_if_0(ld.choice, seq ## _CHOICE) { \
+ rc_update_0(ld.choice); \
+ rc_bit_case(ld.low[pos_state][symbol], , , seq ## _LOW0); \
+ rc_bit_case(ld.low[pos_state][symbol], , , seq ## _LOW1); \
+ rc_bit_case(ld.low[pos_state][symbol], , , seq ## _LOW2); \
+ target = symbol - LEN_LOW_SYMBOLS + MATCH_LEN_MIN; \
} else { \
- update_bit_1_dummy(); \
- if_bit_0(len_decoder.choice2) { \
- update_bit_0_dummy(); \
- target = MATCH_MIN_LEN + LEN_LOW_SYMBOLS; \
- bittree_decode_dummy(target, len_decoder.mid[pos_state], \
- LEN_MID_BITS); \
+ rc_update_1(ld.choice); \
+case seq ## _CHOICE2: \
+ rc_if_0(ld.choice2, seq ## _CHOICE2) { \
+ rc_update_0(ld.choice2); \
+ rc_bit_case(ld.mid[pos_state][symbol], , , \
+ seq ## _MID0); \
+ rc_bit_case(ld.mid[pos_state][symbol], , , \
+ seq ## _MID1); \
+ rc_bit_case(ld.mid[pos_state][symbol], , , \
+ seq ## _MID2); \
+ target = symbol - LEN_MID_SYMBOLS \
+ + MATCH_LEN_MIN + LEN_LOW_SYMBOLS; \
} else { \
- update_bit_1_dummy(); \
- target = MATCH_MIN_LEN + LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; \
- bittree_decode_dummy(target, len_decoder.high, LEN_HIGH_BITS); \
+ rc_update_1(ld.choice2); \
+ rc_bit_case(ld.high[symbol], , , seq ## _HIGH0); \
+ rc_bit_case(ld.high[symbol], , , seq ## _HIGH1); \
+ rc_bit_case(ld.high[symbol], , , seq ## _HIGH2); \
+ rc_bit_case(ld.high[symbol], , , seq ## _HIGH3); \
+ rc_bit_case(ld.high[symbol], , , seq ## _HIGH4); \
+ rc_bit_case(ld.high[symbol], , , seq ## _HIGH5); \
+ rc_bit_case(ld.high[symbol], , , seq ## _HIGH6); \
+ rc_bit_case(ld.high[symbol], , , seq ## _HIGH7); \
+ target = symbol - LEN_HIGH_SYMBOLS \
+ + MATCH_LEN_MIN \
+ + LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; \
} \
} \
} while (0)
+#endif // HAVE_SMALL
+
+/// Length decoder probabilities; see comments in lzma_common.h.
typedef struct {
probability choice;
probability choice2;
@@ -96,26 +169,12 @@ typedef struct {
struct lzma_coder_s {
- /// Data of the next coder, if any.
- lzma_next_coder next;
-
- /// Sliding output window a.k.a. dictionary a.k.a. history buffer.
- lzma_lz_decoder lz;
-
- // Range coder
- lzma_range_decoder rc;
-
- // State
- lzma_lzma_state state;
- uint32_t rep0; ///< Distance of the latest match
- uint32_t rep1; ///< Distance of second latest match
- uint32_t rep2; ///< Distance of third latest match
- uint32_t rep3; ///< Distance of fourth latest match
- uint32_t pos_bits;
- uint32_t pos_mask;
- uint32_t now_pos; // Lowest 32-bits are enough here.
+ ///////////////////
+ // Probabilities //
+ ///////////////////
- lzma_literal_coder literal_coder;
+ /// Literals; see comments in lzma_common.h.
+ probability literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE];
/// If 1, it's a match. Otherwise it's a single 8-bit literal.
probability is_match[STATES][POS_STATES_MAX];
@@ -138,178 +197,107 @@ struct lzma_coder_s {
/// the length is decoded from rep_len_decoder.
probability is_rep0_long[STATES][POS_STATES_MAX];
- probability pos_slot_decoder[LEN_TO_POS_STATES][1 << POS_SLOT_BITS];
- probability pos_decoders[FULL_DISTANCES - END_POS_MODEL_INDEX];
- probability pos_align_decoder[1 << ALIGN_BITS];
-
- /// Length of a match
- lzma_length_decoder match_len_decoder;
-
- /// Length of a repeated match.
- lzma_length_decoder rep_len_decoder;
-
- /// True when we have produced at least one byte of output since the
- /// beginning of the stream or the latest flush marker.
- bool has_produced_output;
-};
-
-
-/// \brief Check if the next iteration of the decoder loop can be run.
-///
-/// \note There must always be REQUIRED_IN_BUFFER_SIZE bytes
-/// readable space!
-///
-static bool lzma_attribute((pure))
-decode_dummy(const lzma_coder *restrict coder,
- const uint8_t *restrict in, size_t in_pos_local,
- const size_t in_size, lzma_range_decoder rc,
- uint32_t state, uint32_t rep0, const uint32_t now_pos)
-{
- uint32_t rc_bound;
-
- do {
- const uint32_t pos_state = now_pos & coder->pos_mask;
-
- if_bit_0(coder->is_match[state][pos_state]) {
- // It's a literal i.e. a single 8-bit byte.
-
- update_bit_0_dummy();
-
- const probability *subcoder = literal_get_subcoder(
- coder->literal_coder, now_pos, lz_get_byte(coder->lz, 0));
- uint32_t symbol = 1;
-
- if (is_literal_state(state)) {
- // Decode literal without match byte.
- do {
- if_bit_0(subcoder[symbol]) {
- update_bit_0_dummy();
- symbol <<= 1;
- } else {
- update_bit_1_dummy();
- symbol = (symbol << 1) | 1;
- }
- } while (symbol < 0x100);
-
- } else {
- // Decode literal with match byte.
- uint32_t match_byte = lz_get_byte(coder->lz, rep0);
- uint32_t subcoder_offset = 0x100;
-
- do {
- match_byte <<= 1;
- const uint32_t match_bit = match_byte & subcoder_offset;
- const uint32_t subcoder_index
- = subcoder_offset + match_bit + symbol;
-
- if_bit_0(subcoder[subcoder_index]) {
- update_bit_0_dummy();
- symbol <<= 1;
- subcoder_offset &= ~match_bit;
- } else {
- update_bit_1_dummy();
- symbol = (symbol << 1) | 1;
- subcoder_offset &= match_bit;
- }
- } while (symbol < 0x100);
- }
-
- break;
- }
-
- update_bit_1_dummy();
- uint32_t len;
-
- if_bit_0(coder->is_rep[state]) {
- update_bit_0_dummy();
- length_decode_dummy(len, coder->match_len_decoder, pos_state);
-
- const uint32_t len_to_pos_state = get_len_to_pos_state(len);
- uint32_t pos_slot = 0;
- bittree_decode_dummy(pos_slot,
- coder->pos_slot_decoder[len_to_pos_state], POS_SLOT_BITS);
- assert(pos_slot <= 63);
-
- if (pos_slot >= START_POS_MODEL_INDEX) {
- uint32_t direct_bits = (pos_slot >> 1) - 1;
- assert(direct_bits >= 1 && direct_bits <= 31);
- rep0 = 2 | (pos_slot & 1);
-
- if (pos_slot < END_POS_MODEL_INDEX) {
- assert(direct_bits <= 5);
- rep0 <<= direct_bits;
- assert(rep0 <= 96);
- // -1 is fine, because bittree_reverse_decode()
- // starts from table index [1] (not [0]).
- assert((int32_t)(rep0 - pos_slot - 1) >= -1);
- assert((int32_t)(rep0 - pos_slot - 1) <= 82);
- // We add the result to rep0, so rep0
- // must not be part of second argument
- // of the macro.
- const int32_t offset = rep0 - pos_slot - 1;
- bittree_reverse_decode_dummy(coder->pos_decoders + offset,
- direct_bits);
- } else {
- assert(pos_slot >= 14);
- assert(direct_bits >= 6);
- direct_bits -= ALIGN_BITS;
- assert(direct_bits >= 2);
- rc_decode_direct_dummy(direct_bits);
-
- bittree_reverse_decode_dummy(coder->pos_align_decoder,
- ALIGN_BITS);
- }
- }
+ /// Probability tree for the highest two bits of the match distance.
+ /// There is a separate probability tree for match lengths of
+ /// 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
+ probability pos_slot[LEN_TO_POS_STATES][POS_SLOTS];
- } else {
- update_bit_1_dummy();
+ /// Probility trees for additional bits for match distance when the
+ /// distance is in the range [4, 127].
+ probability pos_special[FULL_DISTANCES - END_POS_MODEL_INDEX];
- if_bit_0(coder->is_rep0[state]) {
- update_bit_0_dummy();
+ /// Probability tree for the lowest four bits of a match distance
+ /// that is equal to or greater than 128.
+ probability pos_align[ALIGN_TABLE_SIZE];
- if_bit_0(coder->is_rep0_long[state][pos_state]) {
- update_bit_0_dummy();
- break;
- } else {
- update_bit_1_dummy();
- }
+ /// Length of a normal match
+ lzma_length_decoder match_len_decoder;
- } else {
- update_bit_1_dummy();
+ /// Length of a repeated match
+ lzma_length_decoder rep_len_decoder;
- if_bit_0(coder->is_rep1[state]) {
- update_bit_0_dummy();
- } else {
- update_bit_1_dummy();
+ ///////////////////
+ // Decoder state //
+ ///////////////////
- if_bit_0(coder->is_rep2[state]) {
- update_bit_0_dummy();
- } else {
- update_bit_1_dummy();
- }
- }
- }
+ // Range coder
+ lzma_range_decoder rc;
- length_decode_dummy(len, coder->rep_len_decoder, pos_state);
- }
- } while (0);
+ // Types of the most recently seen LZMA symbols
+ lzma_lzma_state state;
- rc_normalize();
+ uint32_t rep0; ///< Distance of the latest match
+ uint32_t rep1; ///< Distance of second latest match
+ uint32_t rep2; ///< Distance of third latest match
+ uint32_t rep3; ///< Distance of fourth latest match
- return in_pos_local <= in_size;
-}
+ uint32_t pos_mask; // (1U << pos_bits) - 1
+ uint32_t literal_context_bits;
+ uint32_t literal_pos_mask;
+
+ /// Uncompressed size as bytes, or LZMA_VLI_VALUE_UNKNOWN if end of
+ /// payload marker is expected.
+ lzma_vli uncompressed_size;
+
+ ////////////////////////////////
+ // State of incomplete symbol //
+ ////////////////////////////////
+
+ /// Position where to continue the decoder loop
+ enum {
+ SEQ_NORMALIZE,
+ SEQ_IS_MATCH,
+ seq_8(SEQ_LITERAL),
+ seq_8(SEQ_LITERAL_MATCHED),
+ SEQ_LITERAL_WRITE,
+ SEQ_IS_REP,
+ seq_len(SEQ_MATCH_LEN),
+ seq_6(SEQ_POS_SLOT),
+ SEQ_POS_MODEL,
+ SEQ_DIRECT,
+ seq_4(SEQ_ALIGN),
+ SEQ_EOPM,
+ SEQ_IS_REP0,
+ SEQ_SHORTREP,
+ SEQ_IS_REP0_LONG,
+ SEQ_IS_REP1,
+ SEQ_IS_REP2,
+ seq_len(SEQ_REP_LEN),
+ SEQ_COPY,
+ } sequence;
+
+ /// Base of the current probability tree
+ probability *probs;
+
+ /// Symbol being decoded. This is also used as an index variable in
+ /// bittree decoders: probs[symbol]
+ uint32_t symbol;
+
+ /// Used as a loop termination condition on bittree decoders and
+ /// direct bits decoder.
+ uint32_t limit;
+
+ /// Matched literal decoder: 0x100 or 0 to help avoiding branches.
+ /// Bittree reverse decoders: Offset of the next bit: 1 << offset
+ uint32_t offset;
+
+ /// If decoding a literal: match byte.
+ /// If decoding a match: length of the match.
+ uint32_t len;
+};
-static bool
-decode_real(lzma_coder *restrict coder, const uint8_t *restrict in,
- size_t *restrict in_pos, size_t in_size, bool has_safe_buffer)
+static lzma_ret
+lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr,
+ const uint8_t *restrict in,
+ size_t *restrict in_pos, size_t in_size)
{
////////////////////
// Initialization //
////////////////////
if (!rc_read_init(&coder->rc, in, in_pos, in_size))
- return false;
+ return LZMA_OK;
///////////////
// Variables //
@@ -318,8 +306,12 @@ decode_real(lzma_coder *restrict coder, const uint8_t *restrict in,
// Making local copies of often-used variables improves both
// speed and readability.
+ lzma_dict dict = *dictptr;
+
+ const size_t dict_start = dict.pos;
+
// Range decoder
- rc_to_local(coder->rc);
+ rc_to_local(coder->rc, *in_pos);
// State
uint32_t state = coder->state;
@@ -328,87 +320,168 @@ decode_real(lzma_coder *restrict coder, const uint8_t *restrict in,
uint32_t rep2 = coder->rep2;
uint32_t rep3 = coder->rep3;
- // Misc
- uint32_t now_pos = coder->now_pos;
- bool has_produced_output = coder->has_produced_output;
-
- // Variables derived from decoder settings
const uint32_t pos_mask = coder->pos_mask;
- size_t in_pos_local = *in_pos; // Local copy
- size_t in_limit;
- if (in_size <= REQUIRED_IN_BUFFER_SIZE)
- in_limit = 0;
- else
- in_limit = in_size - REQUIRED_IN_BUFFER_SIZE;
-
-
- while (coder->lz.pos < coder->lz.limit
- && (in_pos_local < in_limit || (has_safe_buffer
- && decode_dummy(coder, in, in_pos_local, in_size,
- rc, state, rep0, now_pos)))) {
-
- /////////////////////
- // Actual decoding //
- /////////////////////
-
- const uint32_t pos_state = now_pos & pos_mask;
+ // These variables are actually needed only if we last time ran
+ // out of input in the middle of the decoder loop.
+ probability *probs = coder->probs;
+ uint32_t symbol = coder->symbol;
+ uint32_t limit = coder->limit;
+ uint32_t offset = coder->offset;
+ uint32_t len = coder->len;
+
+ const uint32_t literal_pos_mask = coder->literal_pos_mask;
+ const uint32_t literal_context_bits = coder->literal_context_bits;
+
+ // Temporary variables
+ uint32_t pos_state = dict.pos & pos_mask;
+
+ lzma_ret ret = LZMA_OK;
+
+ // If uncompressed size is known, there must be no end of payload
+ // marker.
+ const bool no_eopm = coder->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN;
+ if (no_eopm && coder->uncompressed_size < dict.limit - dict.pos)
+ dict.limit = dict.pos + (size_t)(coder->uncompressed_size);
+
+ // The main decoder loop. The "switch" is used to restart the decoder at
+ // correct location. Once restarted, the "switch" is no longer used.
+ switch (coder->sequence)
+ while (true) {
+ // Calculate new pos_state. This is skipped on the first loop
+ // since we already calculated it when setting up the local
+ // variables.
+ pos_state = dict.pos & pos_mask;
+
+ case SEQ_NORMALIZE:
+ case SEQ_IS_MATCH:
+ if (unlikely(no_eopm && dict.pos == dict.limit))
+ break;
- if_bit_0(coder->is_match[state][pos_state]) {
- update_bit_0(coder->is_match[state][pos_state]);
+ rc_if_0(coder->is_match[state][pos_state], SEQ_IS_MATCH) {
+ rc_update_0(coder->is_match[state][pos_state]);
// It's a literal i.e. a single 8-bit byte.
- probability *subcoder = literal_get_subcoder(coder->literal_coder,
- now_pos, lz_get_byte(coder->lz, 0));
- uint32_t symbol = 1;
+ probs = literal_subcoder(coder->literal,
+ literal_context_bits, literal_pos_mask,
+ dict.pos, dict_get(&dict, 0));
+ symbol = 1;
if (is_literal_state(state)) {
// Decode literal without match byte.
+#ifdef HAVE_SMALL
+ case SEQ_LITERAL:
do {
- if_bit_0(subcoder[symbol]) {
- update_bit_0(subcoder[symbol]);
- symbol <<= 1;
- } else {
- update_bit_1(subcoder[symbol]);
- symbol = (symbol << 1) | 1;
- }
- } while (symbol < 0x100);
-
+ rc_bit(probs[symbol], , , SEQ_LITERAL);
+ } while (symbol < (1 << 8));
+#else
+ rc_bit_case(probs[symbol], , , SEQ_LITERAL0);
+ rc_bit_case(probs[symbol], , , SEQ_LITERAL1);
+ rc_bit_case(probs[symbol], , , SEQ_LITERAL2);
+ rc_bit_case(probs[symbol], , , SEQ_LITERAL3);
+ rc_bit_case(probs[symbol], , , SEQ_LITERAL4);
+ rc_bit_case(probs[symbol], , , SEQ_LITERAL5);
+ rc_bit_case(probs[symbol], , , SEQ_LITERAL6);
+ rc_bit_case(probs[symbol], , , SEQ_LITERAL7);
+#endif
} else {
// Decode literal with match byte.
//
- // The usage of subcoder_offset allows omitting some
- // branches, which should give tiny speed improvement on
- // some CPUs. subcoder_offset gets set to zero if match_bit
- // didn't match.
- uint32_t match_byte = lz_get_byte(coder->lz, rep0);
- uint32_t subcoder_offset = 0x100;
-
+ // We store the byte we compare against
+ // ("match byte") to "len" to minimize the
+ // number of variables we need to store
+ // between decoder calls.
+ len = dict_get(&dict, rep0) << 1;
+
+ // The usage of "offset" allows omitting some
+ // branches, which should give tiny speed
+ // improvement on some CPUs. "offset" gets
+ // set to zero if match_bit didn't match.
+ offset = 0x100;
+
+#ifdef HAVE_SMALL
+ case SEQ_LITERAL_MATCHED:
do {
- match_byte <<= 1;
- const uint32_t match_bit = match_byte & subcoder_offset;
+ const uint32_t match_bit
+ = len & offset;
const uint32_t subcoder_index
- = subcoder_offset + match_bit + symbol;
+ = offset + match_bit
+ + symbol;
+
+ rc_bit(probs[subcoder_index],
+ offset &= ~match_bit,
+ offset &= match_bit,
+ SEQ_LITERAL_MATCHED);
+
+ // It seems to be faster to do this
+ // here instead of putting it to the
+ // beginning of the loop and then
+ // putting the "case" in the middle
+ // of the loop.
+ len <<= 1;
+
+ } while (symbol < (1 << 8));
+#else
+ // Unroll the loop.
+ uint32_t match_bit;
+ uint32_t subcoder_index;
+
+# define d(seq) \
+ case seq: \
+ match_bit = len & offset; \
+ subcoder_index = offset + match_bit + symbol; \
+ rc_bit(probs[subcoder_index], \
+ offset &= ~match_bit, \
+ offset &= match_bit, \
+ seq)
+
+ d(SEQ_LITERAL_MATCHED0);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED1);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED2);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED3);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED4);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED5);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED6);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED7);
+# undef d
+#endif
+ }
- if_bit_0(subcoder[subcoder_index]) {
- update_bit_0(subcoder[subcoder_index]);
- symbol <<= 1;
- subcoder_offset &= ~match_bit;
- } else {
- update_bit_1(subcoder[subcoder_index]);
- symbol = (symbol << 1) | 1;
- subcoder_offset &= match_bit;
- }
- } while (symbol < 0x100);
+ //update_literal(state);
+ // Use a lookup table to update to literal state,
+ // since compared to other state updates, this would
+ // need two branches.
+ static const lzma_lzma_state next_state[] = {
+ STATE_LIT_LIT,
+ STATE_LIT_LIT,
+ STATE_LIT_LIT,
+ STATE_LIT_LIT,
+ STATE_MATCH_LIT_LIT,
+ STATE_REP_LIT_LIT,
+ STATE_SHORTREP_LIT_LIT,
+ STATE_MATCH_LIT,
+ STATE_REP_LIT,
+ STATE_SHORTREP_LIT,
+ STATE_MATCH_LIT,
+ STATE_REP_LIT
+ };
+ state = next_state[state];
+
+ case SEQ_LITERAL_WRITE:
+ if (unlikely(dict_put(&dict, symbol))) {
+ coder->sequence = SEQ_LITERAL_WRITE;
+ goto out;
}
- // Put the decoded byte to the dictionary, update the
- // decoder state, and start a new decoding loop.
- coder->lz.dict[coder->lz.pos++] = (uint8_t)(symbol);
- ++now_pos;
- update_literal(state);
- has_produced_output = true;
continue;
}
@@ -416,115 +489,196 @@ decode_real(lzma_coder *restrict coder, const uint8_t *restrict in,
// (distance and length) which will be repeated from our
// output history.
- update_bit_1(coder->is_match[state][pos_state]);
- uint32_t len;
-
- if_bit_0(coder->is_rep[state]) {
- update_bit_0(coder->is_rep[state]);
+ rc_update_1(coder->is_match[state][pos_state]);
+ case SEQ_IS_REP:
+ rc_if_0(coder->is_rep[state], SEQ_IS_REP) {
// Not a repeated match
- //
- // We will decode a new distance and store
- // the value to distance.
-
- // Decode the length of the match.
- length_decode(len, coder->match_len_decoder, pos_state);
-
+ rc_update_0(coder->is_rep[state]);
update_match(state);
- const uint32_t len_to_pos_state = get_len_to_pos_state(len);
- uint32_t pos_slot = 0;
- bittree_decode(pos_slot,
- coder->pos_slot_decoder[len_to_pos_state], POS_SLOT_BITS);
- assert(pos_slot <= 63);
-
- if (pos_slot >= START_POS_MODEL_INDEX) {
- uint32_t direct_bits = (pos_slot >> 1) - 1;
- assert(direct_bits >= 1 && direct_bits <= 30);
- uint32_t distance = 2 | (pos_slot & 1);
-
- if (pos_slot < END_POS_MODEL_INDEX) {
- assert(direct_bits <= 5);
- distance <<= direct_bits;
- assert(distance <= 96);
- // -1 is fine, because
- // bittree_reverse_decode()
- // starts from table index [1]
- // (not [0]).
- assert((int32_t)(distance - pos_slot - 1) >= -1);
- assert((int32_t)(distance - pos_slot - 1) <= 82);
- // We add the result to distance, so distance
- // must not be part of second argument
- // of the macro.
- const int32_t offset = distance - pos_slot - 1;
- bittree_reverse_decode(distance, coder->pos_decoders + offset,
- direct_bits);
+ // The latest three match distances are kept in
+ // memory in case there are repeated matches.
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+
+ // Decode the length of the match.
+ len_decode(len, coder->match_len_decoder,
+ pos_state, SEQ_MATCH_LEN);
+
+ // Prepare to decode the highest two bits of the
+ // match distance.
+ probs = coder->pos_slot[get_len_to_pos_state(len)];
+ symbol = 1;
+
+#ifdef HAVE_SMALL
+ case SEQ_POS_SLOT:
+ do {
+ rc_bit(probs[symbol], , , SEQ_POS_SLOT);
+ } while (symbol < POS_SLOTS);
+#else
+ rc_bit_case(probs[symbol], , , SEQ_POS_SLOT0);
+ rc_bit_case(probs[symbol], , , SEQ_POS_SLOT1);
+ rc_bit_case(probs[symbol], , , SEQ_POS_SLOT2);
+ rc_bit_case(probs[symbol], , , SEQ_POS_SLOT3);
+ rc_bit_case(probs[symbol], , , SEQ_POS_SLOT4);
+ rc_bit_case(probs[symbol], , , SEQ_POS_SLOT5);
+#endif
+ // Get rid of the highest bit that was needed for
+ // indexing of the probability array.
+ symbol -= POS_SLOTS;
+ assert(symbol <= 63);
+
+ if (symbol < START_POS_MODEL_INDEX) {
+ // Match distances [0, 3] have only two bits.
+ rep0 = symbol;
+ } else {
+ // Decode the lowest [1, 29] bits of
+ // the match distance.
+ limit = (symbol >> 1) - 1;
+ assert(limit >= 1 && limit <= 30);
+ rep0 = 2 + (symbol & 1);
+
+ if (symbol < END_POS_MODEL_INDEX) {
+ // Prepare to decode the low bits for
+ // a distance of [4, 127].
+ assert(limit <= 5);
+ rep0 <<= limit;
+ assert(rep0 <= 96);
+ // -1 is fine, because we start
+ // decoding at probs[1], not probs[0].
+ // NOTE: This violates the C standard,
+ // since we are doing pointer
+ // arithmetic past the beginning of
+ // the array.
+ assert((int32_t)(rep0 - symbol - 1)
+ >= -1);
+ assert((int32_t)(rep0 - symbol - 1)
+ <= 82);
+ probs = coder->pos_special + rep0
+ - symbol - 1;
+ symbol = 1;
+ offset = 0;
+ case SEQ_POS_MODEL:
+#ifdef HAVE_SMALL
+ do {
+ rc_bit(probs[symbol], ,
+ rep0 += 1 << offset,
+ SEQ_POS_MODEL);
+ } while (++offset < limit);
+#else
+ switch (limit) {
+ case 5:
+ assert(offset == 0);
+ rc_bit(probs[symbol], ,
+ rep0 += 1,
+ SEQ_POS_MODEL);
+ ++offset;
+ --limit;
+ case 4:
+ rc_bit(probs[symbol], ,
+ rep0 += 1 << offset,
+ SEQ_POS_MODEL);
+ ++offset;
+ --limit;
+ case 3:
+ rc_bit(probs[symbol], ,
+ rep0 += 1 << offset,
+ SEQ_POS_MODEL);
+ ++offset;
+ --limit;
+ case 2:
+ rc_bit(probs[symbol], ,
+ rep0 += 1 << offset,
+ SEQ_POS_MODEL);
+ ++offset;
+ --limit;
+ case 1:
+ // We need "symbol" only for
+ // indexing the probability
+ // array, thus we can use
+ // rc_bit_last() here to omit
+ // the unneeded updating of
+ // "symbol".
+ rc_bit_last(probs[symbol], ,
+ rep0 += 1 << offset,
+ SEQ_POS_MODEL);
+ }
+#endif
} else {
- assert(pos_slot >= 14);
- assert(direct_bits >= 6);
- direct_bits -= ALIGN_BITS;
- assert(direct_bits >= 2);
- rc_decode_direct(distance, direct_bits);
- distance <<= ALIGN_BITS;
-
- bittree_reverse_decode(distance, coder->pos_align_decoder,
- ALIGN_BITS);
-
- if (distance == UINT32_MAX) {
- if (len == LEN_SPECIAL_EOPM) {
- // End of Payload Marker found.
- coder->lz.eopm_detected = true;
- break;
-
- } else if (len == LEN_SPECIAL_FLUSH) {
- // Flush marker detected. We must have produced
- // at least one byte of output since the previous
- // flush marker or the beginning of the stream.
- // This is to prevent hanging the decoder with
- // malicious input files.
- if (!has_produced_output)
- return true;
-
- has_produced_output = false;
-
- // We know that we have enough input to call
- // this macro, because it is tested at the
- // end of decode_dummy().
- rc_normalize();
-
- rc_reset(rc);
-
- // If we don't have enough input here, we jump
- // out of the loop. Note that while there is a
- // useless call to rc_normalize(), it does nothing
- // since we have just reset the range decoder.
- if (!rc_read_init(&rc, in, &in_pos_local, in_size))
- break;
-
- continue;
-
- } else {
- return true;
+ // The distace is >= 128. Decode the
+ // lower bits without probabilities
+ // except the lowest four bits.
+ assert(symbol >= 14);
+ assert(limit >= 6);
+ limit -= ALIGN_BITS;
+ assert(limit >= 2);
+ case SEQ_DIRECT:
+ // Not worth manual unrolling
+ do {
+ rc_direct(rep0, SEQ_DIRECT);
+ } while (--limit > 0);
+
+ // Decode the lowest four bits using
+ // probabilities.
+ rep0 <<= ALIGN_BITS;
+ symbol = 1;
+#ifdef HAVE_SMALL
+ offset = 0;
+ case SEQ_ALIGN:
+ do {
+ rc_bit(coder->pos_align[
+ symbol], ,
+ rep0 += 1 << offset,
+ SEQ_ALIGN);
+ } while (++offset < ALIGN_BITS);
+#else
+ case SEQ_ALIGN0:
+ rc_bit(coder->pos_align[symbol], ,
+ rep0 += 1, SEQ_ALIGN0);
+ case SEQ_ALIGN1:
+ rc_bit(coder->pos_align[symbol], ,
+ rep0 += 2, SEQ_ALIGN1);
+ case SEQ_ALIGN2:
+ rc_bit(coder->pos_align[symbol], ,
+ rep0 += 4, SEQ_ALIGN2);
+ case SEQ_ALIGN3:
+ // Like in SEQ_POS_MODEL, we don't
+ // need "symbol" for anything else
+ // than indexing the probability array.
+ rc_bit_last(coder->pos_align[symbol], ,
+ rep0 += 8, SEQ_ALIGN3);
+#endif
+
+ if (rep0 == UINT32_MAX) {
+ // End of payload marker was
+ // found. It must not be
+ // present if uncompressed
+ // size is known.
+ if (coder->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN) {
+ ret = LZMA_DATA_ERROR;
+ goto out;
}
+
+ case SEQ_EOPM:
+ // TODO Comment
+ rc_normalize(SEQ_EOPM);
+ ret = LZMA_STREAM_END;
+ goto out;
}
}
+ }
- // The latest three match distances are kept in
- // memory in case there are repeated matches.
- rep3 = rep2;
- rep2 = rep1;
- rep1 = rep0;
- rep0 = distance;
-
- } else {
- rep3 = rep2;
- rep2 = rep1;
- rep1 = rep0;
- rep0 = pos_slot;
+ // Validate the distance we just decoded.
+ if (unlikely(!dict_is_distance_valid(&dict, rep0))) {
+ ret = LZMA_DATA_ERROR;
+ goto out;
}
} else {
- update_bit_1(coder->is_rep[state]);
+ rc_update_1(coder->is_rep[state]);
// Repeated match
//
@@ -532,242 +686,318 @@ decode_real(lzma_coder *restrict coder, const uint8_t *restrict in,
// earlier. The latest four match distances are
// available as rep0, rep1, rep2 and rep3. We will
// now decode which of them is the new distance.
+ //
+ // There cannot be a match if we haven't produced
+ // any output, so check that first.
+ if (unlikely(!dict_is_distance_valid(&dict, 0))) {
+ ret = LZMA_DATA_ERROR;
+ goto out;
+ }
- if_bit_0(coder->is_rep0[state]) {
- update_bit_0(coder->is_rep0[state]);
-
+ case SEQ_IS_REP0:
+ rc_if_0(coder->is_rep0[state], SEQ_IS_REP0) {
+ rc_update_0(coder->is_rep0[state]);
// The distance is rep0.
- if_bit_0(coder->is_rep0_long[state][pos_state]) {
- update_bit_0(coder->is_rep0_long[state][pos_state]);
+ case SEQ_IS_REP0_LONG:
+ rc_if_0(coder->is_rep0_long[state][pos_state],
+ SEQ_IS_REP0_LONG) {
+ rc_update_0(coder->is_rep0_long[
+ state][pos_state]);
update_short_rep(state);
- // Repeat exactly one byte and start a new decoding loop.
- // Note that rep0 is known to have a safe value, thus we
- // don't need to check if we are wrapping the dictionary
- // when it isn't full yet.
- if (unlikely(lz_is_empty(coder->lz)))
- return true;
-
- coder->lz.dict[coder->lz.pos]
- = lz_get_byte(coder->lz, rep0);
- ++coder->lz.pos;
- ++now_pos;
- has_produced_output = true;
- continue;
-
- } else {
- update_bit_1(coder->is_rep0_long[state][pos_state]);
+ case SEQ_SHORTREP:
+ if (unlikely(dict_put(&dict, dict_get(
+ &dict, rep0)))) {
+ coder->sequence = SEQ_SHORTREP;
+ goto out;
+ }
- // Repeating more than one byte at
- // distance of rep0.
+ continue;
}
+ // Repeating more than one byte at
+ // distance of rep0.
+ rc_update_1(coder->is_rep0_long[
+ state][pos_state]);
+
} else {
- update_bit_1(coder->is_rep0[state]);
+ rc_update_1(coder->is_rep0[state]);
+ case SEQ_IS_REP1:
// The distance is rep1, rep2 or rep3. Once
// we find out which one of these three, it
// is stored to rep0 and rep1, rep2 and rep3
// are updated accordingly.
+ rc_if_0(coder->is_rep1[state], SEQ_IS_REP1) {
+ rc_update_0(coder->is_rep1[state]);
- uint32_t distance;
+ const uint32_t distance = rep1;
+ rep1 = rep0;
+ rep0 = distance;
- if_bit_0(coder->is_rep1[state]) {
- update_bit_0(coder->is_rep1[state]);
- distance = rep1;
} else {
- update_bit_1(coder->is_rep1[state]);
+ rc_update_1(coder->is_rep1[state]);
+ case SEQ_IS_REP2:
+ rc_if_0(coder->is_rep2[state],
+ SEQ_IS_REP2) {
+ rc_update_0(coder->is_rep2[
+ state]);
+
+ const uint32_t distance = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance;
- if_bit_0(coder->is_rep2[state]) {
- update_bit_0(coder->is_rep2[state]);
- distance = rep2;
} else {
- update_bit_1(coder->is_rep2[state]);
- distance = rep3;
+ rc_update_1(coder->is_rep2[
+ state]);
+
+ const uint32_t distance = rep3;
rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance;
}
-
- rep2 = rep1;
}
-
- rep1 = rep0;
- rep0 = distance;
}
update_long_rep(state);
// Decode the length of the repeated match.
- length_decode(len, coder->rep_len_decoder, pos_state);
+ len_decode(len, coder->rep_len_decoder,
+ pos_state, SEQ_REP_LEN);
}
-
/////////////////////////////////
// Repeat from history buffer. //
/////////////////////////////////
// The length is always between these limits. There is no way
// to trigger the algorithm to set len outside this range.
- assert(len >= MATCH_MIN_LEN);
- assert(len <= MATCH_MAX_LEN);
-
- now_pos += len;
- has_produced_output = true;
+ assert(len >= MATCH_LEN_MIN);
+ assert(len <= MATCH_LEN_MAX);
+ case SEQ_COPY:
// Repeat len bytes from distance of rep0.
- if (!lzma_lz_out_repeat(&coder->lz, rep0, len))
- return true;
+ if (unlikely(dict_repeat(&dict, rep0, &len))) {
+ coder->sequence = SEQ_COPY;
+ goto out;
+ }
}
- rc_normalize();
+ rc_normalize(SEQ_NORMALIZE);
+ coder->sequence = SEQ_IS_MATCH;
+out:
+ // Save state
- /////////////////////////////////
- // Update the *data structure. //
- /////////////////////////////////
+ // NOTE: Must not copy dict.limit.
+ dictptr->pos = dict.pos;
+ dictptr->full = dict.full;
- // Range decoder
- rc_from_local(coder->rc);
+ rc_from_local(coder->rc, *in_pos);
- // State
coder->state = state;
coder->rep0 = rep0;
coder->rep1 = rep1;
coder->rep2 = rep2;
coder->rep3 = rep3;
- // Misc
- coder->now_pos = now_pos;
- coder->has_produced_output = has_produced_output;
- *in_pos = in_pos_local;
+ coder->probs = probs;
+ coder->symbol = symbol;
+ coder->limit = limit;
+ coder->offset = offset;
+ coder->len = len;
+
+ // Update the remaining amount of uncompressed data if uncompressed
+ // size was known.
+ if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
+ coder->uncompressed_size -= dict.pos - dict_start;
+
+ // Since there cannot be end of payload marker if the
+ // uncompressed size was known, we check here if we
+ // finished decoding.
+ if (coder->uncompressed_size == 0 && ret == LZMA_OK
+ && coder->sequence != SEQ_NORMALIZE)
+ ret = coder->sequence == SEQ_IS_MATCH
+ ? LZMA_STREAM_END : LZMA_DATA_ERROR;
+ }
+
+ // We can do an additional check in the range decoder to catch some
+ // corrupted files.
+ if (ret == LZMA_STREAM_END) {
+ if (!rc_is_finished(coder->rc))
+ ret = LZMA_DATA_ERROR;
- return false;
+ // Reset the range decoder so that it is ready to reinitialize
+ // for a new LZMA2 chunk.
+ rc_reset(coder->rc);
+ }
+
+ return ret;
}
+
static void
-lzma_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+lzma_decoder_uncompressed(lzma_coder *coder, lzma_vli uncompressed_size)
{
- lzma_next_coder_end(&coder->next, allocator);
- lzma_lz_decoder_end(&coder->lz, allocator);
- lzma_free(coder, allocator);
- return;
+ coder->uncompressed_size = uncompressed_size;
}
-
-extern lzma_ret
-lzma_lzma_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
- const lzma_filter_info *filters)
+/*
+extern void
+lzma_lzma_decoder_uncompressed(void *coder_ptr, lzma_vli uncompressed_size)
{
- // LZMA can only be the last filter in the chain.
- assert(filters[1].init == NULL);
-
- // Validate pos_bits. Other options are validated by the
- // respective initialization functions.
- const lzma_options_lzma *options = filters[0].options;
- if (options->pos_bits > LZMA_POS_BITS_MAX)
- return LZMA_HEADER_ERROR;
+ // This is hack.
+ (*(lzma_coder **)(coder))->uncompressed_size = uncompressed_size;
+}
+*/
- // Allocate memory for the decoder if needed.
- if (next->coder == NULL) {
- next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
- if (next->coder == NULL)
- return LZMA_MEM_ERROR;
+static void
+lzma_decoder_reset(lzma_coder *coder, const void *opt)
+{
+ const lzma_options_lzma *options = opt;
- next->code = &lzma_lz_decode;
- next->end = &lzma_decoder_end;
- next->coder->next = LZMA_NEXT_CODER_INIT;
- next->coder->lz = LZMA_LZ_DECODER_INIT;
- }
+ // NOTE: We assume that lc/lp/pb are valid since they were
+ // successfully decoded with lzma_lzma_decode_properties().
+ // FIXME?
- // Store the pos_bits and calculate pos_mask.
- next->coder->pos_bits = options->pos_bits;
- next->coder->pos_mask = (1U << next->coder->pos_bits) - 1;
+ // Calculate pos_mask. We don't need pos_bits as is for anything.
+ coder->pos_mask = (1U << options->pos_bits) - 1;
// Initialize the literal decoder.
- return_if_error(lzma_literal_init(&next->coder->literal_coder,
- options->literal_context_bits,
- options->literal_pos_bits));
+ literal_init(coder->literal, options->literal_context_bits,
+ options->literal_pos_bits);
- // Allocate and initialize the LZ decoder.
- return_if_error(lzma_lz_decoder_reset(&next->coder->lz, allocator,
- &decode_real, options->dictionary_size,
- MATCH_MAX_LEN));
+ coder->literal_context_bits = options->literal_context_bits;
+ coder->literal_pos_mask = (1 << options->literal_pos_bits) - 1;
// State
- next->coder->state = 0;
- next->coder->rep0 = 0;
- next->coder->rep1 = 0;
- next->coder->rep2 = 0;
- next->coder->rep3 = 0;
- next->coder->pos_bits = options->pos_bits;
- next->coder->pos_mask = (1 << next->coder->pos_bits) - 1;
- next->coder->now_pos = 0;
+ coder->state = STATE_LIT_LIT;
+ coder->rep0 = 0;
+ coder->rep1 = 0;
+ coder->rep2 = 0;
+ coder->rep3 = 0;
+ coder->pos_mask = (1 << options->pos_bits) - 1;
// Range decoder
- rc_reset(next->coder->rc);
+ rc_reset(coder->rc);
// Bit and bittree decoders
for (uint32_t i = 0; i < STATES; ++i) {
- for (uint32_t j = 0; j <= next->coder->pos_mask; ++j) {
- bit_reset(next->coder->is_match[i][j]);
- bit_reset(next->coder->is_rep0_long[i][j]);
+ for (uint32_t j = 0; j <= coder->pos_mask; ++j) {
+ bit_reset(coder->is_match[i][j]);
+ bit_reset(coder->is_rep0_long[i][j]);
}
- bit_reset(next->coder->is_rep[i]);
- bit_reset(next->coder->is_rep0[i]);
- bit_reset(next->coder->is_rep1[i]);
- bit_reset(next->coder->is_rep2[i]);
+ bit_reset(coder->is_rep[i]);
+ bit_reset(coder->is_rep0[i]);
+ bit_reset(coder->is_rep1[i]);
+ bit_reset(coder->is_rep2[i]);
}
for (uint32_t i = 0; i < LEN_TO_POS_STATES; ++i)
- bittree_reset(next->coder->pos_slot_decoder[i], POS_SLOT_BITS);
+ bittree_reset(coder->pos_slot[i], POS_SLOT_BITS);
for (uint32_t i = 0; i < FULL_DISTANCES - END_POS_MODEL_INDEX; ++i)
- bit_reset(next->coder->pos_decoders[i]);
+ bit_reset(coder->pos_special[i]);
- bittree_reset(next->coder->pos_align_decoder, ALIGN_BITS);
+ bittree_reset(coder->pos_align, ALIGN_BITS);
// Len decoders (also bit/bittree)
- const uint32_t num_pos_states = 1 << next->coder->pos_bits;
- bit_reset(next->coder->match_len_decoder.choice);
- bit_reset(next->coder->match_len_decoder.choice2);
- bit_reset(next->coder->rep_len_decoder.choice);
- bit_reset(next->coder->rep_len_decoder.choice2);
+ const uint32_t num_pos_states = 1 << options->pos_bits;
+ bit_reset(coder->match_len_decoder.choice);
+ bit_reset(coder->match_len_decoder.choice2);
+ bit_reset(coder->rep_len_decoder.choice);
+ bit_reset(coder->rep_len_decoder.choice2);
for (uint32_t pos_state = 0; pos_state < num_pos_states; ++pos_state) {
- bittree_reset(next->coder->match_len_decoder.low[pos_state],
+ bittree_reset(coder->match_len_decoder.low[pos_state],
LEN_LOW_BITS);
- bittree_reset(next->coder->match_len_decoder.mid[pos_state],
+ bittree_reset(coder->match_len_decoder.mid[pos_state],
LEN_MID_BITS);
- bittree_reset(next->coder->rep_len_decoder.low[pos_state],
+ bittree_reset(coder->rep_len_decoder.low[pos_state],
LEN_LOW_BITS);
- bittree_reset(next->coder->rep_len_decoder.mid[pos_state],
+ bittree_reset(coder->rep_len_decoder.mid[pos_state],
LEN_MID_BITS);
}
- bittree_reset(next->coder->match_len_decoder.high, LEN_HIGH_BITS);
- bittree_reset(next->coder->rep_len_decoder.high, LEN_HIGH_BITS);
+ bittree_reset(coder->match_len_decoder.high, LEN_HIGH_BITS);
+ bittree_reset(coder->rep_len_decoder.high, LEN_HIGH_BITS);
+
+ coder->sequence = SEQ_IS_MATCH;
+ coder->probs = NULL;
+ coder->symbol = 0;
+ coder->limit = 0;
+ coder->offset = 0;
+ coder->len = 0;
+
+ return;
+}
+
+
+extern lzma_ret
+lzma_lzma_decoder_create(lzma_lz_decoder *lz, lzma_allocator *allocator,
+ const void *opt, size_t *dict_size)
+{
+ if (lz->coder == NULL) {
+ lz->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (lz->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ lz->code = &lzma_decode;
+ lz->reset = &lzma_decoder_reset;
+ lz->set_uncompressed = &lzma_decoder_uncompressed;
+ }
- next->coder->has_produced_output = false;
+ // All dictionary sizes are OK here. LZ decoder will take care of
+ // the special cases.
+ const lzma_options_lzma *options = opt;
+ *dict_size = options->dictionary_size;
return LZMA_OK;
}
-extern void
-lzma_lzma_decoder_uncompressed_size(
- lzma_next_coder *next, lzma_vli uncompressed_size)
+/// Allocate and initialize LZMA decoder. This is used only via LZ
+/// initialization (lzma_lzma_decoder_init() passes function pointer to
+/// the LZ initialization).
+static lzma_ret
+lzma_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator,
+ const void *options, size_t *dict_size)
{
- next->coder->lz.uncompressed_size = uncompressed_size;
- return;
+ if (!is_lclppb_valid(options))
+ return LZMA_PROG_ERROR;
+
+ return_if_error(lzma_lzma_decoder_create(
+ lz, allocator, options, dict_size));
+
+ lzma_decoder_reset(lz->coder, options);
+ lzma_decoder_uncompressed(lz->coder, LZMA_VLI_VALUE_UNKNOWN);
+
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_lzma_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ // LZMA can only be the last filter in the chain. This is enforced
+ // by the raw_decoder initialization.
+ assert(filters[1].init == NULL);
+
+ return lzma_lz_decoder_init(next, allocator, filters,
+ &lzma_decoder_init);
}
extern bool
-lzma_lzma_decode_properties(lzma_options_lzma *options, uint8_t byte)
+lzma_lzma_lclppb_decode(lzma_options_lzma *options, uint8_t byte)
{
if (byte > (4 * 5 + 4) * 9 + 8)
return true;
@@ -781,3 +1011,49 @@ lzma_lzma_decode_properties(lzma_options_lzma *options, uint8_t byte)
return options->literal_context_bits + options->literal_pos_bits
> LZMA_LITERAL_BITS_MAX;
}
+
+
+extern uint64_t
+lzma_lzma_decoder_memusage(const void *options)
+{
+ const lzma_options_lzma *const opt = options;
+ const uint64_t lz_memusage
+ = lzma_lz_decoder_memusage(opt->dictionary_size);
+ if (lz_memusage == UINT64_MAX)
+ return UINT64_MAX;
+
+ return sizeof(lzma_coder) + lz_memusage;
+}
+
+
+extern lzma_ret
+lzma_lzma_props_decode(void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size)
+{
+ if (props_size != 5)
+ return LZMA_HEADER_ERROR;
+
+ lzma_options_lzma *opt
+ = lzma_alloc(sizeof(lzma_options_lzma), allocator);
+ if (opt == NULL)
+ return LZMA_MEM_ERROR;
+
+ if (lzma_lzma_lclppb_decode(opt, props[0]))
+ goto error;
+
+ // All dictionary sizes are accepted, including zero. LZ decoder
+ // will automatically use a dictionary at least a few KiB even if
+ // a smaller dictionary is requested.
+ opt->dictionary_size = integer_read_32(props + 1);
+
+ opt->preset_dictionary = NULL;
+ opt->preset_dictionary_size = 0;
+
+ *options = opt;
+
+ return LZMA_OK;
+
+error:
+ lzma_free(opt, allocator);
+ return LZMA_HEADER_ERROR;
+}
diff --git a/src/liblzma/lzma/lzma_decoder.h b/src/liblzma/lzma/lzma_decoder.h
index 9d57c7e5..3792f452 100644
--- a/src/liblzma/lzma/lzma_decoder.h
+++ b/src/liblzma/lzma/lzma_decoder.h
@@ -28,16 +28,27 @@
extern lzma_ret lzma_lzma_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
-/// Set known uncompressed size. This is a hack needed to support
-/// LZMA_Alone files that don't have EOPM.
-extern void lzma_lzma_decoder_uncompressed_size(
- lzma_next_coder *next, lzma_vli uncompressed_size);
+extern uint64_t lzma_lzma_decoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma_props_decode(
+ void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size);
+
/// \brief Decodes the LZMA Properties byte (lc/lp/pb)
///
/// \return true if error occorred, false on success
///
-extern bool lzma_lzma_decode_properties(
+extern bool lzma_lzma_lclppb_decode(
lzma_options_lzma *options, uint8_t byte);
+
+#ifdef LZMA_LZ_DECODER_H
+/// Allocate and setup function pointers only. This is used by LZMA1 and
+/// LZMA2 decoders.
+extern lzma_ret lzma_lzma_decoder_create(
+ lzma_lz_decoder *lz, lzma_allocator *allocator,
+ const void *opt, size_t *dict_size);
+#endif
+
#endif
diff --git a/src/liblzma/lzma/lzma_encoder.c b/src/liblzma/lzma/lzma_encoder.c
index afb1d5ed..a84801e7 100644
--- a/src/liblzma/lzma/lzma_encoder.c
+++ b/src/liblzma/lzma/lzma_encoder.c
@@ -30,40 +30,33 @@ static inline void
literal_matched(lzma_range_encoder *rc, probability *subcoder,
uint32_t match_byte, uint32_t symbol)
{
- uint32_t context = 1;
- uint32_t bit_count = 8;
+ uint32_t offset = 0x100;
+ symbol += UINT32_C(1) << 8;
do {
- uint32_t bit = (symbol >> --bit_count) & 1;
- const uint32_t match_bit = (match_byte >> bit_count) & 1;
- rc_bit(rc, &subcoder[(0x100 << match_bit) + context], bit);
- context = (context << 1) | bit;
-
- if (match_bit != bit) {
- // The bit from the literal being encoded and the bit
- // from the previous match differ. Finish encoding
- // as a normal literal.
- while (bit_count != 0) {
- bit = (symbol >> --bit_count) & 1;
- rc_bit(rc, &subcoder[context], bit);
- context = (context << 1) | bit;
- }
+ match_byte <<= 1;
+ const uint32_t match_bit = match_byte & offset;
+ const uint32_t subcoder_index
+ = offset + match_bit + (symbol >> 8);
+ const uint32_t bit = (symbol >> 7) & 1;
+ rc_bit(rc, &subcoder[subcoder_index], bit);
- break;
- }
+ symbol <<= 1;
+ offset &= ~(match_byte ^ symbol);
- } while (bit_count != 0);
+ } while (symbol < (UINT32_C(1) << 16));
}
static inline void
-literal(lzma_coder *coder)
+literal(lzma_coder *coder, lzma_mf *mf, uint32_t position)
{
// Locate the literal byte to be encoded and the subcoder.
- const uint8_t cur_byte = coder->lz.buffer[
- coder->lz.read_pos - coder->additional_offset];
- probability *subcoder = literal_get_subcoder(coder->literal_coder,
- coder->now_pos, coder->previous_byte);
+ const uint8_t cur_byte = mf->buffer[
+ mf->read_pos - mf->read_ahead];
+ probability *subcoder = literal_subcoder(coder->literal,
+ coder->literal_context_bits, coder->literal_pos_mask,
+ position, mf->buffer[mf->read_pos - mf->read_ahead - 1]);
if (is_literal_state(coder->state)) {
// Previous LZMA-symbol was a literal. Encode a normal
@@ -73,14 +66,13 @@ literal(lzma_coder *coder)
// Previous LZMA-symbol was a match. Use the last byte of
// the match as a "match byte". That is, compare the bits
// of the current literal and the match byte.
- const uint8_t match_byte = coder->lz.buffer[
- coder->lz.read_pos - coder->reps[0] - 1
- - coder->additional_offset];
+ const uint8_t match_byte = mf->buffer[
+ mf->read_pos - coder->reps[0] - 1
+ - mf->read_ahead];
literal_matched(&coder->rc, subcoder, match_byte, cur_byte);
}
update_literal(coder->state);
- coder->previous_byte = cur_byte;
}
@@ -88,12 +80,41 @@ literal(lzma_coder *coder)
// Match length //
//////////////////
+static void
+length_update_prices(lzma_length_encoder *lc, const uint32_t pos_state)
+{
+ const uint32_t table_size = lc->table_size;
+ lc->counters[pos_state] = table_size;
+
+ const uint32_t a0 = rc_bit_0_price(lc->choice);
+ const uint32_t a1 = rc_bit_1_price(lc->choice);
+ const uint32_t b0 = a1 + rc_bit_0_price(lc->choice2);
+ const uint32_t b1 = a1 + rc_bit_1_price(lc->choice2);
+ uint32_t *const prices = lc->prices[pos_state];
+
+ uint32_t i;
+ for (i = 0; i < table_size && i < LEN_LOW_SYMBOLS; ++i)
+ prices[i] = a0 + rc_bittree_price(lc->low[pos_state],
+ LEN_LOW_BITS, i);
+
+ for (; i < table_size && i < LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; ++i)
+ prices[i] = b0 + rc_bittree_price(lc->mid[pos_state],
+ LEN_MID_BITS, i - LEN_LOW_SYMBOLS);
+
+ for (; i < table_size; ++i)
+ prices[i] = b1 + rc_bittree_price(lc->high, LEN_HIGH_BITS,
+ i - LEN_LOW_SYMBOLS - LEN_MID_SYMBOLS);
+
+ return;
+}
+
+
static inline void
length(lzma_range_encoder *rc, lzma_length_encoder *lc,
- const uint32_t pos_state, uint32_t len)
+ const uint32_t pos_state, uint32_t len, const bool fast_mode)
{
- assert(len <= MATCH_MAX_LEN);
- len -= MATCH_MIN_LEN;
+ assert(len <= MATCH_LEN_MAX);
+ len -= MATCH_LEN_MIN;
if (len < LEN_LOW_SYMBOLS) {
rc_bit(rc, &lc->choice, 0);
@@ -111,6 +132,12 @@ length(lzma_range_encoder *rc, lzma_length_encoder *lc,
rc_bittree(rc, lc->high, LEN_HIGH_BITS, len);
}
}
+
+ // Only getoptimum uses the prices so don't update the table when
+ // in fast mode.
+ if (!fast_mode)
+ if (--lc->counters[pos_state] == 0)
+ length_update_prices(lc, pos_state);
}
@@ -124,12 +151,12 @@ match(lzma_coder *coder, const uint32_t pos_state,
{
update_match(coder->state);
- length(&coder->rc, &coder->match_len_encoder, pos_state, len);
- coder->prev_len_encoder = &coder->match_len_encoder;
+ length(&coder->rc, &coder->match_len_encoder, pos_state, len,
+ coder->fast_mode);
const uint32_t pos_slot = get_pos_slot(distance);
const uint32_t len_to_pos_state = get_len_to_pos_state(len);
- rc_bittree(&coder->rc, coder->pos_slot_encoder[len_to_pos_state],
+ rc_bittree(&coder->rc, coder->pos_slot[len_to_pos_state],
POS_SLOT_BITS, pos_slot);
if (pos_slot >= START_POS_MODEL_INDEX) {
@@ -139,13 +166,13 @@ match(lzma_coder *coder, const uint32_t pos_state,
if (pos_slot < END_POS_MODEL_INDEX) {
rc_bittree_reverse(&coder->rc,
- &coder->pos_encoders[base - pos_slot - 1],
+ &coder->pos_special[base - pos_slot - 1],
footer_bits, pos_reduced);
} else {
rc_direct(&coder->rc, pos_reduced >> ALIGN_BITS,
footer_bits - ALIGN_BITS);
rc_bittree_reverse(
- &coder->rc, coder->pos_align_encoder,
+ &coder->rc, coder->pos_align,
ALIGN_BITS, pos_reduced & ALIGN_MASK);
++coder->align_price_count;
}
@@ -196,8 +223,8 @@ rep_match(lzma_coder *coder, const uint32_t pos_state,
if (len == 1) {
update_short_rep(coder->state);
} else {
- length(&coder->rc, &coder->rep_len_encoder, pos_state, len);
- coder->prev_len_encoder = &coder->rep_len_encoder;
+ length(&coder->rc, &coder->rep_len_encoder, pos_state, len,
+ coder->fast_mode);
update_long_rep(coder->state);
}
}
@@ -208,117 +235,123 @@ rep_match(lzma_coder *coder, const uint32_t pos_state,
//////////
static void
-encode_symbol(lzma_coder *coder, uint32_t pos, uint32_t len)
+encode_symbol(lzma_coder *coder, lzma_mf *mf,
+ uint32_t back, uint32_t len, uint32_t position)
{
- const uint32_t pos_state = coder->now_pos & coder->pos_mask;
+ const uint32_t pos_state = position & coder->pos_mask;
- if (len == 1 && pos == UINT32_MAX) {
+ if (back == UINT32_MAX) {
// Literal i.e. eight-bit byte
+ assert(len == 1);
rc_bit(&coder->rc,
&coder->is_match[coder->state][pos_state], 0);
- literal(coder);
+ literal(coder, mf, position);
} else {
// Some type of match
rc_bit(&coder->rc,
&coder->is_match[coder->state][pos_state], 1);
- if (pos < REP_DISTANCES) {
+ if (back < REP_DISTANCES) {
// It's a repeated match i.e. the same distance
// has been used earlier.
rc_bit(&coder->rc, &coder->is_rep[coder->state], 1);
- rep_match(coder, pos_state, pos, len);
+ rep_match(coder, pos_state, back, len);
} else {
// Normal match
rc_bit(&coder->rc, &coder->is_rep[coder->state], 0);
- match(coder, pos_state, pos - REP_DISTANCES, len);
+ match(coder, pos_state, back - REP_DISTANCES, len);
}
+ }
+
+ assert(mf->read_ahead >= len);
+ mf->read_ahead -= len;
+}
+
+
+static bool
+encode_init(lzma_coder *coder, lzma_mf *mf)
+{
+ if (mf->read_pos == mf->read_limit) {
+ if (mf->action == LZMA_RUN)
+ return false; // We cannot do anything.
- coder->previous_byte = coder->lz.buffer[
- coder->lz.read_pos + len - 1
- - coder->additional_offset];
+ // We are finishing (we cannot get here when flushing).
+ assert(mf->write_pos == mf->read_pos);
+ assert(mf->action == LZMA_FINISH);
+ } else {
+ // Do the actual initialization. The first LZMA symbol must
+ // always be a literal.
+ mf_skip(mf, 1);
+ mf->read_ahead = 0;
+ rc_bit(&coder->rc, &coder->is_match[0][0], 0);
+ rc_bittree(&coder->rc, coder->literal[0], 8, mf->buffer[0]);
}
- assert(coder->additional_offset >= len);
- coder->additional_offset -= len;
- coder->now_pos += len;
+ // Initialization is done (except if empty file).
+ coder->is_initialized = true;
+
+ return true;
}
static void
-encode_eopm(lzma_coder *coder)
+encode_eopm(lzma_coder *coder, uint32_t position)
{
- const uint32_t pos_state = coder->now_pos & coder->pos_mask;
+ const uint32_t pos_state = position & coder->pos_mask;
rc_bit(&coder->rc, &coder->is_match[coder->state][pos_state], 1);
rc_bit(&coder->rc, &coder->is_rep[coder->state], 0);
- match(coder, pos_state, UINT32_MAX, MATCH_MIN_LEN);
+ match(coder, pos_state, UINT32_MAX, MATCH_LEN_MIN);
}
-/**
- * \brief LZMA encoder
- *
- * \return true if end of stream was reached, false otherwise.
- */
-extern bool
-lzma_lzma_encode(lzma_coder *coder, uint8_t *restrict out,
- size_t *restrict out_pos, size_t out_size)
+/// Number of bytes that a single encoding loop in lzma_lzma_encode() can
+/// consume from the dictionary. This limit comes from lzma_lzma_optimum()
+/// and may need to be updated if that function is significantly modified.
+#define LOOP_INPUT_MAX (OPTS + 1)
+
+
+extern lzma_ret
+lzma_lzma_encode(lzma_coder *restrict coder, lzma_mf *restrict mf,
+ uint8_t *restrict out, size_t *restrict out_pos,
+ size_t out_size, uint32_t limit)
{
// Initialize the stream if no data has been encoded yet.
- if (!coder->is_initialized) {
- if (coder->lz.read_pos == coder->lz.read_limit) {
- if (coder->lz.sequence == SEQ_RUN)
- return false; // We cannot do anything.
-
- // We are finishing (we cannot get here when flushing).
- assert(coder->lz.write_pos == coder->lz.read_pos);
- assert(coder->lz.sequence == SEQ_FINISH);
- } else {
- // Do the actual initialization.
- uint32_t len;
- uint32_t num_distance_pairs;
- lzma_read_match_distances(coder,
- &len, &num_distance_pairs);
+ if (!coder->is_initialized && !encode_init(coder, mf))
+ return LZMA_OK;
- encode_symbol(coder, UINT32_MAX, 1);
+ // Get the lowest bits of the uncompressed offset from the LZ layer.
+ uint32_t position = mf_position(mf);
- assert(coder->additional_offset == 0);
+ while (true) {
+ // Encode pending bits, if any. Calling this before encoding
+ // the next symbol is needed only with plain LZMA, since
+ // LZMA2 always provides big enough buffer to flush
+ // everything out from the range encoder. For the same reason,
+ // rc_encode() never returns true when this function is used
+ // as part of LZMA2 encoder.
+ if (rc_encode(&coder->rc, out, out_pos, out_size)) {
+ assert(limit == UINT32_MAX);
+ return LZMA_OK;
}
- // Initialization is done (except if empty file).
- coder->is_initialized = true;
- }
-
- // Encoding loop
- while (true) {
- // Encode pending bits, if any.
- if (rc_encode(&coder->rc, out, out_pos, out_size))
- return false;
+ // With LZMA2 we need to take care that compressed size of
+ // a chunk doesn't get too big.
+ // TODO
+ if (limit != UINT32_MAX
+ && (mf->read_pos - mf->read_ahead >= limit
+ || *out_pos + rc_pending(&coder->rc)
+ >= (UINT32_C(1) << 16)
+ - LOOP_INPUT_MAX))
+ break;
// Check that there is some input to process.
- if (coder->lz.read_pos >= coder->lz.read_limit) {
- // If flushing or finishing, we must keep encoding
- // until additional_offset becomes zero to make
- // all the input available at output.
- if (coder->lz.sequence == SEQ_RUN)
- return false;
-
- if (coder->additional_offset == 0)
- break;
- }
-
- assert(coder->lz.read_pos <= coder->lz.write_pos);
+ if (mf->read_pos >= mf->read_limit) {
+ if (mf->action == LZMA_RUN)
+ return LZMA_OK;
-#ifndef NDEBUG
- if (coder->lz.sequence != SEQ_RUN) {
- assert(coder->lz.read_limit == coder->lz.write_pos);
- } else {
- assert(coder->lz.read_limit + coder->lz.keep_size_after
- == coder->lz.write_pos);
+ if (mf->read_ahead == 0)
+ break;
}
-#endif
-
- uint32_t pos;
- uint32_t len;
// Get optimal match (repeat position and length).
// Value ranges for pos:
@@ -327,33 +360,324 @@ lzma_lzma_encode(lzma_coder *coder, uint8_t *restrict out,
// match at (pos - REP_DISTANCES)
// - UINT32_MAX: not a match but a literal
// Value ranges for len:
- // - [MATCH_MIN_LEN, MATCH_MAX_LEN]
- if (coder->best_compression)
- lzma_get_optimum(coder, &pos, &len);
+ // - [MATCH_LEN_MIN, MATCH_LEN_MAX]
+ uint32_t len;
+ uint32_t back;
+
+ if (coder->fast_mode)
+ lzma_lzma_optimum_fast(coder, mf, &back, &len);
else
- lzma_get_optimum_fast(coder, &pos, &len);
+ lzma_lzma_optimum_normal(
+ coder, mf, &back, &len, position);
+
+ encode_symbol(coder, mf, back, len, position);
+
+ position += len;
+ }
+
+ if (!coder->is_flushed) {
+ coder->is_flushed = true;
- encode_symbol(coder, pos, len);
+ // We don't support encoding plain LZMA streams without EOPM,
+ // and LZMA2 doesn't use EOPM at LZMA level.
+ if (limit == UINT32_MAX)
+ encode_eopm(coder, position);
+
+ // Flush the remaining bytes from the range encoder.
+ rc_flush(&coder->rc);
+
+ // Copy the remaining bytes to the output buffer. If there
+ // isn't enough output space, we will copy out the remaining
+ // bytes on the next call to this function by using
+ // the rc_encode() call in the encoding loop above.
+ if (rc_encode(&coder->rc, out, out_pos, out_size)) {
+ assert(limit == UINT32_MAX);
+ return LZMA_OK;
+ }
}
- assert(!coder->longest_match_was_found);
+ // Make it ready for the next LZMA2 chunk.
+ coder->is_flushed = false;
+
+ return LZMA_STREAM_END;
+}
+
+
+static lzma_ret
+lzma_encode(lzma_coder *restrict coder, lzma_mf *restrict mf,
+ uint8_t *restrict out, size_t *restrict out_pos,
+ size_t out_size)
+{
+ // Plain LZMA has no support for sync-flushing.
+ if (unlikely(mf->action == LZMA_SYNC_FLUSH))
+ return LZMA_HEADER_ERROR;
+
+ return lzma_lzma_encode(coder, mf, out, out_pos, out_size, UINT32_MAX);
+}
+
- if (coder->is_flushed) {
- coder->is_flushed = false;
+////////////////////
+// Initialization //
+////////////////////
+
+static bool
+set_lz_options(lzma_lz_options *lz_options, const lzma_options_lzma *options)
+{
+ if (!is_lclppb_valid(options)
+ || options->fast_bytes < LZMA_FAST_BYTES_MIN
+ || options->fast_bytes > LZMA_FAST_BYTES_MAX)
return true;
+
+ // FIXME validation
+
+ lz_options->before_size = OPTS;
+ lz_options->dictionary_size = options->dictionary_size;
+ lz_options->after_size = LOOP_INPUT_MAX;
+ lz_options->match_len_max = MATCH_LEN_MAX;
+ lz_options->find_len_max = options->fast_bytes;
+ lz_options->match_finder = options->match_finder;
+ lz_options->match_finder_cycles = options->match_finder_cycles;
+ lz_options->preset_dictionary = options->preset_dictionary;
+ lz_options->preset_dictionary_size = options->preset_dictionary_size;
+
+ return false;
+}
+
+
+static void
+length_encoder_reset(lzma_length_encoder *lencoder,
+ const uint32_t num_pos_states, const bool fast_mode)
+{
+ bit_reset(lencoder->choice);
+ bit_reset(lencoder->choice2);
+
+ for (size_t pos_state = 0; pos_state < num_pos_states; ++pos_state) {
+ bittree_reset(lencoder->low[pos_state], LEN_LOW_BITS);
+ bittree_reset(lencoder->mid[pos_state], LEN_MID_BITS);
}
- // We don't support encoding old LZMA streams without EOPM, and LZMA2
- // doesn't use EOPM at LZMA level.
- if (coder->write_eopm)
- encode_eopm(coder);
+ bittree_reset(lencoder->high, LEN_HIGH_BITS);
- rc_flush(&coder->rc);
+ if (!fast_mode)
+ for (size_t pos_state = 0; pos_state < num_pos_states;
+ ++pos_state)
+ length_update_prices(lencoder, pos_state);
- if (rc_encode(&coder->rc, out, out_pos, out_size)) {
- coder->is_flushed = true;
- return false;
+ return;
+}
+
+
+extern void
+lzma_lzma_encoder_reset(lzma_coder *coder, const lzma_options_lzma *options)
+{
+ assert(!coder->is_flushed);
+
+ coder->pos_mask = (1U << options->pos_bits) - 1;
+ coder->literal_context_bits = options->literal_context_bits;
+ coder->literal_pos_mask = (1 << options->literal_pos_bits) - 1;
+
+
+ // Range coder
+ rc_reset(&coder->rc);
+
+ // State
+ coder->state = 0;
+ for (size_t i = 0; i < REP_DISTANCES; ++i)
+ coder->reps[i] = 0;
+
+ literal_init(coder->literal, options->literal_context_bits,
+ options->literal_pos_bits);
+
+ // Bit encoders
+ for (size_t i = 0; i < STATES; ++i) {
+ for (size_t j = 0; j <= coder->pos_mask; ++j) {
+ bit_reset(coder->is_match[i][j]);
+ bit_reset(coder->is_rep0_long[i][j]);
+ }
+
+ bit_reset(coder->is_rep[i]);
+ bit_reset(coder->is_rep0[i]);
+ bit_reset(coder->is_rep1[i]);
+ bit_reset(coder->is_rep2[i]);
}
- return true;
+ for (size_t i = 0; i < FULL_DISTANCES - END_POS_MODEL_INDEX; ++i)
+ bit_reset(coder->pos_special[i]);
+
+ // Bit tree encoders
+ for (size_t i = 0; i < LEN_TO_POS_STATES; ++i)
+ bittree_reset(coder->pos_slot[i], POS_SLOT_BITS);
+
+ bittree_reset(coder->pos_align, ALIGN_BITS);
+
+ // Length encoders
+ length_encoder_reset(&coder->match_len_encoder,
+ 1U << options->pos_bits, coder->fast_mode);
+
+ length_encoder_reset(&coder->rep_len_encoder,
+ 1U << options->pos_bits, coder->fast_mode);
+
+ // FIXME: Too big or too small won't work when resetting in the middle of LZMA2.
+ coder->match_price_count = UINT32_MAX / 2;
+ coder->align_price_count = UINT32_MAX / 2;
+
+ coder->opts_end_index = 0;
+ coder->opts_current_index = 0;
+}
+
+
+extern lzma_ret
+lzma_lzma_encoder_create(lzma_coder **coder_ptr, lzma_allocator *allocator,
+ const lzma_options_lzma *options, lzma_lz_options *lz_options)
+{
+ if (*coder_ptr == NULL) {
+ *coder_ptr = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (*coder_ptr == NULL)
+ return LZMA_MEM_ERROR;
+ }
+
+ lzma_coder *coder = *coder_ptr;
+
+ // Validate options that aren't validated elsewhere.
+ if (!is_lclppb_valid(options)
+ || options->fast_bytes < LZMA_FAST_BYTES_MIN
+ || options->fast_bytes > LZMA_FAST_BYTES_MAX)
+ return LZMA_HEADER_ERROR;
+
+ // Set compression mode.
+ switch (options->mode) {
+ case LZMA_MODE_FAST:
+ coder->fast_mode = true;
+ break;
+
+ case LZMA_MODE_NORMAL: {
+ coder->fast_mode = false;
+
+ // Set dist_table_size.
+ // Round the dictionary size up to next 2^n.
+ uint32_t log_size = 0;
+ while ((UINT32_C(1) << log_size)
+ < options->dictionary_size)
+ ++log_size;
+
+ coder->dist_table_size = log_size * 2;
+
+ // Length encoders' price table size
+ coder->match_len_encoder.table_size
+ = options->fast_bytes + 1 - MATCH_LEN_MIN;
+ coder->rep_len_encoder.table_size
+ = options->fast_bytes + 1 - MATCH_LEN_MIN;
+ break;
+ }
+
+ default:
+ return LZMA_HEADER_ERROR;
+ }
+
+ coder->is_initialized = false;
+ coder->is_flushed = false;
+
+ lzma_lzma_encoder_reset(coder, options);
+
+ // LZ encoder options FIXME validation
+ if (set_lz_options(lz_options, options))
+ return LZMA_HEADER_ERROR;
+
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+lzma_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator,
+ const void *options, lzma_lz_options *lz_options)
+{
+ lz->code = &lzma_encode;
+ return lzma_lzma_encoder_create(
+ &lz->coder, allocator, options, lz_options);
+}
+
+
+extern lzma_ret
+lzma_lzma_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ // Initialization call chain:
+ //
+ // lzma_lzma_encoder_init()
+ // `-- lzma_lz_encoder_init()
+ // `-- lzma_encoder_init()
+ // `-- lzma_encoder_init2()
+ //
+ // The above complexity is to let LZ encoder store the pointer to
+ // the LZMA encoder structure. Encoding call tree:
+ //
+ // lz_encode()
+ // |-- fill_window()
+ // | `-- Next coder in the chain, if any
+ // `-- lzma_encode()
+ // |-- lzma_dict_find()
+ // `-- lzma_dict_skip()
+ //
+ // FIXME ^
+ //
+ return lzma_lz_encoder_init(
+ next, allocator, filters, &lzma_encoder_init);
+}
+
+
+extern uint64_t
+lzma_lzma_encoder_memusage(const void *options)
+{
+ lzma_lz_options lz_options;
+ if (set_lz_options(&lz_options, options))
+ return UINT64_MAX;
+
+ const uint64_t lz_memusage = lzma_lz_encoder_memusage(&lz_options);
+ if (lz_memusage == UINT64_MAX)
+ return UINT64_MAX;
+
+ return (uint64_t)(sizeof(lzma_coder)) + lz_memusage;
+}
+
+
+extern bool
+lzma_lzma_lclppb_encode(const lzma_options_lzma *options, uint8_t *byte)
+{
+ if (options->literal_context_bits > LZMA_LITERAL_CONTEXT_BITS_MAX
+ || options->literal_pos_bits
+ > LZMA_LITERAL_POS_BITS_MAX
+ || options->pos_bits > LZMA_POS_BITS_MAX
+ || options->literal_context_bits
+ + options->literal_pos_bits
+ > LZMA_LITERAL_BITS_MAX)
+ return true;
+
+ *byte = (options->pos_bits * 5 + options->literal_pos_bits) * 9
+ + options->literal_context_bits;
+ assert(*byte <= (4 * 5 + 4) * 9 + 8);
+
+ return false;
+}
+
+
+#ifdef HAVE_ENCODER_LZMA
+extern lzma_ret
+lzma_lzma_props_encode(const void *options, uint8_t *out)
+{
+ const lzma_options_lzma *const opt = options;
+
+ if (lzma_lzma_lclppb_encode(opt, out))
+ return LZMA_PROG_ERROR;
+
+ integer_write_32(out + 1, opt->dictionary_size);
+
+ return LZMA_OK;
+}
+#endif
+
+
+extern LZMA_API lzma_bool
+lzma_mode_is_available(lzma_mode mode)
+{
+ return mode == LZMA_MODE_FAST || mode == LZMA_MODE_NORMAL;
}
diff --git a/src/liblzma/lzma/lzma_encoder.h b/src/liblzma/lzma/lzma_encoder.h
index 1c57f80a..e270cc27 100644
--- a/src/liblzma/lzma/lzma_encoder.h
+++ b/src/liblzma/lzma/lzma_encoder.h
@@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file lzma_encoder.h
-/// \brief LZMA method handler API
+/// \brief LZMA encoder API
//
// Copyright (C) 1999-2006 Igor Pavlov
// Copyright (C) 2007 Lasse Collin
@@ -23,13 +23,47 @@
#include "common.h"
+
extern lzma_ret lzma_lzma_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
-extern bool lzma_lzma_encode_properties(
+
+extern uint64_t lzma_lzma_encoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma_props_encode(const void *options, uint8_t *out);
+
+
+/// Encodes lc/lp/pb into one byte. Returns false on success and true on error.
+extern bool lzma_lzma_lclppb_encode(
const lzma_options_lzma *options, uint8_t *byte);
+
+#ifdef HAVE_SMALL
+
/// Initializes the lzma_fastpos[] array.
extern void lzma_fastpos_init(void);
#endif
+
+
+#ifdef LZMA_LZ_ENCODER_H
+
+/// Initializes raw LZMA encoder; this is used by LZMA2.
+extern lzma_ret lzma_lzma_encoder_create(
+ lzma_coder **coder_ptr, lzma_allocator *allocator,
+ const lzma_options_lzma *options, lzma_lz_options *lz_options);
+
+
+/// Resets an already initialized LZMA encoder; this is used by LZMA2.
+extern void lzma_lzma_encoder_reset(
+ lzma_coder *coder, const lzma_options_lzma *options);
+
+
+extern lzma_ret lzma_lzma_encode(lzma_coder *restrict coder,
+ lzma_mf *restrict mf, uint8_t *restrict out,
+ size_t *restrict out_pos, size_t out_size,
+ uint32_t read_limit);
+
+#endif
+
+#endif
diff --git a/src/liblzma/lzma/lzma_encoder_features.c b/src/liblzma/lzma/lzma_encoder_features.c
index 56e59c6a..9fecee48 100644
--- a/src/liblzma/lzma/lzma_encoder_features.c
+++ b/src/liblzma/lzma/lzma_encoder_features.c
@@ -22,7 +22,7 @@
static lzma_mode modes[] = {
LZMA_MODE_FAST,
- LZMA_MODE_BEST,
+ LZMA_MODE_NORMAL,
LZMA_MODE_INVALID
};
diff --git a/src/liblzma/lzma/lzma_encoder_getoptimum.c b/src/liblzma/lzma/lzma_encoder_getoptimum.c
deleted file mode 100644
index b175e4cb..00000000
--- a/src/liblzma/lzma/lzma_encoder_getoptimum.c
+++ /dev/null
@@ -1,925 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file lzma_encoder_getoptimum.c
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-// NOTE: If you want to keep the line length in 80 characters, set
-// tab width to 4 or less in your editor when editing this file.
-
-
-// "Would you love the monster code?
-// Could you understand beauty of the beast?"
-// --Adapted from Lordi's "Would you love a monster man".
-
-
-#include "lzma_encoder_private.h"
-#include "fastpos.h"
-
-
-#define length_get_price(length_encoder, symbol, pos_state) \
- (length_encoder).prices[pos_state][symbol]
-
-
-#define get_rep_len_1_price(state, pos_state) \
- bit_get_price_0(coder->is_rep0[state]) \
- + bit_get_price_0(coder->is_rep0_long[state][pos_state])
-
-
-// Adds to price_target.
-#define get_pure_rep_price(price_target, rep_index, state, pos_state) \
-do { \
- if ((rep_index) == 0) { \
- price_target += bit_get_price_0(coder->is_rep0[state]); \
- price_target += bit_get_price_1( \
- coder->is_rep0_long[state][pos_state]); \
- } else { \
- price_target += bit_get_price_1(coder->is_rep0[state]); \
- if ((rep_index) == 1) { \
- price_target += bit_get_price_0(coder->is_rep1[state]); \
- } else { \
- price_target += bit_get_price_1(coder->is_rep1[state]); \
- price_target += bit_get_price( \
- coder->is_rep2[state], (rep_index) - 2); \
- } \
- } \
-} while (0)
-
-
-// Adds to price_target.
-#define get_rep_price(price_target, rep_index, len, state, pos_state) \
-do { \
- get_pure_rep_price(price_target, rep_index, state, pos_state); \
- price_target += length_get_price(coder->rep_len_encoder, \
- (len) - MATCH_MIN_LEN, pos_state); \
-} while (0)
-
-
-// Adds to price_target.
-#define get_pos_len_price(price_target, pos, len, pos_state) \
-do { \
- const uint32_t len_to_pos_state_tmp = get_len_to_pos_state(len); \
- if ((pos) < FULL_DISTANCES) { \
- price_target += distances_prices[len_to_pos_state_tmp][pos]; \
- } else { \
- price_target \
- += pos_slot_prices[len_to_pos_state_tmp][get_pos_slot_2(pos)] \
- + align_prices[(pos) & ALIGN_MASK]; \
- } \
- price_target += length_get_price( \
- coder->match_len_encoder, (len) - MATCH_MIN_LEN, pos_state); \
-} while (0)
-
-
-// Three macros to manipulate lzma_optimal structures:
-#define make_as_char(opt) \
-do { \
- (opt).back_prev = UINT32_MAX; \
- (opt).prev_1_is_char = false; \
-} while (0)
-
-
-#define make_as_short_rep(opt) \
-do { \
- (opt).back_prev = 0; \
- (opt).prev_1_is_char = false; \
-} while (0)
-
-
-#define is_short_rep(opt) \
- ((opt).back_prev == 0)
-
-
-static void
-fill_length_prices(lzma_length_encoder *lc, uint32_t pos_state)
-{
- const uint32_t num_symbols = lc->table_size;
- const uint32_t a0 = bit_get_price_0(lc->choice);
- const uint32_t a1 = bit_get_price_1(lc->choice);
- const uint32_t b0 = a1 + bit_get_price_0(lc->choice2);
- const uint32_t b1 = a1 + bit_get_price_1(lc->choice2);
-
- uint32_t *prices = lc->prices[pos_state];
- uint32_t i = 0;
-
- for (i = 0; i < num_symbols && i < LEN_LOW_SYMBOLS; ++i)
- prices[i] = a0 + bittree_get_price(lc->low[pos_state],
- LEN_LOW_BITS, i);
-
- for (; i < num_symbols && i < LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; ++i)
- prices[i] = b0 + bittree_get_price(lc->mid[pos_state],
- LEN_MID_BITS, i - LEN_LOW_SYMBOLS);
-
- for (; i < num_symbols; ++i)
- prices[i] = b1 + bittree_get_price(lc->high, LEN_HIGH_BITS,
- i - LEN_LOW_SYMBOLS - LEN_MID_SYMBOLS);
-
- lc->counters[pos_state] = num_symbols;
-
- return;
-}
-
-
-static void
-fill_distances_prices(lzma_coder *coder)
-{
- uint32_t temp_prices[FULL_DISTANCES];
-
- for (uint32_t i = START_POS_MODEL_INDEX; i < FULL_DISTANCES; ++i) {
- const uint32_t pos_slot = get_pos_slot(i);
- const uint32_t footer_bits = ((pos_slot >> 1) - 1);
- const uint32_t base = (2 | (pos_slot & 1)) << footer_bits;
- temp_prices[i] = bittree_reverse_get_price(
- coder->pos_encoders + base - pos_slot - 1,
- footer_bits, i - base);
- }
-
- const uint32_t dist_table_size = coder->dist_table_size;
-
- for (uint32_t len_to_pos_state = 0;
- len_to_pos_state < LEN_TO_POS_STATES;
- ++len_to_pos_state) {
-
- const probability *encoder = coder->pos_slot_encoder[len_to_pos_state];
- uint32_t *pos_slot_prices = coder->pos_slot_prices[len_to_pos_state];
-
- for (uint32_t pos_slot = 0;
- pos_slot < dist_table_size;
- ++pos_slot) {
- pos_slot_prices[pos_slot] = bittree_get_price(encoder,
- POS_SLOT_BITS, pos_slot);
- }
-
- for (uint32_t pos_slot = END_POS_MODEL_INDEX;
- pos_slot < dist_table_size;
- ++pos_slot)
- pos_slot_prices[pos_slot] += (((pos_slot >> 1) - 1)
- - ALIGN_BITS) << BIT_PRICE_SHIFT_BITS;
-
-
- uint32_t *distances_prices
- = coder->distances_prices[len_to_pos_state];
-
- uint32_t i;
- for (i = 0; i < START_POS_MODEL_INDEX; ++i)
- distances_prices[i] = pos_slot_prices[i];
-
- for (; i < FULL_DISTANCES; ++i)
- distances_prices[i] = pos_slot_prices[get_pos_slot(i)]
- + temp_prices[i];
- }
-
- coder->match_price_count = 0;
-
- return;
-}
-
-
-static void
-fill_align_prices(lzma_coder *coder)
-{
- for (uint32_t i = 0; i < ALIGN_TABLE_SIZE; ++i)
- coder->align_prices[i] = bittree_reverse_get_price(
- coder->pos_align_encoder, ALIGN_BITS, i);
-
- coder->align_price_count = 0;
- return;
-}
-
-
-// The first argument is a pointer returned by literal_get_subcoder().
-static uint32_t
-literal_get_price(const probability *encoders, const bool match_mode,
- const uint8_t match_byte, const uint8_t symbol)
-{
- uint32_t price = 0;
- uint32_t context = 1;
- int i = 8;
-
- if (match_mode) {
- do {
- --i;
- const uint32_t match_bit = (match_byte >> i) & 1;
- const uint32_t bit = (symbol >> i) & 1;
- const uint32_t subcoder_index
- = 0x100 + (match_bit << 8) + context;
-
- price += bit_get_price(encoders[subcoder_index], bit);
- context = (context << 1) | bit;
-
- if (match_bit != bit)
- break;
-
- } while (i != 0);
- }
-
- while (i != 0) {
- --i;
- const uint32_t bit = (symbol >> i) & 1;
- price += bit_get_price(encoders[context], bit);
- context = (context << 1) | bit;
- }
-
- return price;
-}
-
-
-static void
-backward(lzma_coder *restrict coder, uint32_t *restrict len_res,
- uint32_t *restrict back_res, uint32_t cur)
-{
- coder->optimum_end_index = cur;
-
- uint32_t pos_mem = coder->optimum[cur].pos_prev;
- uint32_t back_mem = coder->optimum[cur].back_prev;
-
- do {
- if (coder->optimum[cur].prev_1_is_char) {
- make_as_char(coder->optimum[pos_mem]);
- coder->optimum[pos_mem].pos_prev = pos_mem - 1;
-
- if (coder->optimum[cur].prev_2) {
- coder->optimum[pos_mem - 1].prev_1_is_char = false;
- coder->optimum[pos_mem - 1].pos_prev
- = coder->optimum[cur].pos_prev_2;
- coder->optimum[pos_mem - 1].back_prev
- = coder->optimum[cur].back_prev_2;
- }
- }
-
- uint32_t pos_prev = pos_mem;
- uint32_t back_cur = back_mem;
-
- back_mem = coder->optimum[pos_prev].back_prev;
- pos_mem = coder->optimum[pos_prev].pos_prev;
-
- coder->optimum[pos_prev].back_prev = back_cur;
- coder->optimum[pos_prev].pos_prev = cur;
- cur = pos_prev;
-
- } while (cur != 0);
-
- coder->optimum_current_index = coder->optimum[0].pos_prev;
- *len_res = coder->optimum[0].pos_prev;
- *back_res = coder->optimum[0].back_prev;
-
- return;
-}
-
-
-extern void
-lzma_get_optimum(lzma_coder *restrict coder,
- uint32_t *restrict back_res, uint32_t *restrict len_res)
-{
- uint32_t position = coder->now_pos;
- uint32_t pos_state = position & coder->pos_mask;
-
- // Update the price tables. In the C++ LZMA SDK 4.42 this was done in both
- // initialization function and in the main loop. In liblzma they were
- // moved into this single place.
- if (coder->additional_offset == 0) {
- if (coder->match_price_count >= (1 << 7))
- fill_distances_prices(coder);
-
- if (coder->align_price_count >= ALIGN_TABLE_SIZE)
- fill_align_prices(coder);
- }
-
- if (coder->prev_len_encoder != NULL) {
- if (--coder->prev_len_encoder->counters[pos_state] == 0)
- fill_length_prices(coder->prev_len_encoder, pos_state);
-
- coder->prev_len_encoder = NULL;
- }
-
-
- if (coder->optimum_end_index != coder->optimum_current_index) {
- *len_res = coder->optimum[coder->optimum_current_index].pos_prev
- - coder->optimum_current_index;
- *back_res = coder->optimum[coder->optimum_current_index].back_prev;
- coder->optimum_current_index = coder->optimum[
- coder->optimum_current_index].pos_prev;
- return;
- }
-
- coder->optimum_current_index = 0;
- coder->optimum_end_index = 0;
-
-
- const uint32_t fast_bytes = coder->fast_bytes;
- uint32_t *match_distances = coder->match_distances;
-
- uint32_t len_main;
- uint32_t num_distance_pairs;
-
- if (!coder->longest_match_was_found) {
- lzma_read_match_distances(coder, &len_main, &num_distance_pairs);
- } else {
- len_main = coder->longest_match_length;
- num_distance_pairs = coder->num_distance_pairs;
- coder->longest_match_was_found = false;
- }
-
-
- const uint8_t *buf = coder->lz.buffer + coder->lz.read_pos - 1;
- uint32_t num_available_bytes
- = coder->lz.write_pos - coder->lz.read_pos + 1;
- if (num_available_bytes < 2) {
- *back_res = UINT32_MAX;
- *len_res = 1;
- return;
- }
-
- if (num_available_bytes > MATCH_MAX_LEN)
- num_available_bytes = MATCH_MAX_LEN;
-
-
- uint32_t reps[REP_DISTANCES];
- uint32_t rep_lens[REP_DISTANCES];
- uint32_t rep_max_index = 0;
-
- for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
- reps[i] = coder->reps[i];
- const uint32_t back_offset = reps[i] + 1;
-
- if (buf[0] != *(buf - back_offset)
- || buf[1] != *(buf + 1 - back_offset)) {
- rep_lens[i] = 0;
- continue;
- }
-
- uint32_t len_test;
- for (len_test = 2; len_test < num_available_bytes
- && buf[len_test] == *(buf + len_test - back_offset);
- ++len_test) ;
-
- rep_lens[i] = len_test;
- if (len_test > rep_lens[rep_max_index])
- rep_max_index = i;
- }
-
- if (rep_lens[rep_max_index] >= fast_bytes) {
- *back_res = rep_max_index;
- *len_res = rep_lens[rep_max_index];
- move_pos(*len_res - 1);
- return;
- }
-
-
- if (len_main >= fast_bytes) {
- *back_res = match_distances[num_distance_pairs] + REP_DISTANCES;
- *len_res = len_main;
- move_pos(len_main - 1);
- return;
- }
-
- uint8_t current_byte = *buf;
- uint8_t match_byte = *(buf - reps[0] - 1);
-
- if (len_main < 2 && current_byte != match_byte
- && rep_lens[rep_max_index] < 2) {
- *back_res = UINT32_MAX;
- *len_res = 1;
- return;
- }
-
- coder->optimum[0].state = coder->state;
-
- coder->optimum[1].price = bit_get_price_0(
- coder->is_match[coder->state][pos_state])
- + literal_get_price(
- literal_get_subcoder(coder->literal_coder,
- position, coder->previous_byte),
- !is_literal_state(coder->state), match_byte, current_byte);
-
- make_as_char(coder->optimum[1]);
-
- uint32_t match_price
- = bit_get_price_1(coder->is_match[coder->state][pos_state]);
- uint32_t rep_match_price
- = match_price + bit_get_price_1(coder->is_rep[coder->state]);
-
-
- if (match_byte == current_byte) {
- const uint32_t short_rep_price = rep_match_price
- + get_rep_len_1_price(coder->state, pos_state);
-
- if (short_rep_price < coder->optimum[1].price) {
- coder->optimum[1].price = short_rep_price;
- make_as_short_rep(coder->optimum[1]);
- }
- }
-
- uint32_t len_end = (len_main >= rep_lens[rep_max_index])
- ? len_main
- : rep_lens[rep_max_index];
-
- if (len_end < 2) {
- *back_res = coder->optimum[1].back_prev;
- *len_res = 1;
- return;
- }
-
- coder->optimum[1].pos_prev = 0;
-
- for (uint32_t i = 0; i < REP_DISTANCES; ++i)
- coder->optimum[0].backs[i] = reps[i];
-
- uint32_t len = len_end;
- do {
- coder->optimum[len].price = INFINITY_PRICE;
- } while (--len >= 2);
-
-
- uint32_t (*distances_prices)[FULL_DISTANCES] = coder->distances_prices;
- uint32_t (*pos_slot_prices)[DIST_TABLE_SIZE_MAX] = coder->pos_slot_prices;
- uint32_t *align_prices = coder->align_prices;
-
- for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
- uint32_t rep_len = rep_lens[i];
- if (rep_len < 2)
- continue;
-
- uint32_t price = rep_match_price;
- get_pure_rep_price(price, i, coder->state, pos_state);
-
- do {
- const uint32_t cur_and_len_price = price
- + length_get_price(
- coder->rep_len_encoder,
- rep_len - 2, pos_state);
-
- if (cur_and_len_price < coder->optimum[rep_len].price) {
- coder->optimum[rep_len].price = cur_and_len_price;
- coder->optimum[rep_len].pos_prev = 0;
- coder->optimum[rep_len].back_prev = i;
- coder->optimum[rep_len].prev_1_is_char = false;
- }
- } while (--rep_len >= 2);
- }
-
-
- uint32_t normal_match_price = match_price
- + bit_get_price_0(coder->is_rep[coder->state]);
-
- len = (rep_lens[0] >= 2) ? rep_lens[0] + 1 : 2;
-
- if (len <= len_main) {
- uint32_t offs = 0;
-
- while (len > match_distances[offs + 1])
- offs += 2;
-
- for(; ; ++len) {
- const uint32_t distance = match_distances[offs + 2];
- uint32_t cur_and_len_price = normal_match_price;
- get_pos_len_price(cur_and_len_price, distance, len, pos_state);
-
- if (cur_and_len_price < coder->optimum[len].price) {
- coder->optimum[len].price = cur_and_len_price;
- coder->optimum[len].pos_prev = 0;
- coder->optimum[len].back_prev = distance + REP_DISTANCES;
- coder->optimum[len].prev_1_is_char = false;
- }
-
- if (len == match_distances[offs + 1]) {
- offs += 2;
- if (offs == num_distance_pairs)
- break;
- }
- }
- }
-
-
- //////////////////
- // Big loop ;-) //
- //////////////////
-
- uint32_t cur = 0;
-
- // The rest of this function is a huge while-loop. To avoid extreme
- // indentation, the indentation level is not increased here.
- while (true) {
-
- ++cur;
-
- assert(cur < OPTS);
-
- if (cur == len_end) {
- backward(coder, len_res, back_res, cur);
- return;
- }
-
- uint32_t new_len;
-
- lzma_read_match_distances(coder, &new_len, &num_distance_pairs);
-
- if (new_len >= fast_bytes) {
- coder->num_distance_pairs = num_distance_pairs;
- coder->longest_match_length = new_len;
- coder->longest_match_was_found = true;
- backward(coder, len_res, back_res, cur);
- return;
- }
-
-
- ++position;
-
- uint32_t pos_prev = coder->optimum[cur].pos_prev;
- uint32_t state;
-
- if (coder->optimum[cur].prev_1_is_char) {
- --pos_prev;
-
- if (coder->optimum[cur].prev_2) {
- state = coder->optimum[coder->optimum[cur].pos_prev_2].state;
-
- if (coder->optimum[cur].back_prev_2 < REP_DISTANCES)
- update_long_rep(state);
- else
- update_match(state);
-
- } else {
- state = coder->optimum[pos_prev].state;
- }
-
- update_literal(state);
-
- } else {
- state = coder->optimum[pos_prev].state;
- }
-
- if (pos_prev == cur - 1) {
- if (is_short_rep(coder->optimum[cur]))
- update_short_rep(state);
- else
- update_literal(state);
- } else {
- uint32_t pos;
- if (coder->optimum[cur].prev_1_is_char && coder->optimum[cur].prev_2) {
- pos_prev = coder->optimum[cur].pos_prev_2;
- pos = coder->optimum[cur].back_prev_2;
- update_long_rep(state);
- } else {
- pos = coder->optimum[cur].back_prev;
- if (pos < REP_DISTANCES)
- update_long_rep(state);
- else
- update_match(state);
- }
-
- if (pos < REP_DISTANCES) {
- reps[0] = coder->optimum[pos_prev].backs[pos];
-
- uint32_t i;
- for (i = 1; i <= pos; ++i)
- reps[i] = coder->optimum[pos_prev].backs[i - 1];
-
- for (; i < REP_DISTANCES; ++i)
- reps[i] = coder->optimum[pos_prev].backs[i];
-
- } else {
- reps[0] = pos - REP_DISTANCES;
-
- for (uint32_t i = 1; i < REP_DISTANCES; ++i)
- reps[i] = coder->optimum[pos_prev].backs[i - 1];
- }
- }
-
- coder->optimum[cur].state = state;
-
- for (uint32_t i = 0; i < REP_DISTANCES; ++i)
- coder->optimum[cur].backs[i] = reps[i];
-
- const uint32_t cur_price = coder->optimum[cur].price;
-
- buf = coder->lz.buffer + coder->lz.read_pos - 1;
- current_byte = *buf;
- match_byte = *(buf - reps[0] - 1);
-
- pos_state = position & coder->pos_mask;
-
- const uint32_t cur_and_1_price = cur_price
- + bit_get_price_0(coder->is_match[state][pos_state])
- + literal_get_price(
- literal_get_subcoder(coder->literal_coder,
- position, buf[-1]),
- !is_literal_state(state), match_byte, current_byte);
-
- bool next_is_char = false;
-
- if (cur_and_1_price < coder->optimum[cur + 1].price) {
- coder->optimum[cur + 1].price = cur_and_1_price;
- coder->optimum[cur + 1].pos_prev = cur;
- make_as_char(coder->optimum[cur + 1]);
- next_is_char = true;
- }
-
- match_price = cur_price
- + bit_get_price_1(coder->is_match[state][pos_state]);
- rep_match_price = match_price
- + bit_get_price_1(coder->is_rep[state]);
-
- if (match_byte == current_byte
- && !(coder->optimum[cur + 1].pos_prev < cur
- && coder->optimum[cur + 1].back_prev == 0)) {
-
- const uint32_t short_rep_price = rep_match_price
- + get_rep_len_1_price(state, pos_state);
-
- if (short_rep_price <= coder->optimum[cur + 1].price) {
- coder->optimum[cur + 1].price = short_rep_price;
- coder->optimum[cur + 1].pos_prev = cur;
- make_as_short_rep(coder->optimum[cur + 1]);
- next_is_char = true;
- }
- }
-
- uint32_t num_available_bytes_full
- = coder->lz.write_pos - coder->lz.read_pos + 1;
- num_available_bytes_full = MIN(OPTS - 1 - cur, num_available_bytes_full);
- num_available_bytes = num_available_bytes_full;
-
- if (num_available_bytes < 2)
- continue;
-
- if (num_available_bytes > fast_bytes)
- num_available_bytes = fast_bytes;
-
- if (!next_is_char && match_byte != current_byte) { // speed optimization
- // try literal + rep0
- const uint32_t back_offset = reps[0] + 1;
- const uint32_t limit = MIN(num_available_bytes_full, fast_bytes + 1);
-
- uint32_t temp;
- for (temp = 1; temp < limit
- && buf[temp] == *(buf + temp - back_offset);
- ++temp) ;
-
- const uint32_t len_test_2 = temp - 1;
-
- if (len_test_2 >= 2) {
- uint32_t state_2 = state;
- update_literal(state_2);
-
- const uint32_t pos_state_next = (position + 1) & coder->pos_mask;
- const uint32_t next_rep_match_price = cur_and_1_price
- + bit_get_price_1(coder->is_match[state_2][pos_state_next])
- + bit_get_price_1(coder->is_rep[state_2]);
-
- // for (; len_test_2 >= 2; --len_test_2) {
- const uint32_t offset = cur + 1 + len_test_2;
-
- while (len_end < offset)
- coder->optimum[++len_end].price = INFINITY_PRICE;
-
- uint32_t cur_and_len_price = next_rep_match_price;
- get_rep_price(cur_and_len_price,
- 0, len_test_2, state_2, pos_state_next);
-
- if (cur_and_len_price < coder->optimum[offset].price) {
- coder->optimum[offset].price = cur_and_len_price;
- coder->optimum[offset].pos_prev = cur + 1;
- coder->optimum[offset].back_prev = 0;
- coder->optimum[offset].prev_1_is_char = true;
- coder->optimum[offset].prev_2 = false;
- }
-// }
- }
- }
-
-
- uint32_t start_len = 2; // speed optimization
-
- for (uint32_t rep_index = 0; rep_index < REP_DISTANCES; ++rep_index) {
- const uint32_t back_offset = reps[rep_index] + 1;
-
- if (buf[0] != *(buf - back_offset) || buf[1] != *(buf + 1 - back_offset))
- continue;
-
- uint32_t len_test;
- for (len_test = 2; len_test < num_available_bytes
- && buf[len_test] == *(buf + len_test - back_offset);
- ++len_test) ;
-
- while (len_end < cur + len_test)
- coder->optimum[++len_end].price = INFINITY_PRICE;
-
- const uint32_t len_test_temp = len_test;
- uint32_t price = rep_match_price;
- get_pure_rep_price(price, rep_index, state, pos_state);
-
- do {
- const uint32_t cur_and_len_price = price
- + length_get_price(coder->rep_len_encoder,
- len_test - 2, pos_state);
-
- if (cur_and_len_price < coder->optimum[cur + len_test].price) {
- coder->optimum[cur + len_test].price = cur_and_len_price;
- coder->optimum[cur + len_test].pos_prev = cur;
- coder->optimum[cur + len_test].back_prev = rep_index;
- coder->optimum[cur + len_test].prev_1_is_char = false;
- }
- } while (--len_test >= 2);
-
- len_test = len_test_temp;
-
- if (rep_index == 0)
- start_len = len_test + 1;
-
-
- uint32_t len_test_2 = len_test + 1;
- const uint32_t limit = MIN(num_available_bytes_full,
- len_test_2 + fast_bytes);
- for (; len_test_2 < limit
- && buf[len_test_2] == *(buf + len_test_2 - back_offset);
- ++len_test_2) ;
-
- len_test_2 -= len_test + 1;
-
- if (len_test_2 >= 2) {
- uint32_t state_2 = state;
- update_long_rep(state_2);
-
- uint32_t pos_state_next = (position + len_test) & coder->pos_mask;
-
- const uint32_t cur_and_len_char_price = price
- + length_get_price(coder->rep_len_encoder,
- len_test - 2, pos_state)
- + bit_get_price_0(coder->is_match[state_2][pos_state_next])
- + literal_get_price(
- literal_get_subcoder(coder->literal_coder,
- position + len_test, buf[len_test - 1]),
- true, *(buf + len_test - back_offset), buf[len_test]);
-
- update_literal(state_2);
-
- pos_state_next = (position + len_test + 1) & coder->pos_mask;
-
- const uint32_t next_rep_match_price = cur_and_len_char_price
- + bit_get_price_1(coder->is_match[state_2][pos_state_next])
- + bit_get_price_1(coder->is_rep[state_2]);
-
-// for(; len_test_2 >= 2; len_test_2--) {
- const uint32_t offset = cur + len_test + 1 + len_test_2;
-
- while (len_end < offset)
- coder->optimum[++len_end].price = INFINITY_PRICE;
-
- uint32_t cur_and_len_price = next_rep_match_price;
- get_rep_price(cur_and_len_price,
- 0, len_test_2, state_2, pos_state_next);
-
- if (cur_and_len_price < coder->optimum[offset].price) {
- coder->optimum[offset].price = cur_and_len_price;
- coder->optimum[offset].pos_prev = cur + len_test + 1;
- coder->optimum[offset].back_prev = 0;
- coder->optimum[offset].prev_1_is_char = true;
- coder->optimum[offset].prev_2 = true;
- coder->optimum[offset].pos_prev_2 = cur;
- coder->optimum[offset].back_prev_2 = rep_index;
- }
-// }
- }
- }
-
-
-// for (uint32_t len_test = 2; len_test <= new_len; ++len_test)
- if (new_len > num_available_bytes) {
- new_len = num_available_bytes;
-
- for (num_distance_pairs = 0;
- new_len > match_distances[num_distance_pairs + 1];
- num_distance_pairs += 2) ;
-
- match_distances[num_distance_pairs + 1] = new_len;
- num_distance_pairs += 2;
- }
-
-
- if (new_len >= start_len) {
- normal_match_price = match_price
- + bit_get_price_0(coder->is_rep[state]);
-
- while (len_end < cur + new_len)
- coder->optimum[++len_end].price = INFINITY_PRICE;
-
- uint32_t offs = 0;
- while (start_len > match_distances[offs + 1])
- offs += 2;
-
- uint32_t cur_back = match_distances[offs + 2];
- uint32_t pos_slot = get_pos_slot_2(cur_back);
-
- for (uint32_t len_test = start_len; ; ++len_test) {
- uint32_t cur_and_len_price = normal_match_price;
- const uint32_t len_to_pos_state = get_len_to_pos_state(len_test);
-
- if (cur_back < FULL_DISTANCES)
- cur_and_len_price += distances_prices[
- len_to_pos_state][cur_back];
- else
- cur_and_len_price += pos_slot_prices[
- len_to_pos_state][pos_slot]
- + align_prices[cur_back & ALIGN_MASK];
-
- cur_and_len_price += length_get_price(coder->match_len_encoder,
- len_test - MATCH_MIN_LEN, pos_state);
-
- if (cur_and_len_price < coder->optimum[cur + len_test].price) {
- coder->optimum[cur + len_test].price = cur_and_len_price;
- coder->optimum[cur + len_test].pos_prev = cur;
- coder->optimum[cur + len_test].back_prev
- = cur_back + REP_DISTANCES;
- coder->optimum[cur + len_test].prev_1_is_char = false;
- }
-
- if (len_test == match_distances[offs + 1]) {
- // Try Match + Literal + Rep0
- const uint32_t back_offset = cur_back + 1;
- uint32_t len_test_2 = len_test + 1;
- const uint32_t limit = MIN(num_available_bytes_full,
- len_test_2 + fast_bytes);
-
- for (; len_test_2 < limit &&
- buf[len_test_2] == *(buf + len_test_2 - back_offset);
- ++len_test_2) ;
-
- len_test_2 -= len_test + 1;
-
- if (len_test_2 >= 2) {
- uint32_t state_2 = state;
- update_match(state_2);
- uint32_t pos_state_next
- = (position + len_test) & coder->pos_mask;
-
- const uint32_t cur_and_len_char_price = cur_and_len_price
- + bit_get_price_0(
- coder->is_match[state_2][pos_state_next])
- + literal_get_price(
- literal_get_subcoder(
- coder->literal_coder,
- position + len_test,
- buf[len_test - 1]),
- true,
- *(buf + len_test - back_offset),
- buf[len_test]);
-
- update_literal(state_2);
- pos_state_next = (pos_state_next + 1) & coder->pos_mask;
-
- const uint32_t next_rep_match_price
- = cur_and_len_char_price
- + bit_get_price_1(
- coder->is_match[state_2][pos_state_next])
- + bit_get_price_1(coder->is_rep[state_2]);
-
- // for(; len_test_2 >= 2; --len_test_2) {
- const uint32_t offset = cur + len_test + 1 + len_test_2;
-
- while (len_end < offset)
- coder->optimum[++len_end].price = INFINITY_PRICE;
-
- cur_and_len_price = next_rep_match_price;
- get_rep_price(cur_and_len_price,
- 0, len_test_2, state_2, pos_state_next);
-
- if (cur_and_len_price < coder->optimum[offset].price) {
- coder->optimum[offset].price = cur_and_len_price;
- coder->optimum[offset].pos_prev = cur + len_test + 1;
- coder->optimum[offset].back_prev = 0;
- coder->optimum[offset].prev_1_is_char = true;
- coder->optimum[offset].prev_2 = true;
- coder->optimum[offset].pos_prev_2 = cur;
- coder->optimum[offset].back_prev_2
- = cur_back + REP_DISTANCES;
- }
-// }
- }
-
- offs += 2;
- if (offs == num_distance_pairs)
- break;
-
- cur_back = match_distances[offs + 2];
- if (cur_back >= FULL_DISTANCES)
- pos_slot = get_pos_slot_2(cur_back);
- }
- }
- }
-
- } // Closes: while (true)
-}
diff --git a/src/liblzma/lzma/lzma_encoder_getoptimumfast.c b/src/liblzma/lzma/lzma_encoder_getoptimumfast.c
deleted file mode 100644
index fa06be21..00000000
--- a/src/liblzma/lzma/lzma_encoder_getoptimumfast.c
+++ /dev/null
@@ -1,201 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file lzma_encoder_getoptimumfast.c
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-// NOTE: If you want to keep the line length in 80 characters, set
-// tab width to 4 or less in your editor when editing this file.
-
-
-#include "lzma_encoder_private.h"
-
-
-#define change_pair(small_dist, big_dist) \
- (((big_dist) >> 7) > (small_dist))
-
-
-extern void
-lzma_get_optimum_fast(lzma_coder *restrict coder,
- uint32_t *restrict back_res, uint32_t *restrict len_res)
-{
- // Local copies
- const uint32_t fast_bytes = coder->fast_bytes;
-
- uint32_t len_main;
- uint32_t num_distance_pairs;
- if (!coder->longest_match_was_found) {
- lzma_read_match_distances(coder, &len_main, &num_distance_pairs);
- } else {
- len_main = coder->longest_match_length;
- num_distance_pairs = coder->num_distance_pairs;
- coder->longest_match_was_found = false;
- }
-
- const uint8_t *buf = coder->lz.buffer + coder->lz.read_pos - 1;
- uint32_t num_available_bytes
- = coder->lz.write_pos - coder->lz.read_pos + 1;
-
- if (num_available_bytes < 2) {
- // There's not enough input left to encode a match.
- *back_res = UINT32_MAX;
- *len_res = 1;
- return;
- }
-
- if (num_available_bytes > MATCH_MAX_LEN)
- num_available_bytes = MATCH_MAX_LEN;
-
-
- // Look for repetitive matches; scan the previous four match distances
- uint32_t rep_lens[REP_DISTANCES];
- uint32_t rep_max_index = 0;
-
- for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
- const uint32_t back_offset = coder->reps[i] + 1;
-
- // If the first two bytes (2 == MATCH_MIN_LEN) do not match,
- // this rep_distance[i] is not useful. This is indicated
- // using zero as the length of the repetitive match.
- if (buf[0] != *(buf - back_offset)
- || buf[1] != *(buf + 1 - back_offset)) {
- rep_lens[i] = 0;
- continue;
- }
-
- // The first two bytes matched.
- // Calculate the length of the match.
- uint32_t len;
- for (len = 2; len < num_available_bytes
- && buf[len] == *(buf + len - back_offset);
- ++len) ;
-
- // If we have found a repetitive match that is at least
- // as long as fast_bytes, return it immediatelly.
- if (len >= fast_bytes) {
- *back_res = i;
- *len_res = len;
- move_pos(len - 1);
- return;
- }
-
- rep_lens[i] = len;
-
- // After this loop, rep_lens[rep_max_index] is the biggest
- // value of all values in rep_lens[].
- if (len > rep_lens[rep_max_index])
- rep_max_index = i;
- }
-
-
- if (len_main >= fast_bytes) {
- *back_res = coder->match_distances[num_distance_pairs]
- + REP_DISTANCES;
- *len_res = len_main;
- move_pos(len_main - 1);
- return;
- }
-
- uint32_t back_main = 0;
- if (len_main >= 2) {
- back_main = coder->match_distances[num_distance_pairs];
-
- while (num_distance_pairs > 2 && len_main ==
- coder->match_distances[num_distance_pairs - 3] + 1) {
- if (!change_pair(coder->match_distances[
- num_distance_pairs - 2], back_main))
- break;
-
- num_distance_pairs -= 2;
- len_main = coder->match_distances[num_distance_pairs - 1];
- back_main = coder->match_distances[num_distance_pairs];
- }
-
- if (len_main == 2 && back_main >= 0x80)
- len_main = 1;
- }
-
- if (rep_lens[rep_max_index] >= 2) {
- if (rep_lens[rep_max_index] + 1 >= len_main
- || (rep_lens[rep_max_index] + 2 >= len_main
- && (back_main > (1 << 9)))
- || (rep_lens[rep_max_index] + 3 >= len_main
- && (back_main > (1 << 15)))) {
- *back_res = rep_max_index;
- *len_res = rep_lens[rep_max_index];
- move_pos(*len_res - 1);
- return;
- }
- }
-
- if (len_main >= 2 && num_available_bytes > 2) {
- lzma_read_match_distances(coder, &coder->longest_match_length,
- &coder->num_distance_pairs);
-
- if (coder->longest_match_length >= 2) {
- const uint32_t new_distance = coder->match_distances[
- coder->num_distance_pairs];
-
- if ((coder->longest_match_length >= len_main
- && new_distance < back_main)
- || (coder->longest_match_length == len_main + 1
- && !change_pair(back_main, new_distance))
- || (coder->longest_match_length > len_main + 1)
- || (coder->longest_match_length + 1 >= len_main
- && len_main >= 3
- && change_pair(new_distance, back_main))) {
- coder->longest_match_was_found = true;
- *back_res = UINT32_MAX;
- *len_res = 1;
- return;
- }
- }
-
- ++buf;
- --num_available_bytes;
-
- for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
- const uint32_t back_offset = coder->reps[i] + 1;
-
- if (buf[1] != *(buf + 1 - back_offset)
- || buf[2] != *(buf + 2 - back_offset)) {
- rep_lens[i] = 0;
- continue;
- }
-
- uint32_t len;
- for (len = 2; len < num_available_bytes
- && buf[len] == *(buf + len - back_offset);
- ++len) ;
-
- if (len + 1 >= len_main) {
- coder->longest_match_was_found = true;
- *back_res = UINT32_MAX;
- *len_res = 1;
- return;
- }
- }
-
- *back_res = back_main + REP_DISTANCES;
- *len_res = len_main;
- move_pos(len_main - 2);
- return;
- }
-
- *back_res = UINT32_MAX;
- *len_res = 1;
- return;
-}
diff --git a/src/liblzma/lzma/lzma_encoder_init.c b/src/liblzma/lzma/lzma_encoder_init.c
deleted file mode 100644
index 21335f95..00000000
--- a/src/liblzma/lzma/lzma_encoder_init.c
+++ /dev/null
@@ -1,228 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file lzma_encoder_init.c
-/// \brief Creating, resetting and destroying the LZMA encoder
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#include "lzma_encoder_private.h"
-
-
-/// \brief Initializes the length encoder
-static void
-length_encoder_reset(lzma_length_encoder *lencoder,
- const uint32_t num_pos_states, const uint32_t table_size)
-{
- // NLength::CPriceTableEncoder::SetTableSize()
- lencoder->table_size = table_size;
-
- // NLength::CEncoder::Init()
- bit_reset(lencoder->choice);
- bit_reset(lencoder->choice2);
-
- for (size_t pos_state = 0; pos_state < num_pos_states; ++pos_state) {
- bittree_reset(lencoder->low[pos_state], LEN_LOW_BITS);
- bittree_reset(lencoder->mid[pos_state], LEN_MID_BITS);
- }
-
- bittree_reset(lencoder->high, LEN_HIGH_BITS);
-
- // NLength::CPriceTableEncoder::UpdateTables()
- for (size_t pos_state = 0; pos_state < num_pos_states; ++pos_state)
- lencoder->counters[pos_state] = 1;
-
- return;
-}
-
-
-static void
-lzma_lzma_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
-{
- lzma_lz_encoder_end(&coder->lz, allocator);
- lzma_free(coder, allocator);
- return;
-}
-
-
-extern lzma_ret
-lzma_lzma_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
- const lzma_filter_info *filters)
-{
- if (next->coder == NULL) {
- next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
- if (next->coder == NULL)
- return LZMA_MEM_ERROR;
-
- next->coder->next = LZMA_NEXT_CODER_INIT;
- next->coder->lz = LZMA_LZ_ENCODER_INIT;
- }
-
- // Validate options that aren't validated elsewhere.
- const lzma_options_lzma *options = filters[0].options;
- if (options->pos_bits > LZMA_POS_BITS_MAX
- || options->fast_bytes < LZMA_FAST_BYTES_MIN
- || options->fast_bytes > LZMA_FAST_BYTES_MAX) {
- lzma_lzma_encoder_end(next->coder, allocator);
- return LZMA_HEADER_ERROR;
- }
-
- // Set compression mode.
- switch (options->mode) {
- case LZMA_MODE_FAST:
- next->coder->best_compression = false;
- break;
-
- case LZMA_MODE_BEST:
- next->coder->best_compression = true;
- break;
-
- default:
- lzma_lzma_encoder_end(next->coder, allocator);
- return LZMA_HEADER_ERROR;
- }
-
- // Initialize literal coder.
- {
- const lzma_ret ret = lzma_literal_init(
- &next->coder->literal_coder,
- options->literal_context_bits,
- options->literal_pos_bits);
- if (ret != LZMA_OK)
- return ret;
- }
-
- // Initialize LZ encoder.
- {
- const lzma_ret ret = lzma_lz_encoder_reset(
- &next->coder->lz, allocator, &lzma_lzma_encode,
- options->dictionary_size, OPTS,
- options->fast_bytes, MATCH_MAX_LEN + 1 + OPTS,
- options->match_finder,
- options->match_finder_cycles,
- options->preset_dictionary,
- options->preset_dictionary_size);
- if (ret != LZMA_OK) {
- lzma_lzma_encoder_end(next->coder, allocator);
- return ret;
- }
- }
-
- // Set dist_table_size.
- {
- // Round the dictionary size up to next 2^n.
- uint32_t log_size;
- for (log_size = 0; (UINT32_C(1) << log_size)
- < options->dictionary_size; ++log_size) ;
-
- next->coder->dist_table_size = log_size * 2;
- }
-
- // Misc FIXME desc
- next->coder->align_price_count = UINT32_MAX;
- next->coder->match_price_count = UINT32_MAX;
- next->coder->dictionary_size = options->dictionary_size;
- next->coder->pos_mask = (1U << options->pos_bits) - 1;
- next->coder->fast_bytes = options->fast_bytes;
-
- // Range coder
- rc_reset(&next->coder->rc);
-
- // State
- next->coder->state = 0;
- next->coder->previous_byte = 0;
- for (size_t i = 0; i < REP_DISTANCES; ++i)
- next->coder->reps[i] = 0;
-
- // Bit encoders
- for (size_t i = 0; i < STATES; ++i) {
- for (size_t j = 0; j <= next->coder->pos_mask; ++j) {
- bit_reset(next->coder->is_match[i][j]);
- bit_reset(next->coder->is_rep0_long[i][j]);
- }
-
- bit_reset(next->coder->is_rep[i]);
- bit_reset(next->coder->is_rep0[i]);
- bit_reset(next->coder->is_rep1[i]);
- bit_reset(next->coder->is_rep2[i]);
- }
-
- for (size_t i = 0; i < FULL_DISTANCES - END_POS_MODEL_INDEX; ++i)
- bit_reset(next->coder->pos_encoders[i]);
-
- // Bit tree encoders
- for (size_t i = 0; i < LEN_TO_POS_STATES; ++i)
- bittree_reset(next->coder->pos_slot_encoder[i], POS_SLOT_BITS);
-
- bittree_reset(next->coder->pos_align_encoder, ALIGN_BITS);
-
- // Length encoders
- length_encoder_reset(&next->coder->match_len_encoder,
- 1U << options->pos_bits,
- options->fast_bytes + 1 - MATCH_MIN_LEN);
-
- length_encoder_reset(&next->coder->rep_len_encoder,
- 1U << options->pos_bits,
- next->coder->fast_bytes + 1 - MATCH_MIN_LEN);
-
- next->coder->prev_len_encoder = NULL;
-
- // Misc
- next->coder->longest_match_was_found = false;
- next->coder->optimum_end_index = 0;
- next->coder->optimum_current_index = 0;
- next->coder->additional_offset = 0;
-
- next->coder->now_pos = 0;
- next->coder->is_initialized = false;
- next->coder->is_flushed = false,
- next->coder->write_eopm = true;
-
- // Initialize the next decoder in the chain, if any.
- {
- const lzma_ret ret = lzma_next_filter_init(&next->coder->next,
- allocator, filters + 1);
- if (ret != LZMA_OK) {
- lzma_lzma_encoder_end(next->coder, allocator);
- return ret;
- }
- }
-
- // Initialization successful. Set the function pointers.
- next->code = &lzma_lz_encode;
- next->end = &lzma_lzma_encoder_end;
-
- return LZMA_OK;
-}
-
-
-extern bool
-lzma_lzma_encode_properties(const lzma_options_lzma *options, uint8_t *byte)
-{
- if (options->literal_context_bits > LZMA_LITERAL_CONTEXT_BITS_MAX
- || options->literal_pos_bits
- > LZMA_LITERAL_POS_BITS_MAX
- || options->pos_bits > LZMA_POS_BITS_MAX
- || options->literal_context_bits
- + options->literal_pos_bits
- > LZMA_LITERAL_BITS_MAX)
- return true;
-
- *byte = (options->pos_bits * 5 + options->literal_pos_bits) * 9
- + options->literal_context_bits;
- assert(*byte <= (4 * 5 + 4) * 9 + 8);
-
- return false;
-}
diff --git a/src/liblzma/lzma/lzma_encoder_optimum_fast.c b/src/liblzma/lzma/lzma_encoder_optimum_fast.c
new file mode 100644
index 00000000..9da7e79e
--- /dev/null
+++ b/src/liblzma/lzma/lzma_encoder_optimum_fast.c
@@ -0,0 +1,193 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma_encoder_optimum_fast.c
+//
+// Copyright (C) 1999-2008 Igor Pavlov
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma_encoder_private.h"
+
+
+#define change_pair(small_dist, big_dist) \
+ (((big_dist) >> 7) > (small_dist))
+
+
+static inline void
+literal(const lzma_coder *restrict coder, const uint8_t *restrict buf,
+ uint32_t *restrict back_res, uint32_t *restrict len_res)
+{
+ // Try short rep0 instead of always coding it as a literal.
+ *back_res = *buf == *(buf - coder->reps[0] - 1) ? 0 : UINT32_MAX;
+ *len_res = 1;
+ return;
+}
+
+
+extern void
+lzma_lzma_optimum_fast(lzma_coder *restrict coder, lzma_mf *restrict mf,
+ uint32_t *restrict back_res, uint32_t *restrict len_res)
+{
+ const uint32_t fast_bytes = mf->find_len_max;
+
+ uint32_t len_main;
+ uint32_t matches_count;
+ if (mf->read_ahead == 0) {
+ len_main = mf_find(mf, &matches_count, coder->matches);
+ } else {
+ assert(mf->read_ahead == 1);
+ len_main = coder->longest_match_length;
+ matches_count = coder->matches_count;
+ }
+
+ const uint8_t *buf = mf_ptr(mf) - 1;
+ const uint32_t buf_avail = MIN(mf_avail(mf) + 1, MATCH_LEN_MAX);
+
+ if (buf_avail < 2) {
+ // There's not enough input left to encode a match.
+ literal(coder, buf, back_res, len_res);
+ return;
+ }
+
+ // Look for repeated matches; scan the previous four match distances
+ uint32_t rep_len = 0;
+ uint32_t rep_index = 0;
+
+ for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
+ // Pointer to the beginning of the match candidate
+ const uint8_t *const buf_back = buf - coder->reps[i] - 1;
+
+ // If the first two bytes (2 == MATCH_LEN_MIN) do not match,
+ // this rep is not useful.
+ if (not_equal_16(buf, buf_back))
+ continue;
+
+ // The first two bytes matched.
+ // Calculate the length of the match.
+ uint32_t len;
+ for (len = 2; len < buf_avail
+ && buf[len] == buf_back[len]; ++len) ;
+
+ // If we have found a repeated match that is at least
+ // fast_bytes long, return it immediatelly.
+ if (len >= fast_bytes) {
+ *back_res = i;
+ *len_res = len;
+ mf_skip(mf, len - 1);
+ return;
+ }
+
+ if (len > rep_len) {
+ rep_index = i;
+ rep_len = len;
+ }
+ }
+
+ // We didn't find a long enough repeated match. Encode it as a normal
+ // match if the match length is at least fast_bytes.
+ if (len_main >= fast_bytes) {
+ *back_res = coder->matches[matches_count - 1].dist
+ + REP_DISTANCES;
+ *len_res = len_main;
+ mf_skip(mf, len_main - 1);
+ return;
+ }
+
+ uint32_t back_main = 0;
+ if (len_main >= 2) {
+ back_main = coder->matches[matches_count - 1].dist;
+
+ while (matches_count > 1 && len_main ==
+ coder->matches[matches_count - 2].len + 1) {
+ if (!change_pair(coder->matches[
+ matches_count - 2].dist,
+ back_main))
+ break;
+
+ --matches_count;
+ len_main = coder->matches[matches_count - 1].len;
+ back_main = coder->matches[matches_count - 1].dist;
+ }
+
+ if (len_main == 2 && back_main >= 0x80)
+ len_main = 1;
+ }
+
+ if (rep_len >= 2) {
+ if (rep_len + 1 >= len_main
+ || (rep_len + 2 >= len_main
+ && back_main > (UINT32_C(1) << 9))
+ || (rep_len + 3 >= len_main
+ && back_main > (UINT32_C(1) << 15))) {
+ *back_res = rep_index;
+ *len_res = rep_len;
+ mf_skip(mf, rep_len - 1);
+ return;
+ }
+ }
+
+ if (len_main < 2 || buf_avail <= 2) {
+ literal(coder, buf, back_res, len_res);
+ return;
+ }
+
+ // Get the matches for the next byte. If we find a better match,
+ // the current byte is encoded as a literal.
+ coder->longest_match_length = mf_find(mf,
+ &coder->matches_count, coder->matches);
+
+ if (coder->longest_match_length >= 2) {
+ const uint32_t new_dist = coder->matches[
+ coder->matches_count - 1].dist;
+
+ if ((coder->longest_match_length >= len_main
+ && new_dist < back_main)
+ || (coder->longest_match_length == len_main + 1
+ && !change_pair(back_main, new_dist))
+ || (coder->longest_match_length > len_main + 1)
+ || (coder->longest_match_length + 1 >= len_main
+ && len_main >= 3
+ && change_pair(new_dist, back_main))) {
+ literal(coder, buf, back_res, len_res);
+ return;
+ }
+ }
+
+ // In contrast to LZMA SDK, dictionary could not have been moved
+ // between mf_find() calls, thus it is safe to just increment
+ // the old buf pointer instead of recalculating it with mf_ptr().
+ ++buf;
+
+ const uint32_t limit = len_main - 1;
+
+ for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
+ const uint8_t *const buf_back = buf - coder->reps[i] - 1;
+
+ if (not_equal_16(buf, buf_back))
+ continue;
+
+ uint32_t len;
+ for (len = 2; len < limit
+ && buf[len] == buf_back[len]; ++len) ;
+
+ if (len >= limit) {
+ literal(coder, buf - 1, back_res, len_res);
+ return;
+ }
+ }
+
+ *back_res = back_main + REP_DISTANCES;
+ *len_res = len_main;
+ mf_skip(mf, len_main - 2);
+ return;
+}
diff --git a/src/liblzma/lzma/lzma_encoder_optimum_normal.c b/src/liblzma/lzma/lzma_encoder_optimum_normal.c
new file mode 100644
index 00000000..f0dd92c9
--- /dev/null
+++ b/src/liblzma/lzma/lzma_encoder_optimum_normal.c
@@ -0,0 +1,875 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma_encoder_optimum_normal.c
+//
+// Copyright (C) 1999-2008 Igor Pavlov
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma_encoder_private.h"
+#include "fastpos.h"
+
+
+////////////
+// Prices //
+////////////
+
+static uint32_t
+get_literal_price(const lzma_coder *const coder, const uint32_t pos,
+ const uint32_t prev_byte, const bool match_mode,
+ uint32_t match_byte, uint32_t symbol)
+{
+ const probability *const subcoder = literal_subcoder(coder->literal,
+ coder->literal_context_bits, coder->literal_pos_mask,
+ pos, prev_byte);
+
+ uint32_t price = 0;
+
+ if (!match_mode) {
+ price = rc_bittree_price(subcoder, 8, symbol);
+ } else {
+ uint32_t offset = 0x100;
+ symbol += UINT32_C(1) << 8;
+
+ do {
+ match_byte <<= 1;
+
+ const uint32_t match_bit = match_byte & offset;
+ const uint32_t subcoder_index
+ = offset + match_bit + (symbol >> 8);
+ const uint32_t bit = (symbol >> 7) & 1;
+ price += rc_bit_price(subcoder[subcoder_index], bit);
+
+ symbol <<= 1;
+ offset &= ~(match_byte ^ symbol);
+
+ } while (symbol < (UINT32_C(1) << 16));
+ }
+
+ return price;
+}
+
+
+static inline uint32_t
+get_len_price(const lzma_length_encoder *const lencoder,
+ const uint32_t len, const uint32_t pos_state)
+{
+ // NOTE: Unlike the other price tables, length prices are updated
+ // in lzma_encoder.c
+ return lencoder->prices[pos_state][len - MATCH_LEN_MIN];
+}
+
+
+static inline uint32_t
+get_short_rep_price(const lzma_coder *const coder,
+ const lzma_lzma_state state, const uint32_t pos_state)
+{
+ return rc_bit_0_price(coder->is_rep0[state])
+ + rc_bit_0_price(coder->is_rep0_long[state][pos_state]);
+}
+
+
+static inline uint32_t
+get_pure_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
+ const lzma_lzma_state state, uint32_t pos_state)
+{
+ uint32_t price;
+
+ if (rep_index == 0) {
+ price = rc_bit_0_price(coder->is_rep0[state]);
+ price += rc_bit_1_price(coder->is_rep0_long[state][pos_state]);
+ } else {
+ price = rc_bit_1_price(coder->is_rep0[state]);
+
+ if (rep_index == 1) {
+ price += rc_bit_0_price(coder->is_rep1[state]);
+ } else {
+ price += rc_bit_1_price(coder->is_rep1[state]);
+ price += rc_bit_price(coder->is_rep2[state],
+ rep_index - 2);
+ }
+ }
+
+ return price;
+}
+
+
+static inline uint32_t
+get_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
+ const uint32_t len, const lzma_lzma_state state,
+ const uint32_t pos_state)
+{
+ return get_len_price(&coder->rep_len_encoder, len, pos_state)
+ + get_pure_rep_price(coder, rep_index, state, pos_state);
+}
+
+
+static inline uint32_t
+get_pos_len_price(const lzma_coder *const coder, const uint32_t pos,
+ const uint32_t len, const uint32_t pos_state)
+{
+ const uint32_t len_to_pos_state = get_len_to_pos_state(len);
+ uint32_t price;
+
+ if (pos < FULL_DISTANCES) {
+ price = coder->distances_prices[len_to_pos_state][pos];
+ } else {
+ const uint32_t pos_slot = get_pos_slot_2(pos);
+ price = coder->pos_slot_prices[len_to_pos_state][pos_slot]
+ + coder->align_prices[pos & ALIGN_MASK];
+ }
+
+ price += get_len_price(&coder->match_len_encoder, len, pos_state);
+
+ return price;
+}
+
+
+static void
+fill_distances_prices(lzma_coder *coder)
+{
+ for (uint32_t len_to_pos_state = 0;
+ len_to_pos_state < LEN_TO_POS_STATES;
+ ++len_to_pos_state) {
+
+ uint32_t *const pos_slot_prices
+ = coder->pos_slot_prices[len_to_pos_state];
+
+ // Price to encode the pos_slot.
+ for (uint32_t pos_slot = 0;
+ pos_slot < coder->dist_table_size; ++pos_slot)
+ pos_slot_prices[pos_slot] = rc_bittree_price(
+ coder->pos_slot[len_to_pos_state],
+ POS_SLOT_BITS, pos_slot);
+
+ // For matches with distance >= FULL_DISTANCES, add the price
+ // of the direct bits part of the match distance. (Align bits
+ // are handled by fill_align_prices()).
+ for (uint32_t pos_slot = END_POS_MODEL_INDEX;
+ pos_slot < coder->dist_table_size; ++pos_slot)
+ pos_slot_prices[pos_slot] += rc_direct_price(
+ ((pos_slot >> 1) - 1) - ALIGN_BITS);
+
+ // Distances in the range [0, 3] are fully encoded with
+ // pos_slot, so they are used for coder->distances_prices
+ // as is.
+ for (uint32_t i = 0; i < START_POS_MODEL_INDEX; ++i)
+ coder->distances_prices[len_to_pos_state][i]
+ = pos_slot_prices[i];
+ }
+
+ // Distances in the range [4, 127] depend on pos_slot and pos_special.
+ // We do this in a loop separate from the above loop to avoid
+ // redundant calls to get_pos_slot().
+ for (uint32_t i = START_POS_MODEL_INDEX; i < FULL_DISTANCES; ++i) {
+ const uint32_t pos_slot = get_pos_slot(i);
+ const uint32_t footer_bits = ((pos_slot >> 1) - 1);
+ const uint32_t base = (2 | (pos_slot & 1)) << footer_bits;
+ const uint32_t price = rc_bittree_reverse_price(
+ coder->pos_special + base - pos_slot - 1,
+ footer_bits, i - base);
+
+ for (uint32_t len_to_pos_state = 0;
+ len_to_pos_state < LEN_TO_POS_STATES;
+ ++len_to_pos_state)
+ coder->distances_prices[len_to_pos_state][i]
+ = price + coder->pos_slot_prices[
+ len_to_pos_state][pos_slot];
+ }
+
+ coder->match_price_count = 0;
+ return;
+}
+
+
+static void
+fill_align_prices(lzma_coder *coder)
+{
+ for (uint32_t i = 0; i < ALIGN_TABLE_SIZE; ++i)
+ coder->align_prices[i] = rc_bittree_reverse_price(
+ coder->pos_align, ALIGN_BITS, i);
+
+ coder->align_price_count = 0;
+ return;
+}
+
+
+/////////////
+// Optimal //
+/////////////
+
+static inline void
+make_literal(lzma_optimal *optimal)
+{
+ optimal->back_prev = UINT32_MAX;
+ optimal->prev_1_is_literal = false;
+}
+
+
+static inline void
+make_short_rep(lzma_optimal *optimal)
+{
+ optimal->back_prev = 0;
+ optimal->prev_1_is_literal = false;
+}
+
+
+#define is_short_rep(optimal) \
+ ((optimal).back_prev == 0)
+
+
+static void
+backward(lzma_coder *restrict coder, uint32_t *restrict len_res,
+ uint32_t *restrict back_res, uint32_t cur)
+{
+ coder->opts_end_index = cur;
+
+ uint32_t pos_mem = coder->opts[cur].pos_prev;
+ uint32_t back_mem = coder->opts[cur].back_prev;
+
+ do {
+ if (coder->opts[cur].prev_1_is_literal) {
+ make_literal(&coder->opts[pos_mem]);
+ coder->opts[pos_mem].pos_prev = pos_mem - 1;
+
+ if (coder->opts[cur].prev_2) {
+ coder->opts[pos_mem - 1].prev_1_is_literal
+ = false;
+ coder->opts[pos_mem - 1].pos_prev
+ = coder->opts[cur].pos_prev_2;
+ coder->opts[pos_mem - 1].back_prev
+ = coder->opts[cur].back_prev_2;
+ }
+ }
+
+ const uint32_t pos_prev = pos_mem;
+ const uint32_t back_cur = back_mem;
+
+ back_mem = coder->opts[pos_prev].back_prev;
+ pos_mem = coder->opts[pos_prev].pos_prev;
+
+ coder->opts[pos_prev].back_prev = back_cur;
+ coder->opts[pos_prev].pos_prev = cur;
+ cur = pos_prev;
+
+ } while (cur != 0);
+
+ coder->opts_current_index = coder->opts[0].pos_prev;
+ *len_res = coder->opts[0].pos_prev;
+ *back_res = coder->opts[0].back_prev;
+
+ return;
+}
+
+
+//////////
+// Main //
+//////////
+
+static inline uint32_t
+helper1(lzma_coder *restrict coder, lzma_mf *restrict mf,
+ uint32_t *restrict back_res, uint32_t *restrict len_res,
+ uint32_t position)
+{
+ const uint32_t fast_bytes = mf->find_len_max;
+
+ uint32_t len_main;
+ uint32_t matches_count;
+
+ if (mf->read_ahead == 0) {
+ len_main = mf_find(mf, &matches_count, coder->matches);
+ } else {
+ assert(mf->read_ahead == 1);
+ len_main = coder->longest_match_length;
+ matches_count = coder->matches_count;
+ }
+
+ const uint32_t buf_avail = MIN(mf_avail(mf) + 1, MATCH_LEN_MAX);
+ if (buf_avail < 2) {
+ *back_res = UINT32_MAX;
+ *len_res = 1;
+ return UINT32_MAX;
+ }
+
+ const uint8_t *const buf = mf_ptr(mf) - 1;
+
+ uint32_t rep_lens[REP_DISTANCES];
+ uint32_t rep_max_index = 0;
+
+ for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
+ const uint8_t *const buf_back = buf - coder->reps[i] - 1;
+
+ if (not_equal_16(buf, buf_back)) {
+ rep_lens[i] = 0;
+ continue;
+ }
+
+ uint32_t len_test;
+ for (len_test = 2; len_test < buf_avail
+ && buf[len_test] == buf_back[len_test];
+ ++len_test) ;
+
+ rep_lens[i] = len_test;
+ if (len_test > rep_lens[rep_max_index])
+ rep_max_index = i;
+ }
+
+ if (rep_lens[rep_max_index] >= fast_bytes) {
+ *back_res = rep_max_index;
+ *len_res = rep_lens[rep_max_index];
+ mf_skip(mf, *len_res - 1);
+ return UINT32_MAX;
+ }
+
+
+ if (len_main >= fast_bytes) {
+ *back_res = coder->matches[matches_count - 1].dist
+ + REP_DISTANCES;
+ *len_res = len_main;
+ mf_skip(mf, len_main - 1);
+ return UINT32_MAX;
+ }
+
+ const uint8_t current_byte = *buf;
+ const uint8_t match_byte = *(buf - coder->reps[0] - 1);
+
+ if (len_main < 2 && current_byte != match_byte
+ && rep_lens[rep_max_index] < 2) {
+ *back_res = UINT32_MAX;
+ *len_res = 1;
+ return UINT32_MAX;
+ }
+
+ coder->opts[0].state = coder->state;
+
+ const uint32_t pos_state = position & coder->pos_mask;
+
+ coder->opts[1].price = rc_bit_0_price(
+ coder->is_match[coder->state][pos_state])
+ + get_literal_price(coder, position, buf[-1],
+ !is_literal_state(coder->state),
+ match_byte, current_byte);
+
+ make_literal(&coder->opts[1]);
+
+ const uint32_t match_price = rc_bit_1_price(
+ coder->is_match[coder->state][pos_state]);
+ const uint32_t rep_match_price = match_price
+ + rc_bit_1_price(coder->is_rep[coder->state]);
+
+ if (match_byte == current_byte) {
+ const uint32_t short_rep_price = rep_match_price
+ + get_short_rep_price(
+ coder, coder->state, pos_state);
+
+ if (short_rep_price < coder->opts[1].price) {
+ coder->opts[1].price = short_rep_price;
+ make_short_rep(&coder->opts[1]);
+ }
+ }
+
+ const uint32_t len_end = MAX(len_main, rep_lens[rep_max_index]);
+
+ if (len_end < 2) {
+ *back_res = coder->opts[1].back_prev;
+ *len_res = 1;
+ return UINT32_MAX;
+ }
+
+ coder->opts[1].pos_prev = 0;
+
+ for (uint32_t i = 0; i < REP_DISTANCES; ++i)
+ coder->opts[0].backs[i] = coder->reps[i];
+
+ uint32_t len = len_end;
+ do {
+ coder->opts[len].price = RC_INFINITY_PRICE;
+ } while (--len >= 2);
+
+
+ for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
+ uint32_t rep_len = rep_lens[i];
+ if (rep_len < 2)
+ continue;
+
+ const uint32_t price = rep_match_price + get_pure_rep_price(
+ coder, i, coder->state, pos_state);
+
+ do {
+ const uint32_t cur_and_len_price = price
+ + get_len_price(
+ &coder->rep_len_encoder,
+ rep_len, pos_state);
+
+ if (cur_and_len_price < coder->opts[rep_len].price) {
+ coder->opts[rep_len].price = cur_and_len_price;
+ coder->opts[rep_len].pos_prev = 0;
+ coder->opts[rep_len].back_prev = i;
+ coder->opts[rep_len].prev_1_is_literal = false;
+ }
+ } while (--rep_len >= 2);
+ }
+
+
+ const uint32_t normal_match_price = match_price
+ + rc_bit_0_price(coder->is_rep[coder->state]);
+
+ len = rep_lens[0] >= 2 ? rep_lens[0] + 1 : 2;
+ if (len <= len_main) {
+ uint32_t i = 0;
+ while (len > coder->matches[i].len)
+ ++i;
+
+ for(; ; ++len) {
+ const uint32_t dist = coder->matches[i].dist;
+ const uint32_t cur_and_len_price = normal_match_price
+ + get_pos_len_price(coder,
+ dist, len, pos_state);
+
+ if (cur_and_len_price < coder->opts[len].price) {
+ coder->opts[len].price = cur_and_len_price;
+ coder->opts[len].pos_prev = 0;
+ coder->opts[len].back_prev
+ = dist + REP_DISTANCES;
+ coder->opts[len].prev_1_is_literal = false;
+ }
+
+ if (len == coder->matches[i].len)
+ if (++i == matches_count)
+ break;
+ }
+ }
+
+ return len_end;
+}
+
+
+static inline uint32_t
+helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
+ uint32_t len_end, uint32_t position, const uint32_t cur,
+ const uint32_t fast_bytes, const uint32_t buf_avail_full)
+{
+ uint32_t matches_count = coder->matches_count;
+ uint32_t new_len = coder->longest_match_length;
+ uint32_t pos_prev = coder->opts[cur].pos_prev;
+ uint32_t state;
+
+ if (coder->opts[cur].prev_1_is_literal) {
+ --pos_prev;
+
+ if (coder->opts[cur].prev_2) {
+ state = coder->opts[coder->opts[cur].pos_prev_2].state;
+
+ if (coder->opts[cur].back_prev_2 < REP_DISTANCES)
+ update_long_rep(state);
+ else
+ update_match(state);
+
+ } else {
+ state = coder->opts[pos_prev].state;
+ }
+
+ update_literal(state);
+
+ } else {
+ state = coder->opts[pos_prev].state;
+ }
+
+ if (pos_prev == cur - 1) {
+ if (is_short_rep(coder->opts[cur]))
+ update_short_rep(state);
+ else
+ update_literal(state);
+ } else {
+ uint32_t pos;
+ if (coder->opts[cur].prev_1_is_literal
+ && coder->opts[cur].prev_2) {
+ pos_prev = coder->opts[cur].pos_prev_2;
+ pos = coder->opts[cur].back_prev_2;
+ update_long_rep(state);
+ } else {
+ pos = coder->opts[cur].back_prev;
+ if (pos < REP_DISTANCES)
+ update_long_rep(state);
+ else
+ update_match(state);
+ }
+
+ if (pos < REP_DISTANCES) {
+ reps[0] = coder->opts[pos_prev].backs[pos];
+
+ uint32_t i;
+ for (i = 1; i <= pos; ++i)
+ reps[i] = coder->opts[pos_prev].backs[i - 1];
+
+ for (; i < REP_DISTANCES; ++i)
+ reps[i] = coder->opts[pos_prev].backs[i];
+
+ } else {
+ reps[0] = pos - REP_DISTANCES;
+
+ for (uint32_t i = 1; i < REP_DISTANCES; ++i)
+ reps[i] = coder->opts[pos_prev].backs[i - 1];
+ }
+ }
+
+ coder->opts[cur].state = state;
+
+ for (uint32_t i = 0; i < REP_DISTANCES; ++i)
+ coder->opts[cur].backs[i] = reps[i];
+
+ const uint32_t cur_price = coder->opts[cur].price;
+
+ const uint8_t current_byte = *buf;
+ const uint8_t match_byte = *(buf - reps[0] - 1);
+
+ const uint32_t pos_state = position & coder->pos_mask;
+
+ const uint32_t cur_and_1_price = cur_price
+ + rc_bit_0_price(coder->is_match[state][pos_state])
+ + get_literal_price(coder, position, buf[-1],
+ !is_literal_state(state), match_byte, current_byte);
+
+ bool next_is_literal = false;
+
+ if (cur_and_1_price < coder->opts[cur + 1].price) {
+ coder->opts[cur + 1].price = cur_and_1_price;
+ coder->opts[cur + 1].pos_prev = cur;
+ make_literal(&coder->opts[cur + 1]);
+ next_is_literal = true;
+ }
+
+ const uint32_t match_price = cur_price
+ + rc_bit_1_price(coder->is_match[state][pos_state]);
+ const uint32_t rep_match_price = match_price
+ + rc_bit_1_price(coder->is_rep[state]);
+
+ if (match_byte == current_byte
+ && !(coder->opts[cur + 1].pos_prev < cur
+ && coder->opts[cur + 1].back_prev == 0)) {
+
+ const uint32_t short_rep_price = rep_match_price
+ + get_short_rep_price(coder, state, pos_state);
+
+ if (short_rep_price <= coder->opts[cur + 1].price) {
+ coder->opts[cur + 1].price = short_rep_price;
+ coder->opts[cur + 1].pos_prev = cur;
+ make_short_rep(&coder->opts[cur + 1]);
+ next_is_literal = true;
+ }
+ }
+
+ if (buf_avail_full < 2)
+ return len_end;
+
+ const uint32_t buf_avail = MIN(buf_avail_full, fast_bytes);
+
+ if (!next_is_literal && match_byte != current_byte) { // speed optimization
+ // try literal + rep0
+ const uint8_t *const buf_back = buf - reps[0] - 1;
+ const uint32_t limit = MIN(buf_avail_full, fast_bytes + 1);
+
+ uint32_t len_test = 1;
+ while (len_test < limit && buf[len_test] == buf_back[len_test])
+ ++len_test;
+
+ --len_test;
+
+ if (len_test >= 2) {
+ uint32_t state_2 = state;
+ update_literal(state_2);
+
+ const uint32_t pos_state_next = (position + 1) & coder->pos_mask;
+ const uint32_t next_rep_match_price = cur_and_1_price
+ + rc_bit_1_price(coder->is_match[state_2][pos_state_next])
+ + rc_bit_1_price(coder->is_rep[state_2]);
+
+ //for (; len_test >= 2; --len_test) {
+ const uint32_t offset = cur + 1 + len_test;
+
+ while (len_end < offset)
+ coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+ const uint32_t cur_and_len_price = next_rep_match_price
+ + get_rep_price(coder, 0, len_test,
+ state_2, pos_state_next);
+
+ if (cur_and_len_price < coder->opts[offset].price) {
+ coder->opts[offset].price = cur_and_len_price;
+ coder->opts[offset].pos_prev = cur + 1;
+ coder->opts[offset].back_prev = 0;
+ coder->opts[offset].prev_1_is_literal = true;
+ coder->opts[offset].prev_2 = false;
+ }
+ //}
+ }
+ }
+
+
+ uint32_t start_len = 2; // speed optimization
+
+ for (uint32_t rep_index = 0; rep_index < REP_DISTANCES; ++rep_index) {
+ const uint8_t *const buf_back = buf - reps[rep_index] - 1;
+ if (not_equal_16(buf, buf_back))
+ continue;
+
+ uint32_t len_test;
+ for (len_test = 2; len_test < buf_avail
+ && buf[len_test] == buf_back[len_test];
+ ++len_test) ;
+
+ while (len_end < cur + len_test)
+ coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+ const uint32_t len_test_temp = len_test;
+ const uint32_t price = rep_match_price + get_pure_rep_price(
+ coder, rep_index, state, pos_state);
+
+ do {
+ const uint32_t cur_and_len_price = price
+ + get_len_price(&coder->rep_len_encoder,
+ len_test, pos_state);
+
+ if (cur_and_len_price < coder->opts[cur + len_test].price) {
+ coder->opts[cur + len_test].price = cur_and_len_price;
+ coder->opts[cur + len_test].pos_prev = cur;
+ coder->opts[cur + len_test].back_prev = rep_index;
+ coder->opts[cur + len_test].prev_1_is_literal = false;
+ }
+ } while (--len_test >= 2);
+
+ len_test = len_test_temp;
+
+ if (rep_index == 0)
+ start_len = len_test + 1;
+
+
+ uint32_t len_test_2 = len_test + 1;
+ const uint32_t limit = MIN(buf_avail_full,
+ len_test_2 + fast_bytes);
+ for (; len_test_2 < limit
+ && buf[len_test_2] == buf_back[len_test_2];
+ ++len_test_2) ;
+
+ len_test_2 -= len_test + 1;
+
+ if (len_test_2 >= 2) {
+ uint32_t state_2 = state;
+ update_long_rep(state_2);
+
+ uint32_t pos_state_next = (position + len_test) & coder->pos_mask;
+
+ const uint32_t cur_and_len_literal_price = price
+ + get_len_price(&coder->rep_len_encoder,
+ len_test, pos_state)
+ + rc_bit_0_price(coder->is_match[state_2][pos_state_next])
+ + get_literal_price(coder, position + len_test,
+ buf[len_test - 1], true,
+ buf_back[len_test], buf[len_test]);
+
+ update_literal(state_2);
+
+ pos_state_next = (position + len_test + 1) & coder->pos_mask;
+
+ const uint32_t next_rep_match_price = cur_and_len_literal_price
+ + rc_bit_1_price(coder->is_match[state_2][pos_state_next])
+ + rc_bit_1_price(coder->is_rep[state_2]);
+
+ //for(; len_test_2 >= 2; len_test_2--) {
+ const uint32_t offset = cur + len_test + 1 + len_test_2;
+
+ while (len_end < offset)
+ coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+ const uint32_t cur_and_len_price = next_rep_match_price
+ + get_rep_price(coder, 0, len_test_2,
+ state_2, pos_state_next);
+
+ if (cur_and_len_price < coder->opts[offset].price) {
+ coder->opts[offset].price = cur_and_len_price;
+ coder->opts[offset].pos_prev = cur + len_test + 1;
+ coder->opts[offset].back_prev = 0;
+ coder->opts[offset].prev_1_is_literal = true;
+ coder->opts[offset].prev_2 = true;
+ coder->opts[offset].pos_prev_2 = cur;
+ coder->opts[offset].back_prev_2 = rep_index;
+ }
+ //}
+ }
+ }
+
+
+ //for (uint32_t len_test = 2; len_test <= new_len; ++len_test)
+ if (new_len > buf_avail) {
+ new_len = buf_avail;
+
+ matches_count = 0;
+ while (new_len > coder->matches[matches_count].len)
+ ++matches_count;
+
+ coder->matches[matches_count++].len = new_len;
+ }
+
+
+ if (new_len >= start_len) {
+ const uint32_t normal_match_price = match_price
+ + rc_bit_0_price(coder->is_rep[state]);
+
+ while (len_end < cur + new_len)
+ coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+ uint32_t i = 0;
+ while (start_len > coder->matches[i].len)
+ ++i;
+
+ for (uint32_t len_test = start_len; ; ++len_test) {
+ const uint32_t cur_back = coder->matches[i].dist;
+ uint32_t cur_and_len_price = normal_match_price
+ + get_pos_len_price(coder,
+ cur_back, len_test, pos_state);
+
+ if (cur_and_len_price < coder->opts[cur + len_test].price) {
+ coder->opts[cur + len_test].price = cur_and_len_price;
+ coder->opts[cur + len_test].pos_prev = cur;
+ coder->opts[cur + len_test].back_prev
+ = cur_back + REP_DISTANCES;
+ coder->opts[cur + len_test].prev_1_is_literal = false;
+ }
+
+ if (len_test == coder->matches[i].len) {
+ // Try Match + Literal + Rep0
+ const uint8_t *const buf_back = buf - cur_back - 1;
+ uint32_t len_test_2 = len_test + 1;
+ const uint32_t limit = MIN(buf_avail_full,
+ len_test_2 + fast_bytes);
+
+ for (; len_test_2 < limit &&
+ buf[len_test_2] == buf_back[len_test_2];
+ ++len_test_2) ;
+
+ len_test_2 -= len_test + 1;
+
+ if (len_test_2 >= 2) {
+ uint32_t state_2 = state;
+ update_match(state_2);
+ uint32_t pos_state_next
+ = (position + len_test) & coder->pos_mask;
+
+ const uint32_t cur_and_len_literal_price = cur_and_len_price
+ + rc_bit_0_price(
+ coder->is_match[state_2][pos_state_next])
+ + get_literal_price(coder,
+ position + len_test,
+ buf[len_test - 1],
+ true,
+ buf_back[len_test],
+ buf[len_test]);
+
+ update_literal(state_2);
+ pos_state_next = (pos_state_next + 1) & coder->pos_mask;
+
+ const uint32_t next_rep_match_price
+ = cur_and_len_literal_price
+ + rc_bit_1_price(
+ coder->is_match[state_2][pos_state_next])
+ + rc_bit_1_price(coder->is_rep[state_2]);
+
+ // for(; len_test_2 >= 2; --len_test_2) {
+ const uint32_t offset = cur + len_test + 1 + len_test_2;
+
+ while (len_end < offset)
+ coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+ cur_and_len_price = next_rep_match_price
+ + get_rep_price(coder, 0, len_test_2,
+ state_2, pos_state_next);
+
+ if (cur_and_len_price < coder->opts[offset].price) {
+ coder->opts[offset].price = cur_and_len_price;
+ coder->opts[offset].pos_prev = cur + len_test + 1;
+ coder->opts[offset].back_prev = 0;
+ coder->opts[offset].prev_1_is_literal = true;
+ coder->opts[offset].prev_2 = true;
+ coder->opts[offset].pos_prev_2 = cur;
+ coder->opts[offset].back_prev_2
+ = cur_back + REP_DISTANCES;
+ }
+ //}
+ }
+
+ if (++i == matches_count)
+ break;
+ }
+ }
+ }
+
+ return len_end;
+}
+
+
+extern void
+lzma_lzma_optimum_normal(lzma_coder *restrict coder, lzma_mf *restrict mf,
+ uint32_t *restrict back_res, uint32_t *restrict len_res,
+ uint32_t position)
+{
+ // If we have symbols pending, return the next pending symbol.
+ if (coder->opts_end_index != coder->opts_current_index) {
+ assert(mf->read_ahead > 0);
+ *len_res = coder->opts[coder->opts_current_index].pos_prev
+ - coder->opts_current_index;
+ *back_res = coder->opts[coder->opts_current_index].back_prev;
+ coder->opts_current_index = coder->opts[
+ coder->opts_current_index].pos_prev;
+ return;
+ }
+
+ // Update the price tables. In LZMA SDK <= 4.60 (and possibly later)
+ // this was done in both initialization function and in the main loop.
+ // In liblzma they were moved into this single place.
+ if (mf->read_ahead == 0) {
+ if (coder->match_price_count >= (1 << 7))
+ fill_distances_prices(coder);
+
+ if (coder->align_price_count >= ALIGN_TABLE_SIZE)
+ fill_align_prices(coder);
+ }
+
+ // TODO: This needs quite a bit of cleaning still. But splitting
+ // the oroginal function to two pieces makes it at least a little
+ // more readable, since those two parts don't share many variables.
+
+ uint32_t len_end = helper1(coder, mf, back_res, len_res, position);
+ if (len_end == UINT32_MAX)
+ return;
+
+ uint32_t reps[REP_DISTANCES];
+ memcpy(reps, coder->reps, sizeof(reps));
+
+ uint32_t cur;
+ for (cur = 1; cur < len_end; ++cur) {
+ assert(cur < OPTS);
+
+ coder->longest_match_length = mf_find(
+ mf, &coder->matches_count, coder->matches);
+
+ if (coder->longest_match_length >= mf->find_len_max)
+ break;
+
+ len_end = helper2(coder, reps, mf_ptr(mf) - 1, len_end,
+ position + cur, cur, mf->find_len_max,
+ MIN(mf_avail(mf) + 1, OPTS - 1 - cur));
+ }
+
+ backward(coder, len_res, back_res, cur);
+ return;
+}
diff --git a/src/liblzma/lzma/lzma_encoder_presets.c b/src/liblzma/lzma/lzma_encoder_presets.c
index 966c7c86..08f339e9 100644
--- a/src/liblzma/lzma/lzma_encoder_presets.c
+++ b/src/liblzma/lzma/lzma_encoder_presets.c
@@ -20,15 +20,47 @@
#include "common.h"
+#define pow2(e) (UINT32_C(1) << (e))
+
+
LZMA_API const lzma_options_lzma lzma_preset_lzma[9] = {
-// dictionary_size lc lp pb mode fb mf mfc
-{ UINT32_C(1) << 16, 3, 0, 2, NULL, 0, LZMA_MODE_FAST, 64, LZMA_MF_HC3, 0 },
-{ UINT32_C(1) << 20, 3, 0, 2, NULL, 0, LZMA_MODE_FAST, 64, LZMA_MF_HC4, 0 },
-{ UINT32_C(1) << 19, 3, 0, 2, NULL, 0, LZMA_MODE_BEST, 64, LZMA_MF_BT4, 0 },
-{ UINT32_C(1) << 20, 3, 0, 2, NULL, 0, LZMA_MODE_BEST, 64, LZMA_MF_BT4, 0 },
-{ UINT32_C(1) << 21, 3, 0, 2, NULL, 0, LZMA_MODE_BEST, 128, LZMA_MF_BT4, 0 },
-{ UINT32_C(1) << 22, 3, 0, 2, NULL, 0, LZMA_MODE_BEST, 128, LZMA_MF_BT4, 0 },
-{ UINT32_C(1) << 23, 3, 0, 2, NULL, 0, LZMA_MODE_BEST, 128, LZMA_MF_BT4, 0 },
-{ UINT32_C(1) << 24, 3, 0, 2, NULL, 0, LZMA_MODE_BEST, 273, LZMA_MF_BT4, 0 },
-{ UINT32_C(1) << 25, 3, 0, 2, NULL, 0, LZMA_MODE_BEST, 273, LZMA_MF_BT4, 0 },
+// dict lc lp pb mode fb mf mfc
+{ pow2(16), NULL, 0, 3, 0, 2, false, LZMA_MODE_FAST, 64, LZMA_MF_HC3, 0, 0, 0, 0, 0, NULL, NULL },
+{ pow2(20), NULL, 0, 3, 0, 0, false, LZMA_MODE_FAST, 64, LZMA_MF_HC4, 0, 0, 0, 0, 0, NULL, NULL },
+{ pow2(19), NULL, 0, 3, 0, 0, false, LZMA_MODE_NORMAL, 64, LZMA_MF_BT4, 0, 0, 0, 0, 0, NULL, NULL },
+{ pow2(20), NULL, 0, 3, 0, 0, false, LZMA_MODE_NORMAL, 64, LZMA_MF_BT4, 0, 0, 0, 0, 0, NULL, NULL },
+{ pow2(21), NULL, 0, 3, 0, 0, false, LZMA_MODE_NORMAL, 128, LZMA_MF_BT4, 0, 0, 0, 0, 0, NULL, NULL },
+{ pow2(22), NULL, 0, 3, 0, 0, false, LZMA_MODE_NORMAL, 128, LZMA_MF_BT4, 0, 0, 0, 0, 0, NULL, NULL },
+{ pow2(23), NULL, 0, 3, 0, 0, false, LZMA_MODE_NORMAL, 128, LZMA_MF_BT4, 0, 0, 0, 0, 0, NULL, NULL },
+{ pow2(24), NULL, 0, 3, 0, 0, false, LZMA_MODE_NORMAL, 273, LZMA_MF_BT4, 0, 0, 0, 0, 0, NULL, NULL },
+{ pow2(25), NULL, 0, 3, 0, 0, false, LZMA_MODE_NORMAL, 273, LZMA_MF_BT4, 0, 0, 0, 0, 0, NULL, NULL },
};
+
+
+/*
+extern LZMA_API lzma_bool
+lzma_preset_lzma(lzma_options_lzma *options, uint32_t level)
+{
+ *options = (lzma_options_lzma){
+
+ };
+
+ options->literal_context_bits = LZMA_LITERAL_CONTEXT_BITS_DEFAULT
+ options->literal_pos_bits = LZMA_LITERAL_POS_BITS_DEFAULT;
+ options->pos_bits = LZMA_POS_BITS_DEFAULT;
+ options->preset_dictionary = NULL;
+ options->preset_dictionary_size = 0;
+ options->persistent = false;
+
+ options->mode = level <= 2 ? LZMA_MODE_FAST : LZMA_MODE_NORMAL;
+ options->fast_bytes = level <=
+
+ options->match_finder = level == 1 ? LZMA_MF_HC3
+ : (level == 2 ? LZMA_MF_HC4 : LZMA_MF_BT4);
+ options->match_finder_cycles = 0;
+
+
+
+ options->dictionary_size =
+}
+*/
diff --git a/src/liblzma/lzma/lzma_encoder_private.h b/src/liblzma/lzma/lzma_encoder_private.h
index a16051f8..7533bc79 100644
--- a/src/liblzma/lzma/lzma_encoder_private.h
+++ b/src/liblzma/lzma/lzma_encoder_private.h
@@ -21,20 +21,27 @@
#ifndef LZMA_LZMA_ENCODER_PRIVATE_H
#define LZMA_LZMA_ENCODER_PRIVATE_H
-#include "lzma_encoder.h"
-#include "lzma_common.h"
#include "lz_encoder.h"
#include "range_encoder.h"
+#include "lzma_common.h"
+#include "lzma_encoder.h"
+
+// Macro to compare if the first two bytes in two buffers differ. This is
+// needed in lzma_lzma_optimum_*() to test if the match is at least
+// MATCH_LEN_MIN bytes. Unaligned access gives tiny gain so there's no
+// reason to not use it when it is supported.
+#ifdef HAVE_FAST_UNALIGNED_ACCESS
+# define not_equal_16(a, b) \
+ (*(const uint16_t *)(a) != *(const uint16_t *)(b))
+#else
+# define not_equal_16(a, b) \
+ ((a)[0] != (b)[0] || (a)[1] != (b)[1])
+#endif
-#define move_pos(num) \
-do { \
- assert((int32_t)(num) >= 0); \
- if ((num) != 0) { \
- coder->additional_offset += num; \
- coder->lz.skip(&coder->lz, num); \
- } \
-} while (0)
+
+// Optimal - Number of entries in the optimum array.
+#define OPTS (1 << 12)
typedef struct {
@@ -54,7 +61,7 @@ typedef struct {
typedef struct {
lzma_lzma_state state;
- bool prev_1_is_char;
+ bool prev_1_is_literal;
bool prev_2;
uint32_t pos_prev_2;
@@ -70,132 +77,79 @@ typedef struct {
struct lzma_coder_s {
- // Next coder in the chain
- lzma_next_coder next;
-
- // In window and match finder
- lzma_lz_encoder lz;
-
- // Range encoder
+ /// Range encoder
lzma_range_encoder rc;
- // State
+ /// State
lzma_lzma_state state;
- uint8_t previous_byte;
+
+ /// The four most recent match distances
uint32_t reps[REP_DISTANCES];
- // Misc
- uint32_t match_distances[MATCH_MAX_LEN * 2 + 2 + 1];
- uint32_t num_distance_pairs;
- uint32_t additional_offset;
- uint32_t now_pos; // Lowest 32 bits are enough here.
- bool best_compression; ///< True when LZMA_MODE_BEST is used
+ /// Array of match candidates
+ lzma_match matches[MATCH_LEN_MAX + 1];
+
+ /// Number of match candidates in matches[]
+ uint32_t matches_count;
+
+ /// Varibale to hold the length of the longest match between calls
+ /// to lzma_lzma_optimum_*().
+ uint32_t longest_match_length;
+
+ /// True if using getoptimumfast
+ bool fast_mode;
+
+ /// True if the encoder has been initialized by encoding the first
+ /// byte as a literal.
bool is_initialized;
+
+ /// True if the range encoder has been flushed, but not all bytes
+ /// have been written to the output buffer yet.
bool is_flushed;
- bool write_eopm;
- // Literal encoder
- lzma_literal_coder literal_coder;
+ uint32_t pos_mask; ///< (1 << pos_bits) - 1
+ uint32_t literal_context_bits;
+ uint32_t literal_pos_mask;
- // Bit encoders
+ // These are the same as in lzma_decoder.c. See comments there.
+ probability literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE];
probability is_match[STATES][POS_STATES_MAX];
probability is_rep[STATES];
probability is_rep0[STATES];
probability is_rep1[STATES];
probability is_rep2[STATES];
probability is_rep0_long[STATES][POS_STATES_MAX];
- probability pos_encoders[FULL_DISTANCES - END_POS_MODEL_INDEX];
+ probability pos_slot[LEN_TO_POS_STATES][POS_SLOTS];
+ probability pos_special[FULL_DISTANCES - END_POS_MODEL_INDEX];
+ probability pos_align[ALIGN_TABLE_SIZE];
- // Bit Tree Encoders
- probability pos_slot_encoder[LEN_TO_POS_STATES][1 << POS_SLOT_BITS];
- probability pos_align_encoder[1 << ALIGN_BITS];
-
- // Length encoders
+ // These are the same as in lzma_decoder.c except that the encoders
+ // include also price tables.
lzma_length_encoder match_len_encoder;
lzma_length_encoder rep_len_encoder;
- lzma_length_encoder *prev_len_encoder;
- // Optimal
- lzma_optimal optimum[OPTS];
- uint32_t optimum_end_index;
- uint32_t optimum_current_index;
- uint32_t longest_match_length;
- bool longest_match_was_found;
-
- // Prices
- uint32_t pos_slot_prices[LEN_TO_POS_STATES][DIST_TABLE_SIZE_MAX];
+ // Price tables
+ uint32_t pos_slot_prices[LEN_TO_POS_STATES][POS_SLOTS];
uint32_t distances_prices[LEN_TO_POS_STATES][FULL_DISTANCES];
- uint32_t align_prices[ALIGN_TABLE_SIZE];
- uint32_t align_price_count;
uint32_t dist_table_size;
uint32_t match_price_count;
- // LZMA specific settings
- uint32_t dictionary_size; ///< Size in bytes
- uint32_t fast_bytes;
- uint32_t pos_state_bits;
- uint32_t pos_mask; ///< (1 << pos_state_bits) - 1
-};
-
-
-extern void lzma_length_encoder_update_table(lzma_length_encoder *lencoder,
- const uint32_t pos_state);
+ uint32_t align_prices[ALIGN_TABLE_SIZE];
+ uint32_t align_price_count;
-extern bool lzma_lzma_encode(lzma_coder *coder, uint8_t *restrict out,
- size_t *restrict out_pos, size_t out_size);
+ // Optimal
+ uint32_t opts_end_index;
+ uint32_t opts_current_index;
+ lzma_optimal opts[OPTS];
+};
-extern void lzma_get_optimum(lzma_coder *restrict coder,
- uint32_t *restrict back_res, uint32_t *restrict len_res);
-extern void lzma_get_optimum_fast(lzma_coder *restrict coder,
+extern void lzma_lzma_optimum_fast(
+ lzma_coder *restrict coder, lzma_mf *restrict mf,
uint32_t *restrict back_res, uint32_t *restrict len_res);
-
-// NOTE: Don't add 'restrict'.
-static inline void
-lzma_read_match_distances(lzma_coder *coder,
- uint32_t *len_res, uint32_t *num_distance_pairs)
-{
- *len_res = 0;
-
- coder->lz.get_matches(&coder->lz, coder->match_distances);
-
- *num_distance_pairs = coder->match_distances[0];
-
- if (*num_distance_pairs > 0) {
- *len_res = coder->match_distances[*num_distance_pairs - 1];
- assert(*len_res <= MATCH_MAX_LEN);
-
- if (*len_res == coder->fast_bytes) {
- uint32_t offset = *len_res - 1;
- const uint32_t distance = coder->match_distances[
- *num_distance_pairs] + 1;
- uint32_t limit = MATCH_MAX_LEN - *len_res;
-
- assert(offset + limit < coder->lz.keep_size_after);
- assert(coder->lz.read_pos <= coder->lz.write_pos);
-
- // If we are close to end of the stream, we may need
- // to limit the length of the match.
- if (coder->lz.write_pos - coder->lz.read_pos
- < offset + limit)
- limit = coder->lz.write_pos
- - (coder->lz.read_pos + offset);
-
- offset += coder->lz.read_pos;
- uint32_t i = 0;
- while (i < limit && coder->lz.buffer[offset + i]
- == coder->lz.buffer[
- offset + i - distance])
- ++i;
-
- *len_res += i;
- }
- }
-
- ++coder->additional_offset;
-
- return;
-}
+extern void lzma_lzma_optimum_normal(lzma_coder *restrict coder,
+ lzma_mf *restrict mf, uint32_t *restrict back_res,
+ uint32_t *restrict len_res, uint32_t position);
#endif
diff --git a/src/liblzma/lzma/lzma_literal.c b/src/liblzma/lzma/lzma_literal.c
deleted file mode 100644
index 3611a1f7..00000000
--- a/src/liblzma/lzma/lzma_literal.c
+++ /dev/null
@@ -1,51 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file lzma_literal.c
-/// \brief Literal Coder
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#include "lzma_literal.h"
-
-
-extern lzma_ret
-lzma_literal_init(lzma_literal_coder *coder,
- uint32_t literal_context_bits, uint32_t literal_pos_bits)
-{
- // Verify that arguments are sane.
- if (literal_context_bits > LZMA_LITERAL_CONTEXT_BITS_MAX
- || literal_pos_bits > LZMA_LITERAL_POS_BITS_MAX)
- return LZMA_HEADER_ERROR;
-
- // Calculate the number of states the literal coder must store.
- const uint32_t states = literal_states(
- literal_pos_bits, literal_context_bits);
-
- // Store the new settings.
- coder->literal_context_bits = literal_context_bits;
- coder->literal_pos_bits = literal_pos_bits;
-
- // Calculate also the literal_pos_mask. It's not changed
- // anywhere else than here.
- coder->literal_pos_mask = (1 << literal_pos_bits) - 1;
-
- // Reset the literal coder.
- for (uint32_t i = 0; i < states; ++i)
- for (uint32_t j = 0; j < LIT_SIZE; ++j)
- bit_reset(coder->coders[i][j]);
-
- return LZMA_OK;
-}
diff --git a/src/liblzma/lzma/lzma_literal.h b/src/liblzma/lzma/lzma_literal.h
deleted file mode 100644
index 208abd99..00000000
--- a/src/liblzma/lzma/lzma_literal.h
+++ /dev/null
@@ -1,71 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file lzma_literal.h
-/// \brief Literal Coder
-///
-/// This is used as is by both LZMA encoder and decoder.
-//
-// Copyright (C) 1999-2006 Igor Pavlov
-// Copyright (C) 2007 Lasse Collin
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef LZMA_LITERAL_H
-#define LZMA_LITERAL_H
-
-#include "common.h"
-
-// We need typedef of `probability'.
-#include "range_common.h"
-
-
-/// Each literal coder is divided in three sections:
-/// - 0x001-0x0FF: Without match byte
-/// - 0x101-0x1FF: With match byte; match bit is 0
-/// - 0x201-0x2FF: With match byte; match bit is 1
-#define LIT_SIZE 0x300
-
-/// Calculate how many states are needed. Each state has
-/// LIT_SIZE `probability' variables.
-#define literal_states(literal_context_bits, literal_pos_bits) \
- (1U << ((literal_context_bits) + (literal_pos_bits)))
-
-/// Locate the literal coder for the next literal byte. The choice depends on
-/// - the lowest literal_pos_bits bits of the position of the current
-/// byte; and
-/// - the highest literal_context_bits bits of the previous byte.
-#define literal_get_subcoder(literal_coder, pos, prev_byte) \
- (literal_coder).coders[(((pos) & (literal_coder).literal_pos_mask) \
- << (literal_coder).literal_context_bits) \
- + ((prev_byte) >> (8 - (literal_coder).literal_context_bits))]
-
-
-typedef struct {
- uint32_t literal_context_bits;
- uint32_t literal_pos_bits;
-
- /// literal_pos_mask is always (1 << literal_pos_bits) - 1.
- uint32_t literal_pos_mask;
-
- /// There are (1 << (literal_pos_bits + literal_context_bits))
- /// literal coders.
- probability coders[1 << LZMA_LITERAL_BITS_MAX][LIT_SIZE];
-
-} lzma_literal_coder;
-
-
-extern lzma_ret lzma_literal_init(
- lzma_literal_coder *coder,
- uint32_t literal_context_bits, uint32_t literal_pos_bits);
-
-#endif