• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * LZMAEncoder
3  *
4  * Authors: Lasse Collin <lasse.collin@tukaani.org>
5  *          Igor Pavlov <http://7-zip.org/>
6  *
7  * This file has been put into the public domain.
8  * You can do whatever you want with this file.
9  */
10 
11 package org.tukaani.xz.lzma;
12 
13 import org.tukaani.xz.lz.LZEncoder;
14 import org.tukaani.xz.lz.Matches;
15 import org.tukaani.xz.rangecoder.RangeEncoder;
16 
17 public abstract class LZMAEncoder extends LZMACoder {
18     public static final int MODE_FAST = 1;
19     public static final int MODE_NORMAL = 2;
20 
21     /**
22      * LZMA2 chunk is considered full when its uncompressed size exceeds
23      * <code>LZMA2_UNCOMPRESSED_LIMIT</code>.
24      * <p>
25      * A compressed LZMA2 chunk can hold 2 MiB of uncompressed data.
26      * A single LZMA symbol may indicate up to MATCH_LEN_MAX bytes
27      * of data, so the LZMA2 chunk is considered full when there is
28      * less space than MATCH_LEN_MAX bytes.
29      */
30     private static final int LZMA2_UNCOMPRESSED_LIMIT
31             = (2 << 20) - MATCH_LEN_MAX;
32 
33     /**
34      * LZMA2 chunk is considered full when its compressed size exceeds
35      * <code>LZMA2_COMPRESSED_LIMIT</code>.
36      * <p>
37      * The maximum compressed size of a LZMA2 chunk is 64 KiB.
38      * A single LZMA symbol might use 20 bytes of space even though
39      * it usually takes just one byte or so. Two more bytes are needed
40      * for LZMA2 uncompressed chunks (see LZMA2OutputStream.writeChunk).
41      * Leave a little safety margin and use 26 bytes.
42      */
43     private static final int LZMA2_COMPRESSED_LIMIT = (64 << 10) - 26;
44 
45     private static final int DIST_PRICE_UPDATE_INTERVAL = FULL_DISTANCES;
46     private static final int ALIGN_PRICE_UPDATE_INTERVAL = ALIGN_SIZE;
47 
48     private final RangeEncoder rc;
49     final LZEncoder lz;
50     final LiteralEncoder literalEncoder;
51     final LengthEncoder matchLenEncoder;
52     final LengthEncoder repLenEncoder;
53     final int niceLen;
54 
55     private int distPriceCount = 0;
56     private int alignPriceCount = 0;
57 
58     private final int distSlotPricesSize;
59     private final int[][] distSlotPrices;
60     private final int[][] fullDistPrices
61             = new int[DIST_STATES][FULL_DISTANCES];
62     private final int[] alignPrices = new int[ALIGN_SIZE];
63 
64     int back = 0;
65     int readAhead = -1;
66     private int uncompressedSize = 0;
67 
getMemoryUsage(int mode, int dictSize, int extraSizeBefore, int mf)68     public static int getMemoryUsage(int mode, int dictSize,
69                                      int extraSizeBefore, int mf) {
70         int m = 80;
71 
72         switch (mode) {
73             case MODE_FAST:
74                 m += LZMAEncoderFast.getMemoryUsage(
75                         dictSize, extraSizeBefore, mf);
76                 break;
77 
78             case MODE_NORMAL:
79                 m += LZMAEncoderNormal.getMemoryUsage(
80                         dictSize, extraSizeBefore, mf);
81                 break;
82 
83             default:
84                 throw new IllegalArgumentException();
85         }
86 
87         return m;
88     }
89 
getInstance( RangeEncoder rc, int lc, int lp, int pb, int mode, int dictSize, int extraSizeBefore, int niceLen, int mf, int depthLimit)90     public static LZMAEncoder getInstance(
91                 RangeEncoder rc, int lc, int lp, int pb, int mode,
92                 int dictSize, int extraSizeBefore,
93                 int niceLen, int mf, int depthLimit) {
94         switch (mode) {
95             case MODE_FAST:
96                 return new LZMAEncoderFast(rc, lc, lp, pb,
97                                            dictSize, extraSizeBefore,
98                                            niceLen, mf, depthLimit);
99 
100             case MODE_NORMAL:
101                 return new LZMAEncoderNormal(rc, lc, lp, pb,
102                                              dictSize, extraSizeBefore,
103                                              niceLen, mf, depthLimit);
104         }
105 
106         throw new IllegalArgumentException();
107     }
108 
109     /**
110      * Gets an integer [0, 63] matching the highest two bits of an integer.
111      * This is like bit scan reverse (BSR) on x86 except that this also
112      * cares about the second highest bit.
113      */
getDistSlot(int dist)114     public static int getDistSlot(int dist) {
115         if (dist <= DIST_MODEL_START)
116             return dist;
117 
118         int n = dist;
119         int i = 31;
120 
121         if ((n & 0xFFFF0000) == 0) {
122             n <<= 16;
123             i = 15;
124         }
125 
126         if ((n & 0xFF000000) == 0) {
127             n <<= 8;
128             i -= 8;
129         }
130 
131         if ((n & 0xF0000000) == 0) {
132             n <<= 4;
133             i -= 4;
134         }
135 
136         if ((n & 0xC0000000) == 0) {
137             n <<= 2;
138             i -= 2;
139         }
140 
141         if ((n & 0x80000000) == 0)
142             --i;
143 
144         return (i << 1) + ((dist >>> (i - 1)) & 1);
145     }
146 
147     /**
148      * Gets the next LZMA symbol.
149      * <p>
150      * There are three types of symbols: literal (a single byte),
151      * repeated match, and normal match. The symbol is indicated
152      * by the return value and by the variable <code>back</code>.
153      * <p>
154      * Literal: <code>back == -1</code> and return value is <code>1</code>.
155      * The literal itself needs to be read from <code>lz</code> separately.
156      * <p>
157      * Repeated match: <code>back</code> is in the range [0, 3] and
158      * the return value is the length of the repeated match.
159      * <p>
160      * Normal match: <code>back - REPS<code> (<code>back - 4</code>)
161      * is the distance of the match and the return value is the length
162      * of the match.
163      */
getNextSymbol()164     abstract int getNextSymbol();
165 
LZMAEncoder(RangeEncoder rc, LZEncoder lz, int lc, int lp, int pb, int dictSize, int niceLen)166     LZMAEncoder(RangeEncoder rc, LZEncoder lz,
167                 int lc, int lp, int pb, int dictSize, int niceLen) {
168         super(pb);
169         this.rc = rc;
170         this.lz = lz;
171         this.niceLen = niceLen;
172 
173         literalEncoder = new LiteralEncoder(lc, lp);
174         matchLenEncoder = new LengthEncoder(pb, niceLen);
175         repLenEncoder = new LengthEncoder(pb, niceLen);
176 
177         distSlotPricesSize = getDistSlot(dictSize - 1) + 1;
178         distSlotPrices = new int[DIST_STATES][distSlotPricesSize];
179 
180         reset();
181     }
182 
getLZEncoder()183     public LZEncoder getLZEncoder() {
184         return lz;
185     }
186 
reset()187     public void reset() {
188         super.reset();
189         literalEncoder.reset();
190         matchLenEncoder.reset();
191         repLenEncoder.reset();
192         distPriceCount = 0;
193         alignPriceCount = 0;
194 
195         uncompressedSize += readAhead + 1;
196         readAhead = -1;
197     }
198 
getUncompressedSize()199     public int getUncompressedSize() {
200         return uncompressedSize;
201     }
202 
resetUncompressedSize()203     public void resetUncompressedSize() {
204         uncompressedSize = 0;
205     }
206 
207     /**
208      * Compresses for LZMA2.
209      *
210      * @return      true if the LZMA2 chunk became full, false otherwise
211      */
encodeForLZMA2()212     public boolean encodeForLZMA2() {
213         if (!lz.isStarted() && !encodeInit())
214             return false;
215 
216         while (uncompressedSize <= LZMA2_UNCOMPRESSED_LIMIT
217                 && rc.getPendingSize() <= LZMA2_COMPRESSED_LIMIT)
218             if (!encodeSymbol())
219                 return false;
220 
221         return true;
222     }
223 
encodeInit()224     private boolean encodeInit() {
225         assert readAhead == -1;
226         if (!lz.hasEnoughData(0))
227             return false;
228 
229         // The first symbol must be a literal unless using
230         // a preset dictionary. This code isn't run if using
231         // a preset dictionary.
232         skip(1);
233         rc.encodeBit(isMatch[state.get()], 0, 0);
234         literalEncoder.encodeInit();
235 
236         --readAhead;
237         assert readAhead == -1;
238 
239         ++uncompressedSize;
240         assert uncompressedSize == 1;
241 
242         return true;
243     }
244 
encodeSymbol()245     private boolean encodeSymbol() {
246         if (!lz.hasEnoughData(readAhead + 1))
247             return false;
248 
249         int len = getNextSymbol();
250 
251         assert readAhead >= 0;
252         int posState = (lz.getPos() - readAhead) & posMask;
253 
254         if (back == -1) {
255             // Literal i.e. eight-bit byte
256             assert len == 1;
257             rc.encodeBit(isMatch[state.get()], posState, 0);
258             literalEncoder.encode();
259         } else {
260             // Some type of match
261             rc.encodeBit(isMatch[state.get()], posState, 1);
262             if (back < REPS) {
263                 // Repeated match i.e. the same distance
264                 // has been used earlier.
265                 assert lz.getMatchLen(-readAhead, reps[back], len) == len;
266                 rc.encodeBit(isRep, state.get(), 1);
267                 encodeRepMatch(back, len, posState);
268             } else {
269                 // Normal match
270                 assert lz.getMatchLen(-readAhead, back - REPS, len) == len;
271                 rc.encodeBit(isRep, state.get(), 0);
272                 encodeMatch(back - REPS, len, posState);
273             }
274         }
275 
276         readAhead -= len;
277         uncompressedSize += len;
278 
279         return true;
280     }
281 
encodeMatch(int dist, int len, int posState)282     private void encodeMatch(int dist, int len, int posState) {
283         state.updateMatch();
284         matchLenEncoder.encode(len, posState);
285 
286         int distSlot = getDistSlot(dist);
287         rc.encodeBitTree(distSlots[getDistState(len)], distSlot);
288 
289         if (distSlot >= DIST_MODEL_START) {
290             int footerBits = (distSlot >>> 1) - 1;
291             int base = (2 | (distSlot & 1)) << footerBits;
292             int distReduced = dist - base;
293 
294             if (distSlot < DIST_MODEL_END) {
295                 rc.encodeReverseBitTree(
296                         distSpecial[distSlot - DIST_MODEL_START],
297                         distReduced);
298             } else {
299                 rc.encodeDirectBits(distReduced >>> ALIGN_BITS,
300                                     footerBits - ALIGN_BITS);
301                 rc.encodeReverseBitTree(distAlign, distReduced & ALIGN_MASK);
302                 --alignPriceCount;
303             }
304         }
305 
306         reps[3] = reps[2];
307         reps[2] = reps[1];
308         reps[1] = reps[0];
309         reps[0] = dist;
310 
311         --distPriceCount;
312     }
313 
encodeRepMatch(int rep, int len, int posState)314     private void encodeRepMatch(int rep, int len, int posState) {
315         if (rep == 0) {
316             rc.encodeBit(isRep0, state.get(), 0);
317             rc.encodeBit(isRep0Long[state.get()], posState, len == 1 ? 0 : 1);
318         } else {
319             int dist = reps[rep];
320             rc.encodeBit(isRep0, state.get(), 1);
321 
322             if (rep == 1) {
323                 rc.encodeBit(isRep1, state.get(), 0);
324             } else {
325                 rc.encodeBit(isRep1, state.get(), 1);
326                 rc.encodeBit(isRep2, state.get(), rep - 2);
327 
328                 if (rep == 3)
329                     reps[3] = reps[2];
330 
331                 reps[2] = reps[1];
332             }
333 
334             reps[1] = reps[0];
335             reps[0] = dist;
336         }
337 
338         if (len == 1) {
339             state.updateShortRep();
340         } else {
341             repLenEncoder.encode(len, posState);
342             state.updateLongRep();
343         }
344     }
345 
getMatches()346     Matches getMatches() {
347         ++readAhead;
348         Matches matches = lz.getMatches();
349         assert lz.verifyMatches(matches);
350         return matches;
351     }
352 
skip(int len)353     void skip(int len) {
354         readAhead += len;
355         lz.skip(len);
356     }
357 
getAnyMatchPrice(State state, int posState)358     int getAnyMatchPrice(State state, int posState) {
359         return RangeEncoder.getBitPrice(isMatch[state.get()][posState], 1);
360     }
361 
getNormalMatchPrice(int anyMatchPrice, State state)362     int getNormalMatchPrice(int anyMatchPrice, State state) {
363         return anyMatchPrice
364                + RangeEncoder.getBitPrice(isRep[state.get()], 0);
365     }
366 
getAnyRepPrice(int anyMatchPrice, State state)367     int getAnyRepPrice(int anyMatchPrice, State state) {
368         return anyMatchPrice
369                + RangeEncoder.getBitPrice(isRep[state.get()], 1);
370     }
371 
getShortRepPrice(int anyRepPrice, State state, int posState)372     int getShortRepPrice(int anyRepPrice, State state, int posState) {
373         return anyRepPrice
374                + RangeEncoder.getBitPrice(isRep0[state.get()], 0)
375                + RangeEncoder.getBitPrice(isRep0Long[state.get()][posState],
376                                           0);
377     }
378 
getLongRepPrice(int anyRepPrice, int rep, State state, int posState)379     int getLongRepPrice(int anyRepPrice, int rep, State state, int posState) {
380         int price = anyRepPrice;
381 
382         if (rep == 0) {
383             price += RangeEncoder.getBitPrice(isRep0[state.get()], 0)
384                      + RangeEncoder.getBitPrice(
385                        isRep0Long[state.get()][posState], 1);
386         } else {
387             price += RangeEncoder.getBitPrice(isRep0[state.get()], 1);
388 
389             if (rep == 1)
390                 price += RangeEncoder.getBitPrice(isRep1[state.get()], 0);
391             else
392                 price += RangeEncoder.getBitPrice(isRep1[state.get()], 1)
393                          + RangeEncoder.getBitPrice(isRep2[state.get()],
394                                                     rep - 2);
395         }
396 
397         return price;
398     }
399 
getLongRepAndLenPrice(int rep, int len, State state, int posState)400     int getLongRepAndLenPrice(int rep, int len, State state, int posState) {
401         int anyMatchPrice = getAnyMatchPrice(state, posState);
402         int anyRepPrice = getAnyRepPrice(anyMatchPrice, state);
403         int longRepPrice = getLongRepPrice(anyRepPrice, rep, state, posState);
404         return longRepPrice + repLenEncoder.getPrice(len, posState);
405     }
406 
getMatchAndLenPrice(int normalMatchPrice, int dist, int len, int posState)407     int getMatchAndLenPrice(int normalMatchPrice,
408                             int dist, int len, int posState) {
409         int price = normalMatchPrice
410                     + matchLenEncoder.getPrice(len, posState);
411         int distState = getDistState(len);
412 
413         if (dist < FULL_DISTANCES) {
414             price += fullDistPrices[distState][dist];
415         } else {
416             // Note that distSlotPrices includes also
417             // the price of direct bits.
418             int distSlot = getDistSlot(dist);
419             price += distSlotPrices[distState][distSlot]
420                      + alignPrices[dist & ALIGN_MASK];
421         }
422 
423         return price;
424     }
425 
updateDistPrices()426     private void updateDistPrices() {
427         distPriceCount = DIST_PRICE_UPDATE_INTERVAL;
428 
429         for (int distState = 0; distState < DIST_STATES; ++distState) {
430             for (int distSlot = 0; distSlot < distSlotPricesSize; ++distSlot)
431                 distSlotPrices[distState][distSlot]
432                         = RangeEncoder.getBitTreePrice(
433                           distSlots[distState], distSlot);
434 
435             for (int distSlot = DIST_MODEL_END; distSlot < distSlotPricesSize;
436                     ++distSlot) {
437                 int count = (distSlot >>> 1) - 1 - ALIGN_BITS;
438                 distSlotPrices[distState][distSlot]
439                         += RangeEncoder.getDirectBitsPrice(count);
440             }
441 
442             for (int dist = 0; dist < DIST_MODEL_START; ++dist)
443                 fullDistPrices[distState][dist]
444                         = distSlotPrices[distState][dist];
445         }
446 
447         int dist = DIST_MODEL_START;
448         for (int distSlot = DIST_MODEL_START; distSlot < DIST_MODEL_END;
449                 ++distSlot) {
450             int footerBits = (distSlot >>> 1) - 1;
451             int base = (2 | (distSlot & 1)) << footerBits;
452 
453             int limit = distSpecial[distSlot - DIST_MODEL_START].length;
454             for (int i = 0; i < limit; ++i) {
455                 int distReduced = dist - base;
456                 int price = RangeEncoder.getReverseBitTreePrice(
457                         distSpecial[distSlot - DIST_MODEL_START],
458                         distReduced);
459 
460                 for (int distState = 0; distState < DIST_STATES; ++distState)
461                     fullDistPrices[distState][dist]
462                             = distSlotPrices[distState][distSlot] + price;
463 
464                 ++dist;
465             }
466         }
467 
468         assert dist == FULL_DISTANCES;
469     }
470 
updateAlignPrices()471     private void updateAlignPrices() {
472         alignPriceCount = ALIGN_PRICE_UPDATE_INTERVAL;
473 
474         for (int i = 0; i < ALIGN_SIZE; ++i)
475             alignPrices[i] = RangeEncoder.getReverseBitTreePrice(distAlign,
476                                                                  i);
477     }
478 
479     /**
480      * Updates the lookup tables used for calculating match distance
481      * and length prices. The updating is skipped for performance reasons
482      * if the tables haven't changed much since the previous update.
483      */
updatePrices()484     void updatePrices() {
485         if (distPriceCount <= 0)
486             updateDistPrices();
487 
488         if (alignPriceCount <= 0)
489             updateAlignPrices();
490 
491         matchLenEncoder.updatePrices();
492         repLenEncoder.updatePrices();
493     }
494 
495 
496     class LiteralEncoder extends LiteralCoder {
497         private final LiteralSubencoder[] subencoders;
498 
LiteralEncoder(int lc, int lp)499         LiteralEncoder(int lc, int lp) {
500             super(lc, lp);
501 
502             subencoders = new LiteralSubencoder[1 << (lc + lp)];
503             for (int i = 0; i < subencoders.length; ++i)
504                 subencoders[i] = new LiteralSubencoder();
505         }
506 
reset()507         void reset() {
508             for (int i = 0; i < subencoders.length; ++i)
509                 subencoders[i].reset();
510         }
511 
encodeInit()512         void encodeInit() {
513             // When encoding the first byte of the stream, there is
514             // no previous byte in the dictionary so the encode function
515             // wouldn't work.
516             assert readAhead >= 0;
517             subencoders[0].encode();
518         }
519 
encode()520         void encode() {
521             assert readAhead >= 0;
522             int i = getSubcoderIndex(lz.getByte(1 + readAhead),
523                                      lz.getPos() - readAhead);
524             subencoders[i].encode();
525         }
526 
getPrice(int curByte, int matchByte, int prevByte, int pos, State state)527         int getPrice(int curByte, int matchByte,
528                      int prevByte, int pos, State state) {
529             int price = RangeEncoder.getBitPrice(
530                     isMatch[state.get()][pos & posMask], 0);
531 
532             int i = getSubcoderIndex(prevByte, pos);
533             price += state.isLiteral()
534                    ? subencoders[i].getNormalPrice(curByte)
535                    : subencoders[i].getMatchedPrice(curByte, matchByte);
536 
537             return price;
538         }
539 
540         private class LiteralSubencoder extends LiteralSubcoder {
encode()541             void encode() {
542                 int symbol = lz.getByte(readAhead) | 0x100;
543 
544                 if (state.isLiteral()) {
545                     int subencoderIndex;
546                     int bit;
547 
548                     do {
549                         subencoderIndex = symbol >>> 8;
550                         bit = (symbol >>> 7) & 1;
551                         rc.encodeBit(probs, subencoderIndex, bit);
552                         symbol <<= 1;
553                     } while (symbol < 0x10000);
554 
555                 } else {
556                     int matchByte = lz.getByte(reps[0] + 1 + readAhead);
557                     int offset = 0x100;
558                     int subencoderIndex;
559                     int matchBit;
560                     int bit;
561 
562                     do {
563                         matchByte <<= 1;
564                         matchBit = matchByte & offset;
565                         subencoderIndex = offset + matchBit + (symbol >>> 8);
566                         bit = (symbol >>> 7) & 1;
567                         rc.encodeBit(probs, subencoderIndex, bit);
568                         symbol <<= 1;
569                         offset &= ~(matchByte ^ symbol);
570                     } while (symbol < 0x10000);
571                 }
572 
573                 state.updateLiteral();
574             }
575 
getNormalPrice(int symbol)576             int getNormalPrice(int symbol) {
577                 int price = 0;
578                 int subencoderIndex;
579                 int bit;
580 
581                 symbol |= 0x100;
582 
583                 do {
584                     subencoderIndex = symbol >>> 8;
585                     bit = (symbol >>> 7) & 1;
586                     price += RangeEncoder.getBitPrice(probs[subencoderIndex],
587                                                       bit);
588                     symbol <<= 1;
589                 } while (symbol < (0x100 << 8));
590 
591                 return price;
592             }
593 
getMatchedPrice(int symbol, int matchByte)594             int getMatchedPrice(int symbol, int matchByte) {
595                 int price = 0;
596                 int offset = 0x100;
597                 int subencoderIndex;
598                 int matchBit;
599                 int bit;
600 
601                 symbol |= 0x100;
602 
603                 do {
604                     matchByte <<= 1;
605                     matchBit = matchByte & offset;
606                     subencoderIndex = offset + matchBit + (symbol >>> 8);
607                     bit = (symbol >>> 7) & 1;
608                     price += RangeEncoder.getBitPrice(probs[subencoderIndex],
609                                                       bit);
610                     symbol <<= 1;
611                     offset &= ~(matchByte ^ symbol);
612                 } while (symbol < (0x100 << 8));
613 
614                 return price;
615             }
616         }
617     }
618 
619 
620     class LengthEncoder extends LengthCoder {
621         /**
622          * The prices are updated after at least
623          * <code>PRICE_UPDATE_INTERVAL</code> many lengths
624          * have been encoded with the same posState.
625          */
626         private static final int PRICE_UPDATE_INTERVAL = 32; // FIXME?
627 
628         private final int[] counters;
629         private final int[][] prices;
630 
LengthEncoder(int pb, int niceLen)631         LengthEncoder(int pb, int niceLen) {
632             int posStates = 1 << pb;
633             counters = new int[posStates];
634 
635             // Always allocate at least LOW_SYMBOLS + MID_SYMBOLS because
636             // it makes updatePrices slightly simpler. The prices aren't
637             // usually needed anyway if niceLen < 18.
638             int lenSymbols = Math.max(niceLen - MATCH_LEN_MIN + 1,
639                                       LOW_SYMBOLS + MID_SYMBOLS);
640             prices = new int[posStates][lenSymbols];
641         }
642 
reset()643         void reset() {
644             super.reset();
645 
646             // Reset counters to zero to force price update before
647             // the prices are needed.
648             for (int i = 0; i < counters.length; ++i)
649                 counters[i] = 0;
650         }
651 
encode(int len, int posState)652         void encode(int len, int posState) {
653             len -= MATCH_LEN_MIN;
654 
655             if (len < LOW_SYMBOLS) {
656                 rc.encodeBit(choice, 0, 0);
657                 rc.encodeBitTree(low[posState], len);
658             } else {
659                 rc.encodeBit(choice, 0, 1);
660                 len -= LOW_SYMBOLS;
661 
662                 if (len < MID_SYMBOLS) {
663                     rc.encodeBit(choice, 1, 0);
664                     rc.encodeBitTree(mid[posState], len);
665                 } else {
666                     rc.encodeBit(choice, 1, 1);
667                     rc.encodeBitTree(high, len - MID_SYMBOLS);
668                 }
669             }
670 
671             --counters[posState];
672         }
673 
getPrice(int len, int posState)674         int getPrice(int len, int posState) {
675             return prices[posState][len - MATCH_LEN_MIN];
676         }
677 
updatePrices()678         void updatePrices() {
679             for (int posState = 0; posState < counters.length; ++posState) {
680                 if (counters[posState] <= 0) {
681                     counters[posState] = PRICE_UPDATE_INTERVAL;
682                     updatePrices(posState);
683                 }
684             }
685         }
686 
updatePrices(int posState)687         private void updatePrices(int posState) {
688             int choice0Price = RangeEncoder.getBitPrice(choice[0], 0);
689 
690             int i = 0;
691             for (; i < LOW_SYMBOLS; ++i)
692                 prices[posState][i] = choice0Price
693                         + RangeEncoder.getBitTreePrice(low[posState], i);
694 
695             choice0Price = RangeEncoder.getBitPrice(choice[0], 1);
696             int choice1Price = RangeEncoder.getBitPrice(choice[1], 0);
697 
698             for (; i < LOW_SYMBOLS + MID_SYMBOLS; ++i)
699                 prices[posState][i] = choice0Price + choice1Price
700                          + RangeEncoder.getBitTreePrice(mid[posState],
701                                                         i - LOW_SYMBOLS);
702 
703             choice1Price = RangeEncoder.getBitPrice(choice[1], 1);
704 
705             for (; i < prices[posState].length; ++i)
706                 prices[posState][i] = choice0Price + choice1Price
707                          + RangeEncoder.getBitTreePrice(high, i - LOW_SYMBOLS
708                                                               - MID_SYMBOLS);
709         }
710     }
711 }
712