| 1 | /*
|
|---|
| 2 | * LZMA2Options
|
|---|
| 3 | *
|
|---|
| 4 | * Author: Lasse Collin <lasse.collin@tukaani.org>
|
|---|
| 5 | *
|
|---|
| 6 | * This file has been put into the public domain.
|
|---|
| 7 | * You can do whatever you want with this file.
|
|---|
| 8 | */
|
|---|
| 9 |
|
|---|
| 10 | package org.tukaani.xz;
|
|---|
| 11 |
|
|---|
| 12 | import java.io.InputStream;
|
|---|
| 13 | import java.io.IOException;
|
|---|
| 14 | import org.tukaani.xz.lz.LZEncoder;
|
|---|
| 15 | import org.tukaani.xz.lzma.LZMAEncoder;
|
|---|
| 16 |
|
|---|
| 17 | /**
|
|---|
| 18 | * LZMA2 compression options.
|
|---|
| 19 | * <p>
|
|---|
| 20 | * While this allows setting the LZMA2 compression options in detail,
|
|---|
| 21 | * often you only need <code>LZMA2Options()</code> or
|
|---|
| 22 | * <code>LZMA2Options(int)</code>.
|
|---|
| 23 | */
|
|---|
| 24 | public class LZMA2Options extends FilterOptions {
|
|---|
| 25 | /**
|
|---|
| 26 | * Minimum valid compression preset level is 0.
|
|---|
| 27 | */
|
|---|
| 28 | public static final int PRESET_MIN = 0;
|
|---|
| 29 |
|
|---|
| 30 | /**
|
|---|
| 31 | * Maximum valid compression preset level is 9.
|
|---|
| 32 | */
|
|---|
| 33 | public static final int PRESET_MAX = 9;
|
|---|
| 34 |
|
|---|
| 35 | /**
|
|---|
| 36 | * Default compression preset level is 6.
|
|---|
| 37 | */
|
|---|
| 38 | public static final int PRESET_DEFAULT = 6;
|
|---|
| 39 |
|
|---|
| 40 | /**
|
|---|
| 41 | * Minimum dictionary size is 4 KiB.
|
|---|
| 42 | */
|
|---|
| 43 | public static final int DICT_SIZE_MIN = 4096;
|
|---|
| 44 |
|
|---|
| 45 | /**
|
|---|
| 46 | * Maximum dictionary size for compression is 768 MiB.
|
|---|
| 47 | * <p>
|
|---|
| 48 | * The decompressor supports bigger dictionaries, up to almost 2 GiB.
|
|---|
| 49 | * With HC4 the encoder would support dictionaries bigger than 768 MiB.
|
|---|
| 50 | * The 768 MiB limit comes from the current implementation of BT4 where
|
|---|
| 51 | * we would otherwise hit the limits of signed ints in array indexing.
|
|---|
| 52 | * <p>
|
|---|
| 53 | * If you really need bigger dictionary for decompression,
|
|---|
| 54 | * use {@link LZMA2InputStream} directly.
|
|---|
| 55 | */
|
|---|
| 56 | public static final int DICT_SIZE_MAX = 768 << 20;
|
|---|
| 57 |
|
|---|
| 58 | /**
|
|---|
| 59 | * The default dictionary size is 8 MiB.
|
|---|
| 60 | */
|
|---|
| 61 | public static final int DICT_SIZE_DEFAULT = 8 << 20;
|
|---|
| 62 |
|
|---|
| 63 | /**
|
|---|
| 64 | * Maximum value for lc + lp is 4.
|
|---|
| 65 | */
|
|---|
| 66 | public static final int LC_LP_MAX = 4;
|
|---|
| 67 |
|
|---|
| 68 | /**
|
|---|
| 69 | * The default number of literal context bits is 3.
|
|---|
| 70 | */
|
|---|
| 71 | public static final int LC_DEFAULT = 3;
|
|---|
| 72 |
|
|---|
| 73 | /**
|
|---|
| 74 | * The default number of literal position bits is 0.
|
|---|
| 75 | */
|
|---|
| 76 | public static final int LP_DEFAULT = 0;
|
|---|
| 77 |
|
|---|
| 78 | /**
|
|---|
| 79 | * Maximum value for pb is 4.
|
|---|
| 80 | */
|
|---|
| 81 | public static final int PB_MAX = 4;
|
|---|
| 82 |
|
|---|
| 83 | /**
|
|---|
| 84 | * The default number of position bits is 2.
|
|---|
| 85 | */
|
|---|
| 86 | public static final int PB_DEFAULT = 2;
|
|---|
| 87 |
|
|---|
| 88 | /**
|
|---|
| 89 | * Compression mode: uncompressed.
|
|---|
| 90 | * The data is wrapped into a LZMA2 stream without compression.
|
|---|
| 91 | */
|
|---|
| 92 | public static final int MODE_UNCOMPRESSED = 0;
|
|---|
| 93 |
|
|---|
| 94 | /**
|
|---|
| 95 | * Compression mode: fast.
|
|---|
| 96 | * This is usually combined with a hash chain match finder.
|
|---|
| 97 | */
|
|---|
| 98 | public static final int MODE_FAST = LZMAEncoder.MODE_FAST;
|
|---|
| 99 |
|
|---|
| 100 | /**
|
|---|
| 101 | * Compression mode: normal.
|
|---|
| 102 | * This is usually combined with a binary tree match finder.
|
|---|
| 103 | */
|
|---|
| 104 | public static final int MODE_NORMAL = LZMAEncoder.MODE_NORMAL;
|
|---|
| 105 |
|
|---|
| 106 | /**
|
|---|
| 107 | * Minimum value for <code>niceLen</code> is 8.
|
|---|
| 108 | */
|
|---|
| 109 | public static final int NICE_LEN_MIN = 8;
|
|---|
| 110 |
|
|---|
| 111 | /**
|
|---|
| 112 | * Maximum value for <code>niceLen</code> is 273.
|
|---|
| 113 | */
|
|---|
| 114 | public static final int NICE_LEN_MAX = 273;
|
|---|
| 115 |
|
|---|
| 116 | /**
|
|---|
| 117 | * Match finder: Hash Chain 2-3-4
|
|---|
| 118 | */
|
|---|
| 119 | public static final int MF_HC4 = LZEncoder.MF_HC4;
|
|---|
| 120 |
|
|---|
| 121 | /**
|
|---|
| 122 | * Match finder: Binary tree 2-3-4
|
|---|
| 123 | */
|
|---|
| 124 | public static final int MF_BT4 = LZEncoder.MF_BT4;
|
|---|
| 125 |
|
|---|
| 126 | private static final int[] presetToDictSize = {
|
|---|
| 127 | 1 << 18, 1 << 20, 1 << 21, 1 << 22, 1 << 22,
|
|---|
| 128 | 1 << 23, 1 << 23, 1 << 24, 1 << 25, 1 << 26 };
|
|---|
| 129 |
|
|---|
| 130 | private static final int[] presetToDepthLimit = { 4, 8, 24, 48 };
|
|---|
| 131 |
|
|---|
| 132 | private int dictSize;
|
|---|
| 133 | private byte[] presetDict = null;
|
|---|
| 134 | private int lc;
|
|---|
| 135 | private int lp;
|
|---|
| 136 | private int pb;
|
|---|
| 137 | private int mode;
|
|---|
| 138 | private int niceLen;
|
|---|
| 139 | private int mf;
|
|---|
| 140 | private int depthLimit;
|
|---|
| 141 |
|
|---|
| 142 | /**
|
|---|
| 143 | * Creates new LZMA2 options and sets them to the default values.
|
|---|
| 144 | * This is equivalent to <code>LZMA2Options(PRESET_DEFAULT)</code>.
|
|---|
| 145 | */
|
|---|
| 146 | public LZMA2Options() {
|
|---|
| 147 | try {
|
|---|
| 148 | setPreset(PRESET_DEFAULT);
|
|---|
| 149 | } catch (UnsupportedOptionsException e) {
|
|---|
| 150 | assert false;
|
|---|
| 151 | throw new RuntimeException();
|
|---|
| 152 | }
|
|---|
| 153 | }
|
|---|
| 154 |
|
|---|
| 155 | /**
|
|---|
| 156 | * Creates new LZMA2 options and sets them to the given preset.
|
|---|
| 157 | *
|
|---|
| 158 | * @throws UnsupportedOptionsException
|
|---|
| 159 | * <code>preset</code> is not supported
|
|---|
| 160 | */
|
|---|
| 161 | public LZMA2Options(int preset) throws UnsupportedOptionsException {
|
|---|
| 162 | setPreset(preset);
|
|---|
| 163 | }
|
|---|
| 164 |
|
|---|
| 165 | /**
|
|---|
| 166 | * Creates new LZMA2 options and sets them to the given custom values.
|
|---|
| 167 | *
|
|---|
| 168 | * @throws UnsupportedOptionsException
|
|---|
| 169 | * unsupported options were specified
|
|---|
| 170 | */
|
|---|
| 171 | public LZMA2Options(int dictSize, int lc, int lp, int pb, int mode,
|
|---|
| 172 | int niceLen, int mf, int depthLimit)
|
|---|
| 173 | throws UnsupportedOptionsException {
|
|---|
| 174 | setDictSize(dictSize);
|
|---|
| 175 | setLcLp(lc, lp);
|
|---|
| 176 | setPb(pb);
|
|---|
| 177 | setMode(mode);
|
|---|
| 178 | setNiceLen(niceLen);
|
|---|
| 179 | setMatchFinder(mf);
|
|---|
| 180 | setDepthLimit(depthLimit);
|
|---|
| 181 | }
|
|---|
| 182 |
|
|---|
| 183 | /**
|
|---|
| 184 | * Sets the compression options to the given preset.
|
|---|
| 185 | * <p>
|
|---|
| 186 | * The presets 0-3 are fast presets with medium compression.
|
|---|
| 187 | * The presets 4-6 are fairly slow presets with high compression.
|
|---|
| 188 | * The default preset (<code>PRESET_DEFAULT</code>) is 6.
|
|---|
| 189 | * <p>
|
|---|
| 190 | * The presets 7-9 are like the preset 6 but use bigger dictionaries
|
|---|
| 191 | * and have higher compressor and decompressor memory requirements.
|
|---|
| 192 | * Unless the uncompressed size of the file exceeds 8 MiB,
|
|---|
| 193 | * 16 MiB, or 32 MiB, it is waste of memory to use the
|
|---|
| 194 | * presets 7, 8, or 9, respectively.
|
|---|
| 195 | *
|
|---|
| 196 | * @throws UnsupportedOptionsException
|
|---|
| 197 | * <code>preset</code> is not supported
|
|---|
| 198 | */
|
|---|
| 199 | public void setPreset(int preset) throws UnsupportedOptionsException {
|
|---|
| 200 | if (preset < 0 || preset > 9)
|
|---|
| 201 | throw new UnsupportedOptionsException(
|
|---|
| 202 | "Unsupported preset: " + preset);
|
|---|
| 203 |
|
|---|
| 204 | lc = LC_DEFAULT;
|
|---|
| 205 | lp = LP_DEFAULT;
|
|---|
| 206 | pb = PB_DEFAULT;
|
|---|
| 207 | dictSize = presetToDictSize[preset];
|
|---|
| 208 |
|
|---|
| 209 | if (preset <= 3) {
|
|---|
| 210 | mode = MODE_FAST;
|
|---|
| 211 | mf = MF_HC4;
|
|---|
| 212 | niceLen = preset <= 1 ? 128 : NICE_LEN_MAX;
|
|---|
| 213 | depthLimit = presetToDepthLimit[preset];
|
|---|
| 214 | } else {
|
|---|
| 215 | mode = MODE_NORMAL;
|
|---|
| 216 | mf = MF_BT4;
|
|---|
| 217 | niceLen = (preset == 4) ? 16 : (preset == 5) ? 32 : 64;
|
|---|
| 218 | depthLimit = 0;
|
|---|
| 219 | }
|
|---|
| 220 | }
|
|---|
| 221 |
|
|---|
| 222 | /**
|
|---|
| 223 | * Sets the dictionary size in bytes.
|
|---|
| 224 | * <p>
|
|---|
| 225 | * The dictionary (or history buffer) holds the most recently seen
|
|---|
| 226 | * uncompressed data. Bigger dictionary usually means better compression.
|
|---|
| 227 | * However, using a dictioanary bigger than the size of the uncompressed
|
|---|
| 228 | * data is waste of memory.
|
|---|
| 229 | * <p>
|
|---|
| 230 | * Any value in the range [DICT_SIZE_MIN, DICT_SIZE_MAX] is valid,
|
|---|
| 231 | * but sizes of 2^n and 2^n + 2^(n-1) bytes are somewhat
|
|---|
| 232 | * recommended.
|
|---|
| 233 | *
|
|---|
| 234 | * @throws UnsupportedOptionsException
|
|---|
| 235 | * <code>dictSize</code> is not supported
|
|---|
| 236 | */
|
|---|
| 237 | public void setDictSize(int dictSize) throws UnsupportedOptionsException {
|
|---|
| 238 | if (dictSize < DICT_SIZE_MIN)
|
|---|
| 239 | throw new UnsupportedOptionsException(
|
|---|
| 240 | "LZMA2 dictionary size must be at least 4 KiB: "
|
|---|
| 241 | + dictSize + " B");
|
|---|
| 242 |
|
|---|
| 243 | if (dictSize > DICT_SIZE_MAX)
|
|---|
| 244 | throw new UnsupportedOptionsException(
|
|---|
| 245 | "LZMA2 dictionary size must not exceed "
|
|---|
| 246 | + (DICT_SIZE_MAX >> 20) + " MiB: " + dictSize + " B");
|
|---|
| 247 |
|
|---|
| 248 | this.dictSize = dictSize;
|
|---|
| 249 | }
|
|---|
| 250 |
|
|---|
| 251 | /**
|
|---|
| 252 | * Gets the dictionary size in bytes.
|
|---|
| 253 | */
|
|---|
| 254 | public int getDictSize() {
|
|---|
| 255 | return dictSize;
|
|---|
| 256 | }
|
|---|
| 257 |
|
|---|
| 258 | /**
|
|---|
| 259 | * Sets a preset dictionary. Use null to disable the use of
|
|---|
| 260 | * a preset dictionary. By default there is no preset dictionary.
|
|---|
| 261 | * <p>
|
|---|
| 262 | * <b>The .xz format doesn't support a preset dictionary for now.
|
|---|
| 263 | * Do not set a preset dictionary unless you use raw LZMA2.</b>
|
|---|
| 264 | * <p>
|
|---|
| 265 | * Preset dictionary can be useful when compressing many similar,
|
|---|
| 266 | * relatively small chunks of data independently from each other.
|
|---|
| 267 | * A preset dictionary should contain typical strings that occur in
|
|---|
| 268 | * the files being compressed. The most probable strings should be
|
|---|
| 269 | * near the end of the preset dictionary. The preset dictionary used
|
|---|
| 270 | * for compression is also needed for decompression.
|
|---|
| 271 | */
|
|---|
| 272 | public void setPresetDict(byte[] presetDict) {
|
|---|
| 273 | this.presetDict = presetDict;
|
|---|
| 274 | }
|
|---|
| 275 |
|
|---|
| 276 | /**
|
|---|
| 277 | * Gets the preset dictionary.
|
|---|
| 278 | */
|
|---|
| 279 | public byte[] getPresetDict() {
|
|---|
| 280 | return presetDict;
|
|---|
| 281 | }
|
|---|
| 282 |
|
|---|
| 283 | /**
|
|---|
| 284 | * Sets the number of literal context bits and literal position bits.
|
|---|
| 285 | * <p>
|
|---|
| 286 | * The sum of <code>lc</code> and <code>lp</code> is limited to 4.
|
|---|
| 287 | * Trying to exceed it will throw an exception. This function lets
|
|---|
| 288 | * you change both at the same time.
|
|---|
| 289 | *
|
|---|
| 290 | * @throws UnsupportedOptionsException
|
|---|
| 291 | * <code>lc</code> and <code>lp</code>
|
|---|
| 292 | * are invalid
|
|---|
| 293 | */
|
|---|
| 294 | public void setLcLp(int lc, int lp) throws UnsupportedOptionsException {
|
|---|
| 295 | if (lc < 0 || lp < 0 || lc > LC_LP_MAX || lp > LC_LP_MAX
|
|---|
| 296 | || lc + lp > LC_LP_MAX)
|
|---|
| 297 | throw new UnsupportedOptionsException(
|
|---|
| 298 | "lc + lp must not exceed " + LC_LP_MAX + ": "
|
|---|
| 299 | + lc + " + " + lp);
|
|---|
| 300 |
|
|---|
| 301 | this.lc = lc;
|
|---|
| 302 | this.lp = lp;
|
|---|
| 303 | }
|
|---|
| 304 |
|
|---|
| 305 | /**
|
|---|
| 306 | * Sets the number of literal context bits.
|
|---|
| 307 | * <p>
|
|---|
| 308 | * All bytes that cannot be encoded as matches are encoded as literals.
|
|---|
| 309 | * That is, literals are simply 8-bit bytes that are encoded one at
|
|---|
| 310 | * a time.
|
|---|
| 311 | * <p>
|
|---|
| 312 | * The literal coding makes an assumption that the highest <code>lc</code>
|
|---|
| 313 | * bits of the previous uncompressed byte correlate with the next byte.
|
|---|
| 314 | * For example, in typical English text, an upper-case letter is often
|
|---|
| 315 | * followed by a lower-case letter, and a lower-case letter is usually
|
|---|
| 316 | * followed by another lower-case letter. In the US-ASCII character set,
|
|---|
| 317 | * the highest three bits are 010 for upper-case letters and 011 for
|
|---|
| 318 | * lower-case letters. When <code>lc</code> is at least 3, the literal
|
|---|
| 319 | * coding can take advantage of this property in the uncompressed data.
|
|---|
| 320 | * <p>
|
|---|
| 321 | * The default value (3) is usually good. If you want maximum compression,
|
|---|
| 322 | * try <code>setLc(4)</code>. Sometimes it helps a little, and sometimes it
|
|---|
| 323 | * makes compression worse. If it makes it worse, test for example
|
|---|
| 324 | * <code>setLc(2)</code> too.
|
|---|
| 325 | *
|
|---|
| 326 | * @throws UnsupportedOptionsException
|
|---|
| 327 | * <code>lc</code> is invalid, or the sum
|
|---|
| 328 | * of <code>lc</code> and <code>lp</code>
|
|---|
| 329 | * exceed LC_LP_MAX
|
|---|
| 330 | */
|
|---|
| 331 | public void setLc(int lc) throws UnsupportedOptionsException {
|
|---|
| 332 | setLcLp(lc, lp);
|
|---|
| 333 | }
|
|---|
| 334 |
|
|---|
| 335 | /**
|
|---|
| 336 | * Sets the number of literal position bits.
|
|---|
| 337 | * <p>
|
|---|
| 338 | * This affets what kind of alignment in the uncompressed data is
|
|---|
| 339 | * assumed when encoding literals. See {@link #setPb(int) setPb} for
|
|---|
| 340 | * more information about alignment.
|
|---|
| 341 | *
|
|---|
| 342 | * @throws UnsupportedOptionsException
|
|---|
| 343 | * <code>lp</code> is invalid, or the sum
|
|---|
| 344 | * of <code>lc</code> and <code>lp</code>
|
|---|
| 345 | * exceed LC_LP_MAX
|
|---|
| 346 | */
|
|---|
| 347 | public void setLp(int lp) throws UnsupportedOptionsException {
|
|---|
| 348 | setLcLp(lc, lp);
|
|---|
| 349 | }
|
|---|
| 350 |
|
|---|
| 351 | /**
|
|---|
| 352 | * Gets the number of literal context bits.
|
|---|
| 353 | */
|
|---|
| 354 | public int getLc() {
|
|---|
| 355 | return lc;
|
|---|
| 356 | }
|
|---|
| 357 |
|
|---|
| 358 | /**
|
|---|
| 359 | * Gets the number of literal position bits.
|
|---|
| 360 | */
|
|---|
| 361 | public int getLp() {
|
|---|
| 362 | return lp;
|
|---|
| 363 | }
|
|---|
| 364 |
|
|---|
| 365 | /**
|
|---|
| 366 | * Sets the number of position bits.
|
|---|
| 367 | * <p>
|
|---|
| 368 | * This affects what kind of alignment in the uncompressed data is
|
|---|
| 369 | * assumed in general. The default (2) means four-byte alignment
|
|---|
| 370 | * (2^<code>pb</code> = 2^2 = 4), which is often a good choice when
|
|---|
| 371 | * there's no better guess.
|
|---|
| 372 | * <p>
|
|---|
| 373 | * When the alignment is known, setting the number of position bits
|
|---|
| 374 | * accordingly may reduce the file size a little. For example with text
|
|---|
| 375 | * files having one-byte alignment (US-ASCII, ISO-8859-*, UTF-8), using
|
|---|
| 376 | * <code>setPb(0)</code> can improve compression slightly. For UTF-16
|
|---|
| 377 | * text, <code>setPb(1)</code> is a good choice. If the alignment is
|
|---|
| 378 | * an odd number like 3 bytes, <code>setPb(0)</code> might be the best
|
|---|
| 379 | * choice.
|
|---|
| 380 | * <p>
|
|---|
| 381 | * Even though the assumed alignment can be adjusted with
|
|---|
| 382 | * <code>setPb</code> and <code>setLp</code>, LZMA2 still slightly favors
|
|---|
| 383 | * 16-byte alignment. It might be worth taking into account when designing
|
|---|
| 384 | * file formats that are likely to be often compressed with LZMA2.
|
|---|
| 385 | *
|
|---|
| 386 | * @throws UnsupportedOptionsException
|
|---|
| 387 | * <code>pb</code> is invalid
|
|---|
| 388 | */
|
|---|
| 389 | public void setPb(int pb) throws UnsupportedOptionsException {
|
|---|
| 390 | if (pb < 0 || pb > PB_MAX)
|
|---|
| 391 | throw new UnsupportedOptionsException(
|
|---|
| 392 | "pb must not exceed " + PB_MAX + ": " + pb);
|
|---|
| 393 |
|
|---|
| 394 | this.pb = pb;
|
|---|
| 395 | }
|
|---|
| 396 |
|
|---|
| 397 | /**
|
|---|
| 398 | * Gets the number of position bits.
|
|---|
| 399 | */
|
|---|
| 400 | public int getPb() {
|
|---|
| 401 | return pb;
|
|---|
| 402 | }
|
|---|
| 403 |
|
|---|
| 404 | /**
|
|---|
| 405 | * Sets the compression mode.
|
|---|
| 406 | * <p>
|
|---|
| 407 | * This specifies the method to analyze the data produced by
|
|---|
| 408 | * a match finder. The default is <code>MODE_FAST</code> for presets
|
|---|
| 409 | * 0-3 and <code>MODE_NORMAL</code> for presets 4-9.
|
|---|
| 410 | * <p>
|
|---|
| 411 | * Usually <code>MODE_FAST</code> is used with Hash Chain match finders
|
|---|
| 412 | * and <code>MODE_NORMAL</code> with Binary Tree match finders. This is
|
|---|
| 413 | * also what the presets do.
|
|---|
| 414 | * <p>
|
|---|
| 415 | * The special mode <code>MODE_UNCOMPRESSED</code> doesn't try to
|
|---|
| 416 | * compress the data at all (and doesn't use a match finder) and will
|
|---|
| 417 | * simply wrap it in uncompressed LZMA2 chunks.
|
|---|
| 418 | *
|
|---|
| 419 | * @throws UnsupportedOptionsException
|
|---|
| 420 | * <code>mode</code> is not supported
|
|---|
| 421 | */
|
|---|
| 422 | public void setMode(int mode) throws UnsupportedOptionsException {
|
|---|
| 423 | if (mode < MODE_UNCOMPRESSED || mode > MODE_NORMAL)
|
|---|
| 424 | throw new UnsupportedOptionsException(
|
|---|
| 425 | "Unsupported compression mode: " + mode);
|
|---|
| 426 |
|
|---|
| 427 | this.mode = mode;
|
|---|
| 428 | }
|
|---|
| 429 |
|
|---|
| 430 | /**
|
|---|
| 431 | * Gets the compression mode.
|
|---|
| 432 | */
|
|---|
| 433 | public int getMode() {
|
|---|
| 434 | return mode;
|
|---|
| 435 | }
|
|---|
| 436 |
|
|---|
| 437 | /**
|
|---|
| 438 | * Sets the nice length of matches.
|
|---|
| 439 | * Once a match of at least <code>niceLen</code> bytes is found,
|
|---|
| 440 | * the algorithm stops looking for better matches. Higher values tend
|
|---|
| 441 | * to give better compression at the expense of speed. The default
|
|---|
| 442 | * depends on the preset.
|
|---|
| 443 | *
|
|---|
| 444 | * @throws UnsupportedOptionsException
|
|---|
| 445 | * <code>niceLen</code> is invalid
|
|---|
| 446 | */
|
|---|
| 447 | public void setNiceLen(int niceLen) throws UnsupportedOptionsException {
|
|---|
| 448 | if (niceLen < NICE_LEN_MIN)
|
|---|
| 449 | throw new UnsupportedOptionsException(
|
|---|
| 450 | "Minimum nice length of matches is "
|
|---|
| 451 | + NICE_LEN_MIN + " bytes: " + niceLen);
|
|---|
| 452 |
|
|---|
| 453 | if (niceLen > NICE_LEN_MAX)
|
|---|
| 454 | throw new UnsupportedOptionsException(
|
|---|
| 455 | "Maximum nice length of matches is " + NICE_LEN_MAX
|
|---|
| 456 | + ": " + niceLen);
|
|---|
| 457 |
|
|---|
| 458 | this.niceLen = niceLen;
|
|---|
| 459 | }
|
|---|
| 460 |
|
|---|
| 461 | /**
|
|---|
| 462 | * Gets the nice length of matches.
|
|---|
| 463 | */
|
|---|
| 464 | public int getNiceLen() {
|
|---|
| 465 | return niceLen;
|
|---|
| 466 | }
|
|---|
| 467 |
|
|---|
| 468 | /**
|
|---|
| 469 | * Sets the match finder type.
|
|---|
| 470 | * <p>
|
|---|
| 471 | * Match finder has a major effect on compression speed, memory usage,
|
|---|
| 472 | * and compression ratio. Usually Hash Chain match finders are faster
|
|---|
| 473 | * than Binary Tree match finders. The default depends on the preset:
|
|---|
| 474 | * 0-3 use <code>MF_HC4</code> and 4-9 use <code>MF_BT4</code>.
|
|---|
| 475 | *
|
|---|
| 476 | * @throws UnsupportedOptionsException
|
|---|
| 477 | * <code>mf</code> is not supported
|
|---|
| 478 | */
|
|---|
| 479 | public void setMatchFinder(int mf) throws UnsupportedOptionsException {
|
|---|
| 480 | if (mf != MF_HC4 && mf != MF_BT4)
|
|---|
| 481 | throw new UnsupportedOptionsException(
|
|---|
| 482 | "Unsupported match finder: " + mf);
|
|---|
| 483 |
|
|---|
| 484 | this.mf = mf;
|
|---|
| 485 | }
|
|---|
| 486 |
|
|---|
| 487 | /**
|
|---|
| 488 | * Gets the match finder type.
|
|---|
| 489 | */
|
|---|
| 490 | public int getMatchFinder() {
|
|---|
| 491 | return mf;
|
|---|
| 492 | }
|
|---|
| 493 |
|
|---|
| 494 | /**
|
|---|
| 495 | * Sets the match finder search depth limit.
|
|---|
| 496 | * <p>
|
|---|
| 497 | * The default is a special value of <code>0</code> which indicates that
|
|---|
| 498 | * the depth limit should be automatically calculated by the selected
|
|---|
| 499 | * match finder from the nice length of matches.
|
|---|
| 500 | * <p>
|
|---|
| 501 | * Reasonable depth limit for Hash Chain match finders is 4-100 and
|
|---|
| 502 | * 16-1000 for Binary Tree match finders. Using very high values can
|
|---|
| 503 | * make the compressor extremely slow with some files. Avoid settings
|
|---|
| 504 | * higher than 1000 unless you are prepared to interrupt the compression
|
|---|
| 505 | * in case it is taking far too long.
|
|---|
| 506 | *
|
|---|
| 507 | * @throws UnsupportedOptionsException
|
|---|
| 508 | * <code>depthLimit</code> is invalid
|
|---|
| 509 | */
|
|---|
| 510 | public void setDepthLimit(int depthLimit)
|
|---|
| 511 | throws UnsupportedOptionsException {
|
|---|
| 512 | if (depthLimit < 0)
|
|---|
| 513 | throw new UnsupportedOptionsException(
|
|---|
| 514 | "Depth limit cannot be negative: " + depthLimit);
|
|---|
| 515 |
|
|---|
| 516 | this.depthLimit = depthLimit;
|
|---|
| 517 | }
|
|---|
| 518 |
|
|---|
| 519 | /**
|
|---|
| 520 | * Gets the match finder search depth limit.
|
|---|
| 521 | */
|
|---|
| 522 | public int getDepthLimit() {
|
|---|
| 523 | return depthLimit;
|
|---|
| 524 | }
|
|---|
| 525 |
|
|---|
| 526 | public int getEncoderMemoryUsage() {
|
|---|
| 527 | return (mode == MODE_UNCOMPRESSED)
|
|---|
| 528 | ? UncompressedLZMA2OutputStream.getMemoryUsage()
|
|---|
| 529 | : LZMA2OutputStream.getMemoryUsage(this);
|
|---|
| 530 | }
|
|---|
| 531 |
|
|---|
| 532 | public FinishableOutputStream getOutputStream(FinishableOutputStream out,
|
|---|
| 533 | ArrayCache arrayCache) {
|
|---|
| 534 | if (mode == MODE_UNCOMPRESSED)
|
|---|
| 535 | return new UncompressedLZMA2OutputStream(out, arrayCache);
|
|---|
| 536 |
|
|---|
| 537 | return new LZMA2OutputStream(out, this, arrayCache);
|
|---|
| 538 | }
|
|---|
| 539 |
|
|---|
| 540 | /**
|
|---|
| 541 | * Gets how much memory the LZMA2 decoder will need to decompress the data
|
|---|
| 542 | * that was encoded with these options and stored in a .xz file.
|
|---|
| 543 | * <p>
|
|---|
| 544 | * The returned value may bigger than the value returned by a direct call
|
|---|
| 545 | * to {@link LZMA2InputStream#getMemoryUsage(int)} if the dictionary size
|
|---|
| 546 | * is not 2^n or 2^n + 2^(n-1) bytes. This is because the .xz
|
|---|
| 547 | * headers store the dictionary size in such a format and other values
|
|---|
| 548 | * are rounded up to the next such value. Such rounding is harmess except
|
|---|
| 549 | * it might waste some memory if an unsual dictionary size is used.
|
|---|
| 550 | * <p>
|
|---|
| 551 | * If you use raw LZMA2 streams and unusual dictioanary size, call
|
|---|
| 552 | * {@link LZMA2InputStream#getMemoryUsage} directly to get raw decoder
|
|---|
| 553 | * memory requirements.
|
|---|
| 554 | */
|
|---|
| 555 | public int getDecoderMemoryUsage() {
|
|---|
| 556 | // Round the dictionary size up to the next 2^n or 2^n + 2^(n-1).
|
|---|
| 557 | int d = dictSize - 1;
|
|---|
| 558 | d |= d >>> 2;
|
|---|
| 559 | d |= d >>> 3;
|
|---|
| 560 | d |= d >>> 4;
|
|---|
| 561 | d |= d >>> 8;
|
|---|
| 562 | d |= d >>> 16;
|
|---|
| 563 | return LZMA2InputStream.getMemoryUsage(d + 1);
|
|---|
| 564 | }
|
|---|
| 565 |
|
|---|
| 566 | public InputStream getInputStream(InputStream in, ArrayCache arrayCache)
|
|---|
| 567 | throws IOException {
|
|---|
| 568 | return new LZMA2InputStream(in, dictSize, presetDict, arrayCache);
|
|---|
| 569 | }
|
|---|
| 570 |
|
|---|
| 571 | FilterEncoder getFilterEncoder() {
|
|---|
| 572 | return new LZMA2Encoder(this);
|
|---|
| 573 | }
|
|---|
| 574 |
|
|---|
| 575 | public Object clone() {
|
|---|
| 576 | try {
|
|---|
| 577 | return super.clone();
|
|---|
| 578 | } catch (CloneNotSupportedException e) {
|
|---|
| 579 | assert false;
|
|---|
| 580 | throw new RuntimeException();
|
|---|
| 581 | }
|
|---|
| 582 | }
|
|---|
| 583 | }
|
|---|