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 */ LZMA2Options()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 */ LZMA2Options(int preset)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 */ LZMA2Options(int dictSize, int lc, int lp, int pb, int mode, int niceLen, int mf, int depthLimit)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 */ setPreset(int preset)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 */ setDictSize(int dictSize)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 */ getDictSize()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 */ setPresetDict(byte[] presetDict)272 public void setPresetDict(byte[] presetDict) { 273 this.presetDict = presetDict; 274 } 275 276 /** 277 * Gets the preset dictionary. 278 */ getPresetDict()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 */ setLcLp(int lc, int lp)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 */ setLc(int lc)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 */ setLp(int lp)347 public void setLp(int lp) throws UnsupportedOptionsException { 348 setLcLp(lc, lp); 349 } 350 351 /** 352 * Gets the number of literal context bits. 353 */ getLc()354 public int getLc() { 355 return lc; 356 } 357 358 /** 359 * Gets the number of literal position bits. 360 */ getLp()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 */ setPb(int pb)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 */ getPb()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 */ setMode(int mode)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 */ getMode()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 */ setNiceLen(int niceLen)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 */ getNiceLen()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 */ setMatchFinder(int mf)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 */ getMatchFinder()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 */ setDepthLimit(int depthLimit)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 */ getDepthLimit()522 public int getDepthLimit() { 523 return depthLimit; 524 } 525 getEncoderMemoryUsage()526 public int getEncoderMemoryUsage() { 527 return (mode == MODE_UNCOMPRESSED) 528 ? UncompressedLZMA2OutputStream.getMemoryUsage() 529 : LZMA2OutputStream.getMemoryUsage(this); 530 } 531 getOutputStream(FinishableOutputStream out, ArrayCache arrayCache)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 */ getDecoderMemoryUsage()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 getInputStream(InputStream in, ArrayCache arrayCache)566 public InputStream getInputStream(InputStream in, ArrayCache arrayCache) 567 throws IOException { 568 return new LZMA2InputStream(in, dictSize, presetDict, arrayCache); 569 } 570 getFilterEncoder()571 FilterEncoder getFilterEncoder() { 572 return new LZMA2Encoder(this); 573 } 574 clone()575 public Object clone() { 576 try { 577 return super.clone(); 578 } catch (CloneNotSupportedException e) { 579 assert false; 580 throw new RuntimeException(); 581 } 582 } 583 } 584