Skip to main content

rar_stream/decompress/ppm/
model.rs

1//! PPMd model for RAR decompression.
2//!
3//! Based on Dmitry Shkarin's PPMd implementation.
4
5use super::super::BitReader;
6use super::range_coder::{RangeCoder, SubRange};
7use super::sub_alloc::SubAllocator;
8
9/// PPMd constants.
10const INT_BITS: u32 = 7;
11const PERIOD_BITS: u32 = 7;
12const TOT_BITS: u32 = INT_BITS + PERIOD_BITS;
13const INTERVAL: u32 = 1 << INT_BITS;
14const BIN_SCALE: u32 = 1 << TOT_BITS;
15const MAX_FREQ: u32 = 124;
16const MAX_O: usize = 64;
17const INIT_ESC: u32 = 4;
18
19/// PPMd state (symbol + frequency + successor).
20#[derive(Clone, Copy, Default)]
21struct State {
22    symbol: u8,
23    freq: u8,
24    successor: u32, // Offset in sub-allocator
25}
26
27/// PPMd context.
28struct Context {
29    num_stats: u16,
30    summ_freq: u16,
31    stats: u32,  // Offset to states array
32    suffix: u32, // Offset to suffix context
33    // For single-stat contexts, we use OneState inline
34    one_state: State,
35}
36
37/// SEE2 context for escape estimation.
38#[derive(Clone, Copy)]
39struct See2Context {
40    summ: u16,
41    shift: u8,
42    count: u8,
43}
44
45impl See2Context {
46    fn new(init_val: u16) -> Self {
47        Self {
48            summ: init_val << (PERIOD_BITS as u8 - 4),
49            shift: PERIOD_BITS as u8 - 4,
50            count: 4,
51        }
52    }
53
54    fn get_mean(&mut self) -> u32 {
55        let ret = (self.summ >> self.shift) as i16;
56        self.summ = self.summ.wrapping_sub(ret as u16);
57        if ret == 0 {
58            1
59        } else {
60            ret as u32
61        }
62    }
63
64    fn update(&mut self) {
65        if self.shift < PERIOD_BITS as u8 {
66            self.count = self.count.wrapping_sub(1);
67            if self.count == 0 {
68                self.summ = self.summ.wrapping_add(self.summ);
69                self.count = 3 << self.shift;
70                self.shift += 1;
71            }
72        }
73    }
74}
75
76/// PPMd model.
77pub struct PpmModel {
78    /// Sub-allocator for contexts.
79    sub_alloc: SubAllocator,
80    /// Minimum context.
81    min_context: u32,
82    /// Medium context.
83    med_context: u32,
84    /// Maximum context.
85    max_context: u32,
86    /// Found state.
87    found_state: u32,
88    /// Number of masked symbols.
89    num_masked: usize,
90    /// Initial escape.
91    init_esc: u32,
92    /// Order fall.
93    order_fall: i32,
94    /// Maximum order.
95    max_order: i32,
96    /// Run length.
97    run_length: i32,
98    /// Initial run length.
99    init_rl: i32,
100    /// Character mask.
101    char_mask: [u8; 256],
102    /// NS2 index mapping.
103    ns2_indx: [u8; 256],
104    /// NS2 BS index mapping.
105    ns2_bs_indx: [u8; 256],
106    /// HB2 flag.
107    hb2_flag: [u8; 256],
108    /// Escape count.
109    esc_count: u8,
110    /// Previous success.
111    prev_success: u8,
112    /// High bits flag.
113    hi_bits_flag: u8,
114    /// Binary SEE contexts.
115    bin_summ: [[u16; 64]; 128],
116    /// SEE2 contexts.
117    see2_cont: [[See2Context; 16]; 25],
118    /// Dummy SEE2 context.
119    dummy_see2: See2Context,
120    /// Escape character.
121    esc_char: i32,
122    /// Debug: decode count
123    debug_count: u32,
124}
125
126impl PpmModel {
127    /// Create a new PPM model.
128    pub fn new() -> Self {
129        Self {
130            sub_alloc: SubAllocator::new(1), // Start with 1MB
131            min_context: 0,
132            med_context: 0,
133            max_context: 0,
134            found_state: 0,
135            num_masked: 0,
136            init_esc: 0,
137            order_fall: 0,
138            max_order: 0,
139            run_length: 0,
140            init_rl: 0,
141            char_mask: [0; 256],
142            ns2_indx: [0; 256],
143            ns2_bs_indx: [0; 256],
144            hb2_flag: [0; 256],
145            esc_count: 0,
146            prev_success: 0,
147            hi_bits_flag: 0,
148            bin_summ: [[0; 64]; 128],
149            see2_cont: [[See2Context::new(0); 16]; 25],
150            dummy_see2: See2Context {
151                summ: 0,
152                shift: PERIOD_BITS as u8,
153                count: 0,
154            },
155            esc_char: -1,
156
157            debug_count: 0,
158        }
159    }
160
161    /// Initialize the model from a byte stream. Returns (RangeCoder, esc_char).
162    pub fn init(&mut self, reader: &mut BitReader) -> Result<(RangeCoder, i32), &'static str> {
163        let max_order_byte = reader.read_byte().ok_or("EOF reading max order")?;
164        let reset = (max_order_byte & 0x20) != 0;
165
166        #[cfg(test)]
167        eprintln!(
168            "[PPM init] max_order_byte=0x{:02x} reset={}",
169            max_order_byte, reset
170        );
171
172        // If reset flag is set, or if we haven't initialized yet, we need to initialize
173        let need_init = reset || self.min_context == 0;
174
175        let max_mb = if reset {
176            reader.read_byte().ok_or("EOF reading max MB")? as usize
177        } else {
178            1 // Default
179        };
180
181        if (max_order_byte & 0x40) != 0 {
182            self.esc_char = reader.read_byte().ok_or("EOF reading esc char")? as i32;
183        }
184
185        // Initialize range coder
186        let coder = RangeCoder::new(reader);
187
188        if need_init {
189            let mut max_order = (max_order_byte & 0x1f) as i32 + 1;
190            if max_order > 16 {
191                max_order = 16 + (max_order - 16) * 3;
192            }
193
194            #[cfg(test)]
195            eprintln!("[PPM init] max_order={} max_mb={}", max_order, max_mb);
196
197            if max_order == 1 {
198                return Err("Invalid max order");
199            }
200
201            // Resize sub-allocator (reuses buffer if size matches)
202            self.sub_alloc.resize(max_mb + 1);
203            self.start_model(max_order);
204        }
205
206        if self.min_context == 0 {
207            return Err("Model initialization failed");
208        }
209
210        Ok((coder, self.esc_char))
211    }
212
213    /// Start/restart the model.
214    fn start_model(&mut self, max_order: i32) {
215        self.max_order = max_order;
216        self.esc_count = 1;
217        self.restart_model();
218
219        // Initialize NS2 index tables
220        self.ns2_bs_indx[0] = 0;
221        self.ns2_bs_indx[1] = 2;
222        for i in 2..11 {
223            self.ns2_bs_indx[i] = 4;
224        }
225        for i in 11..256 {
226            self.ns2_bs_indx[i] = 6;
227        }
228
229        for i in 0..3 {
230            self.ns2_indx[i] = i as u8;
231        }
232        let mut m = 3u8;
233        let mut k = 1usize;
234        let mut step = 1usize;
235        for i in 3..256 {
236            self.ns2_indx[i] = m;
237            k = k.saturating_sub(1);
238            if k == 0 {
239                step += 1;
240                k = step;
241                m += 1;
242            }
243        }
244
245        for i in 0..0x40 {
246            self.hb2_flag[i] = 0;
247        }
248        for i in 0x40..0x100 {
249            self.hb2_flag[i] = 0x08;
250        }
251
252        self.dummy_see2.shift = PERIOD_BITS as u8;
253    }
254
255    /// Restart the model (clear and reinitialize).
256    fn restart_model(&mut self) {
257        self.char_mask = [0; 256];
258        self.sub_alloc.init();
259
260        self.init_rl = -(if self.max_order < 12 {
261            self.max_order
262        } else {
263            12
264        }) - 1;
265
266        // Allocate root context
267        let ctx = self.sub_alloc.alloc_context().unwrap_or(0);
268        self.min_context = ctx as u32;
269        self.max_context = ctx as u32;
270
271        if ctx == 0 {
272            return;
273        }
274
275        // Initialize root context with 256 symbols
276        self.write_context_num_stats(ctx, 256);
277        self.write_context_summ_freq(ctx, 257);
278
279        let stats = self.sub_alloc.alloc_units(128).unwrap_or(0);
280        self.write_context_stats(ctx, stats as u32);
281
282        // Verify it was written correctly
283
284        {
285            let _read_back = self.read_context_stats(ctx);
286        }
287        self.write_context_stats(ctx, stats as u32);
288
289        self.order_fall = self.max_order;
290        self.found_state = stats as u32;
291
292        // Initialize all 256 symbols with freq=1
293        for i in 0..256 {
294            self.write_state(stats + i * 6, i as u8, 1, 0);
295        }
296
297        // Verify initialization
298        #[cfg(test)]
299        {
300            for i in 0..256 {
301                let sym = self.read_state_symbol(stats + i * 6);
302                if sym != i as u8 {
303                    eprintln!(
304                        "[INIT] ERROR: stats[{}] has sym {} instead of {}",
305                        i, sym, i
306                    );
307                }
308            }
309        }
310
311        self.run_length = self.init_rl;
312        self.prev_success = 0;
313
314        // Initialize binary SEE contexts
315        let init_bin_esc: [u16; 8] = [
316            0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051,
317        ];
318
319        for i in 0..128 {
320            for k in 0..8 {
321                for m in (0..64).step_by(8) {
322                    self.bin_summ[i][k + m] =
323                        (BIN_SCALE as u16).wrapping_sub(init_bin_esc[k] / (i as u16 + 2));
324                }
325            }
326        }
327
328        // Initialize SEE2 contexts
329        for i in 0..25 {
330            for k in 0..16 {
331                self.see2_cont[i][k] = See2Context::new((5 * i + 10) as u16);
332            }
333        }
334    }
335
336    /// Decode a character.
337    pub fn decode_char(
338        &mut self,
339        coder: &mut RangeCoder,
340        reader: &mut BitReader,
341    ) -> Result<i32, &'static str> {
342        #[cfg(test)]
343        {
344            self.debug_count += 1;
345        }
346
347        #[cfg(test)]
348        let start_bytes = reader.byte_position();
349
350        #[cfg(test)]
351        if self.debug_count == 0 {
352            let (code, low, range) = coder.debug_state();
353            eprintln!(
354                "[ENTRY pos={}] low={} range={} code={} code-low={} prev_success={}",
355                self.debug_count,
356                low,
357                range,
358                code,
359                code.wrapping_sub(low),
360                self.prev_success
361            );
362        }
363
364        // Check context validity
365        let text_ptr = self.sub_alloc.text_ptr();
366        let heap_end = self.sub_alloc.heap_end();
367
368        if self.min_context as usize <= text_ptr || self.min_context as usize > heap_end {
369            return Err("Invalid context");
370        }
371
372        let num_stats = self.read_context_num_stats(self.min_context as usize);
373
374        #[cfg(test)]
375        if self.debug_count == 0 {
376            let (code, low, range) = coder.debug_state();
377            eprintln!(
378                "[ENTRY pos={}] low={} range={} code={} NumStats={} ctx={}",
379                self.debug_count, low, range, code, num_stats, self.min_context
380            );
381        }
382
383        #[cfg(test)]
384        if self.debug_count == 0 {
385            let summ = self.read_context_summ_freq(self.min_context as usize);
386            eprintln!(
387                "[pos={}] min_context={} NumStats={} SummFreq={} order_fall={}",
388                self.debug_count, self.min_context, num_stats, summ, self.order_fall
389            );
390        }
391
392        if num_stats != 1 {
393            // Multi-symbol context
394            let stats = self.read_context_stats(self.min_context as usize);
395            if stats as usize <= text_ptr || stats as usize > heap_end {
396                #[cfg(test)]
397                eprintln!(
398                    "[pos={}] INVALID STATS: ctx={} num_stats={} stats={} text_ptr={} heap_end={}",
399                    self.debug_count, self.min_context, num_stats, stats, text_ptr, heap_end
400                );
401                return Err("Invalid stats pointer");
402            }
403            #[cfg(test)]
404            if self.debug_count == 0 {
405                eprintln!(
406                    "[pos={}] Multi-symbol context at {}, num_stats={}",
407                    self.debug_count, self.min_context, num_stats
408                );
409            }
410            self.decode_symbol1(coder, reader)?;
411        } else {
412            // Binary context
413            #[cfg(test)]
414            if self.debug_count == 0 {
415                // OneState symbol is at context+2
416                let sym = self.sub_alloc.read_byte(self.min_context as usize + 2);
417                let suffix = self.read_context_suffix(self.min_context as usize);
418                eprintln!("[pos={}] Binary context at {}, sym='{}' ({}), suffix={}, order_fall={}, max_order={}", 
419                         self.debug_count, self.min_context, sym as char, sym, suffix, self.order_fall, self.max_order);
420            }
421            self.decode_bin_symbol(coder, reader)?;
422        }
423
424        // Normalize is called in the escape loop or at the end of decode_char
425        // Not here after a successful decode
426
427        while self.found_state == 0 {
428            coder.normalize(reader);
429            #[cfg(test)]
430            if self.debug_count == 0 {
431                let (code, low, range) = coder.debug_state();
432                eprintln!(
433                    "[ESCAPE pos={}] After normalize: low={} range={} code={}",
434                    self.debug_count, low, range, code
435                );
436            }
437
438            // Walk up suffix chain
439            loop {
440                self.order_fall += 1;
441                let suffix = self.read_context_suffix(self.min_context as usize);
442
443                #[cfg(test)]
444                if self.debug_count == 0 {
445                    eprintln!(
446                        "[ESCAPE pos={}] order_fall={} min_context={} suffix={}",
447                        self.debug_count, self.order_fall, self.min_context, suffix
448                    );
449                }
450
451                if suffix as usize <= text_ptr || suffix as usize > heap_end {
452                    #[cfg(test)]
453                    eprintln!(
454                        "[ESCAPE pos={}] Invalid suffix={} (text_ptr={} heap_end={})",
455                        self.debug_count, suffix, text_ptr, heap_end
456                    );
457                    return Err("Invalid suffix");
458                }
459
460                self.min_context = suffix;
461
462                let ns = self.read_context_num_stats(suffix as usize);
463                if ns as usize != self.num_masked {
464                    #[cfg(test)]
465                    if self.debug_count == 0 {
466                        eprintln!(
467                            "[ESCAPE pos={}] Found context with ns={} (masked={})",
468                            self.debug_count, ns, self.num_masked
469                        );
470                    }
471                    break;
472                }
473            }
474
475            self.decode_symbol2(coder, reader)?;
476            // No normalize here - unrar doesn't normalize after decodeSymbol2 inside the while loop
477        }
478
479        // Get the decoded symbol
480        let symbol = self.read_state_symbol(self.found_state as usize);
481
482        // Update model
483        let successor = self.read_state_successor(self.found_state as usize);
484        if self.order_fall == 0 && successor as usize > text_ptr {
485            let succ = successor;
486            self.min_context = succ;
487            self.max_context = succ;
488        } else {
489            self.update_model();
490            if self.esc_count == 0 {
491                self.clear_mask();
492            }
493        }
494
495        coder.normalize(reader);
496
497        #[cfg(test)]
498        {
499            let end_bytes = reader.byte_position();
500            let bytes_consumed = end_bytes - start_bytes;
501            if self.debug_count == 0 || (self.debug_count >= 1120 && self.debug_count <= 1135) {
502                eprintln!(
503                    "[pos={}] sym='{}' ({}) bytes_consumed={} found_state={}",
504                    self.debug_count, symbol as char, symbol, bytes_consumed, self.found_state
505                );
506            }
507        }
508
509        Ok(symbol as i32)
510    }
511
512    /// Decode from a multi-symbol context.
513    #[inline]
514    fn decode_symbol1(
515        &mut self,
516        coder: &mut RangeCoder,
517        _reader: &mut BitReader,
518    ) -> Result<(), &'static str> {
519        let summ_freq = self.read_context_summ_freq(self.min_context as usize);
520        let stats = self.read_context_stats(self.min_context as usize);
521        let num_stats = self.read_context_num_stats(self.min_context as usize);
522
523        #[cfg(test)]
524        if self.debug_count == 0 {
525            eprintln!(
526                "[DS1 pos={}] summ_freq={} num_stats={} prev_success_before={}",
527                self.debug_count, summ_freq, num_stats, self.prev_success
528            );
529        }
530
531        let count = coder.get_current_count(summ_freq as u32);
532
533        #[cfg(test)]
534        if self.debug_count == 0 {
535            eprintln!("[DS1 pos={}] count={}", self.debug_count, count);
536        }
537
538        // Check for out-of-range count
539        if count >= summ_freq as u32 {
540            return Err("Count exceeds scale");
541        }
542
543        let mut hi_cnt = 0u32;
544
545        for i in 0..num_stats {
546            let state_ptr = stats as usize + (i as usize) * 6;
547            let freq = self.read_state_freq(state_ptr) as u32;
548            #[cfg(test)]
549            let sym = self.read_state_symbol(state_ptr);
550            hi_cnt += freq;
551
552            #[cfg(test)]
553            if self.debug_count == 0 {
554                eprintln!(
555                    "[DS1 pos={}] i={} sym='{}' ({}) freq={} hi_cnt={}",
556                    self.debug_count, i, sym as char, sym, freq, hi_cnt
557                );
558            }
559
560            if hi_cnt > count {
561                let lo_cnt = hi_cnt - freq;
562
563                #[cfg(test)]
564                if self.debug_count == 0 {
565                    eprintln!(
566                        "[DS1 pos={}] Selected i={} sym='{}' ({}) lo={} hi={}",
567                        self.debug_count, i, sym as char, sym, lo_cnt, hi_cnt
568                    );
569                    let (code, low, range) = coder.debug_state();
570                    eprintln!(
571                        "[DS1 pos={}] BEFORE decode: low={} range={} code={}",
572                        self.debug_count, low, range, code
573                    );
574                }
575                let sub = SubRange {
576                    low_count: lo_cnt,
577                    high_count: hi_cnt,
578                    scale: summ_freq as u32,
579                };
580                coder.decode(&sub);
581
582                #[cfg(test)]
583                if self.debug_count == 0 {
584                    let (code, low, range) = coder.debug_state();
585                    eprintln!(
586                        "[DS1 pos={}] AFTER decode: low={:#x} range={:#x} code={:#x}",
587                        self.debug_count, low, range, code
588                    );
589                }
590
591                // Calculate prev_success BEFORE updating frequencies (match unrar)
592                // IMPORTANT: PrevSuccess is only calculated for FIRST symbol (i==0)
593                // For other symbols, PrevSuccess = 0
594                if i == 0 {
595                    self.prev_success = if 2 * freq > summ_freq as u32 { 1 } else { 0 };
596                    self.run_length += self.prev_success as i32;
597                } else {
598                    self.prev_success = 0;
599                }
600
601                // Update frequency and check for rescale
602                let hi_cnt = freq + 4;
603                self.write_state_freq(state_ptr, hi_cnt as u8);
604
605                // Update summ_freq
606                let new_summ = summ_freq.saturating_add(4);
607                self.write_context_summ_freq(self.min_context as usize, new_summ);
608
609                // Swap with previous state if this one has higher frequency (move-to-front)
610                // This matches unrar's update1() behavior
611                if i > 0 {
612                    let prev_ptr = stats as usize + ((i - 1) as usize) * 6;
613                    let prev_freq = self.read_state_freq(prev_ptr);
614                    if hi_cnt as u8 > prev_freq {
615                        // Swap the two states (6 bytes each)
616                        let cur_sym = self.read_state_symbol(state_ptr);
617                        let cur_succ = self.read_state_successor(state_ptr);
618                        let prev_sym = self.read_state_symbol(prev_ptr);
619                        let prev_succ = self.read_state_successor(prev_ptr);
620
621                        self.write_state(prev_ptr, cur_sym, hi_cnt as u8, cur_succ);
622                        self.write_state(state_ptr, prev_sym, prev_freq, prev_succ);
623
624                        self.found_state = prev_ptr as u32;
625
626                        // Check if rescale needed
627                        if hi_cnt > MAX_FREQ {
628                            self.rescale();
629                        }
630                    } else {
631                        self.found_state = state_ptr as u32;
632                        if hi_cnt > MAX_FREQ {
633                            self.rescale();
634                        }
635                    }
636                } else {
637                    self.found_state = state_ptr as u32;
638                    if hi_cnt > MAX_FREQ {
639                        self.rescale();
640                    }
641                }
642
643                return Ok(());
644            }
645        }
646
647        // Escape
648        #[cfg(test)]
649        if self.debug_count == 0 {
650            eprintln!(
651                "[DS1 pos={} ESCAPE] hi_cnt={} summ_freq={} before decode",
652                self.debug_count, hi_cnt, summ_freq
653            );
654        }
655
656        // Set PrevSuccess = 0 on escape (matching unrar line 467)
657        self.prev_success = 0;
658
659        // Set HiBitsFlag based on previous FoundState's symbol (matching unrar's line 448)
660        if self.found_state != 0 {
661            let prev_sym = self.read_state_symbol(self.found_state as usize);
662            self.hi_bits_flag = self.hb2_flag[prev_sym as usize];
663        }
664
665        let sub = SubRange {
666            low_count: hi_cnt,
667            high_count: summ_freq as u32,
668            scale: summ_freq as u32,
669        };
670        coder.decode(&sub);
671
672        #[cfg(test)]
673        if self.debug_count == 0 {
674            let (code, low, range) = coder.debug_state();
675            eprintln!(
676                "[DS1 pos=98 ESCAPE] After decode: low={} range={} code={}",
677                low, range, code
678            );
679        }
680
681        self.num_masked = num_stats as usize;
682        self.found_state = 0;
683
684        // Set masks - mark all symbols in this context as masked
685        // NOTE: Do NOT increment esc_count here - that happens in update2() after decodeSymbol2 finds a symbol
686        for i in 0..num_stats {
687            let state_ptr = stats as usize + (i as usize) * 6;
688            let sym = self.read_state_symbol(state_ptr);
689            self.char_mask[sym as usize] = self.esc_count;
690        }
691
692        Ok(())
693    }
694
695    /// Decode from a binary context.
696    #[inline]
697    fn decode_bin_symbol(
698        &mut self,
699        coder: &mut RangeCoder,
700        _reader: &mut BitReader,
701    ) -> Result<(), &'static str> {
702        let state = self.read_context_one_state(self.min_context as usize);
703
704        // Update HiBitsFlag based on previous FoundState's symbol (set at start of decode)
705        if self.found_state != 0 {
706            let prev_sym = self.read_state_symbol(self.found_state as usize);
707            self.hi_bits_flag = self.hb2_flag[prev_sym as usize];
708        }
709
710        // Get binary probability - match unrar's index calculation exactly
711        let suffix = self.read_context_suffix(self.min_context as usize);
712        let suffix_num_stats = if suffix != 0 {
713            self.read_context_num_stats(suffix as usize)
714        } else {
715            1 // Default if no suffix
716        };
717
718        // Use NS2BSIndx (not ns2_indx) with NumStats-1
719        let ns_idx = if suffix_num_stats > 0 {
720            (suffix_num_stats - 1).min(255)
721        } else {
722            0
723        };
724        // SAFETY: ns_idx clamped to [0, 255], ns2_bs_indx is [u8; 256]
725        let ns1 = unsafe { *self.ns2_bs_indx.get_unchecked(ns_idx as usize) } as usize;
726
727        // Index calculation matching unrar:
728        // PrevSuccess + NS2BSIndx[Suffix->NumStats-1] + HiBitsFlag + 2*HB2Flag[rs.Symbol] + ((RunLength >> 26) & 0x20)
729        let idx1 = (self.prev_success as usize)
730            + ns1
731            + self.hi_bits_flag as usize
732            + 2 * (unsafe { *self.hb2_flag.get_unchecked(state.symbol as usize) } as usize)
733            + ((self.run_length >> 26) & 0x20) as usize;
734
735        // BinSumm first index is Freq-1 (not freq>>2)
736        let freq_idx = state.freq.saturating_sub(1) as usize;
737        // SAFETY: freq_idx < 128 and idx1 < 64 guaranteed by saturating ops and bit mask
738        let freq_idx = freq_idx & 127; // BinSumm is [128][64]
739        let idx1 = idx1 & 63;
740
741        let bs = unsafe { *self.bin_summ.get_unchecked(freq_idx).get_unchecked(idx1) };
742
743        #[cfg(test)]
744        if self.debug_count == 0 {
745            eprintln!("[BIN pos={} idx] prev_success={} ns1={} hi_bits_flag={} hb2_flag[{}]={} run_length={}", 
746                     self.debug_count, self.prev_success, ns1, self.hi_bits_flag, state.symbol, self.hb2_flag[state.symbol as usize], self.run_length);
747            eprintln!(
748                "[BIN pos={} idx] idx1={} freq_idx={} bs={}",
749                self.debug_count, idx1, freq_idx, bs
750            );
751        }
752
753        let count = coder.get_current_shift_count(TOT_BITS);
754
755        #[cfg(test)]
756        if self.debug_count == 0 {
757            eprintln!(
758                "[BIN pos={}] sym='{}' ({}) freq={} bs={} count={}",
759                self.debug_count, state.symbol as char, state.symbol, state.freq, bs, count
760            );
761            let (code, low, range) = coder.debug_state();
762            eprintln!(
763                "[BIN pos={}] after get_count: low={} range={} code={}",
764                self.debug_count, low, range, code
765            );
766        }
767
768        if count < bs as u32 {
769            // Symbol found
770            let sub = SubRange {
771                low_count: 0,
772                high_count: bs as u32,
773                scale: BIN_SCALE,
774            };
775
776            #[cfg(test)]
777            if self.debug_count == 0 {
778                let (code, low, range) = coder.debug_state();
779                eprintln!("[BIN pos={}] FOUND: lo=0 hi={} scale={} | before decode: low={} range={} code={}", 
780                         self.debug_count, bs, BIN_SCALE, low, range, code);
781            }
782
783            coder.decode(&sub);
784
785            // Update frequency
786            let new_freq = state.freq + (if state.freq < 128 { 1 } else { 0 });
787            self.write_context_one_state_freq(self.min_context as usize, new_freq);
788
789            // Update bin_summ: bs + INTERVAL - GET_MEAN(bs, PERIOD_BITS, 2)
790            // GET_MEAN(SUMM,SHIFT,ROUND) = ((SUMM+(1 << (SHIFT-ROUND))) >> SHIFT)
791            let mean = ((bs as u32 + (1 << (PERIOD_BITS - 2))) >> PERIOD_BITS) as u16;
792            let new_bs = bs.saturating_add((INTERVAL as u16).saturating_sub(mean));
793            // SAFETY: freq_idx < 128 and idx1 < 64 guaranteed by bit masking above
794            unsafe {
795                *self
796                    .bin_summ
797                    .get_unchecked_mut(freq_idx)
798                    .get_unchecked_mut(idx1) = new_bs
799            };
800
801            self.found_state = self.min_context + 2; // OneState offset (in union at offset 2)
802            self.prev_success = 1;
803            self.run_length += 1;
804        } else {
805            // Escape
806            let sub = SubRange {
807                low_count: bs as u32,
808                high_count: BIN_SCALE,
809                scale: BIN_SCALE,
810            };
811
812            #[cfg(test)]
813            if self.debug_count == 0 {
814                let (code, low, range) = coder.debug_state();
815                eprintln!("[BIN pos={}] ESCAPE: lo={} hi={} scale={} | before decode: low={} range={} code={}", 
816                         self.debug_count, bs, BIN_SCALE, BIN_SCALE, low, range, code);
817            }
818
819            coder.decode(&sub);
820
821            // Update bin_summ: bs - GET_MEAN(bs, PERIOD_BITS, 2)
822            let mean = ((bs as u32 + (1 << (PERIOD_BITS - 2))) >> PERIOD_BITS) as u16;
823            let new_bs = bs.saturating_sub(mean);
824            // SAFETY: freq_idx < 128 and idx1 < 64 guaranteed by bit masking above
825            unsafe {
826                *self
827                    .bin_summ
828                    .get_unchecked_mut(freq_idx)
829                    .get_unchecked_mut(idx1) = new_bs
830            };
831
832            // InitEsc = ExpEscape[bs >> 10]
833            static EXP_ESCAPE: [u8; 16] = [25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2];
834            // SAFETY: index clamped to [0, 15], EXP_ESCAPE has 16 elements
835            let esc_idx = ((new_bs >> 10) as usize).min(15);
836            self.init_esc = unsafe { *EXP_ESCAPE.get_unchecked(esc_idx) } as u32;
837
838            self.num_masked = 1;
839            self.found_state = 0;
840            // SAFETY: state.symbol is u8, char_mask is [u8; 256]
841            unsafe { *self.char_mask.get_unchecked_mut(state.symbol as usize) = self.esc_count };
842            // Don't increment esc_count here - it's done in update2 after successful decode
843            self.prev_success = 0;
844        }
845
846        Ok(())
847    }
848
849    /// Decode from a masked context.
850    #[inline]
851    fn decode_symbol2(
852        &mut self,
853        coder: &mut RangeCoder,
854        _reader: &mut BitReader,
855    ) -> Result<(), &'static str> {
856        #[cfg(test)]
857        if self.debug_count == 0 {
858            let (code, low, range) = coder.debug_state();
859            eprintln!(
860                "[DS2 pos={} entry] coder: low={:010} range={:010} code={:010}",
861                self.debug_count, low, range, code
862            );
863        }
864
865        let num_stats = self.read_context_num_stats(self.min_context as usize);
866        let stats = self.read_context_stats(self.min_context as usize);
867
868        #[cfg(test)]
869        if self.debug_count == 0 || self.debug_count == 58 {
870            eprintln!(
871                "[DS2 pos={}] min_context={} num_stats={} num_masked={}",
872                self.debug_count, self.min_context, num_stats, self.num_masked
873            );
874        }
875
876        // Calculate i = NumStats - NumMasked (number of unmasked symbols)
877        let i = num_stats as usize - self.num_masked;
878        if i == 0 {
879            return Err("All symbols masked");
880        }
881
882        // Calculate escape frequency using SEE2 or simplified for root
883        let esc_freq: u32;
884        let see2_row: usize;
885        let see2_col: usize;
886        let is_root = num_stats == 256;
887
888        if !is_root {
889            // Use SEE2 - simplified version using NS2Indx
890            let ns2_idx = self.ns2_indx[(i - 1).min(255)] as usize;
891            let suffix = self.read_context_suffix(self.min_context as usize);
892            let suffix_num_stats = if suffix != 0 {
893                self.read_context_num_stats(suffix as usize)
894            } else {
895                num_stats
896            };
897            let summ_freq = self.read_context_summ_freq(self.min_context as usize);
898
899            // Index into SEE2Cont
900            let diff_suffix = (i < (suffix_num_stats as usize - num_stats as usize)) as usize;
901            let freq_check = (summ_freq < 11 * num_stats) as usize;
902            let masked_check = (self.num_masked > i) as usize;
903            let see2_idx = ns2_idx
904                + diff_suffix
905                + 2 * freq_check
906                + 4 * masked_check
907                + self.hi_bits_flag as usize;
908            let see2_idx = see2_idx.min(24 * 16 - 1);
909
910            see2_row = ns2_idx.min(24);
911            see2_col = see2_idx % 16;
912
913            // Use get_mean() which decrements Summ (matching unrar's getMean behavior)
914            esc_freq = self.see2_cont[see2_row][see2_col].get_mean();
915
916            #[cfg(test)]
917            if self.debug_count == 58 || self.debug_count == 0 {
918                let suffix = self.read_context_suffix(self.min_context as usize);
919                let suffix_ns = if suffix != 0 {
920                    self.read_context_num_stats(suffix as usize)
921                } else {
922                    0
923                };
924                eprintln!("[DS2 pos={}] SEE2 inputs: i={} suffix_ns={} summ_freq={} num_masked={} hi_bits_flag={}",
925                         self.debug_count, i, suffix_ns, summ_freq, self.num_masked, self.hi_bits_flag);
926                eprintln!("[DS2 pos={}] SEE2 indices: ns2_idx={} diff_suffix={} freq_check={} masked_check={}", 
927                         self.debug_count, ns2_idx, diff_suffix, freq_check, masked_check);
928                eprintln!(
929                    "[DS2 pos={}] SEE2: see2_idx={} esc_freq={}",
930                    self.debug_count, see2_idx, esc_freq
931                );
932            }
933        } else {
934            // Root context uses scale=1 (escape freq = 1)
935            esc_freq = 1;
936            see2_row = 0;
937            see2_col = 0;
938        }
939
940        // First pass: count unmasked symbol frequencies (avoid 3KB array allocation)
941        let mut hi_cnt = 0u32;
942
943        for j in 0..num_stats {
944            let state_ptr = stats as usize + (j as usize) * 6;
945            let sym = self.read_state_symbol(state_ptr);
946            if self.char_mask[sym as usize] != self.esc_count {
947                let freq = self.read_state_freq(state_ptr) as u32;
948                hi_cnt += freq;
949            }
950        }
951
952        #[cfg(test)]
953        let _freq_histogram = [0u32; 256];
954
955        #[cfg(test)]
956        if self.debug_count == 15 {
957            eprintln!(
958                "[DS2 pos=15] stats pointer={}, root context={}",
959                stats, self.min_context
960            );
961
962            // Find symbol 'l' (108) and 'p' (112)
963            let mut cum = 0u32;
964            for j in 0..num_stats {
965                let state_ptr = stats as usize + (j as usize) * 6;
966                let sym = self.read_state_symbol(state_ptr);
967                if self.char_mask[sym as usize] != self.esc_count {
968                    let freq = self.read_state_freq(state_ptr) as u32;
969                    let prev_cum = cum;
970                    cum += freq;
971                    if sym == 108 {
972                        // 'l'
973                        eprintln!(
974                            "[DS2 pos=15] 'l' at j={} prev_cum={} cum={} freq={}",
975                            j, prev_cum, cum, freq
976                        );
977                    }
978                    if sym == 112 {
979                        // 'p'
980                        eprintln!(
981                            "[DS2 pos=15] 'p' at j={} prev_cum={} cum={} freq={}",
982                            j, prev_cum, cum, freq
983                        );
984                    }
985                    // Trace symbols with freq > 1
986                    if freq > 1 {
987                        eprintln!("[DS2 pos=15] sym='{}' ({}) j={} prev_cum={} cum={} freq={} state_ptr={}", 
988                                 sym as char, sym, j, prev_cum, cum, freq, state_ptr);
989                    }
990                }
991            }
992        }
993
994        #[cfg(test)]
995        if self.debug_count == 13 {
996            // Find symbol 'd' (100)
997            let mut cum = 0u32;
998            for j in 0..num_stats {
999                let state_ptr = stats as usize + (j as usize) * 6;
1000                let sym = self.read_state_symbol(state_ptr);
1001                if self.char_mask[sym as usize] != self.esc_count {
1002                    let freq = self.read_state_freq(state_ptr) as u32;
1003                    let prev_cum = cum;
1004                    cum += freq;
1005                    if sym == 100 {
1006                        // 'd'
1007                        eprintln!(
1008                            "[DS2 pos=13] 'd' at j={} prev_cum={} cum={} freq={}",
1009                            j, prev_cum, cum, freq
1010                        );
1011                    }
1012                    // Also trace which symbol is at cumulative 238-239
1013                    if prev_cum <= 238 && cum > 238 {
1014                        eprintln!(
1015                            "[DS2 pos=13] At cum=238: j={} sym='{}' ({}) prev_cum={} cum={}",
1016                            j, sym as char, sym, prev_cum, cum
1017                        );
1018                    }
1019                }
1020            }
1021            eprintln!("[DS2 pos=13] To select 'd', need count in [prev_cum, cum)");
1022        }
1023
1024        // Total scale = escape freq + sum of unmasked frequencies
1025        let scale = esc_freq + hi_cnt;
1026
1027        let count = coder.get_current_count(scale);
1028
1029        #[cfg(test)]
1030        if self.debug_count == 0 {
1031            eprintln!(
1032                "[DS2 pos={}] esc_freq={} hi_cnt={} scale={} count={}",
1033                self.debug_count, esc_freq, hi_cnt, scale, count
1034            );
1035        }
1036
1037        // Find symbol or escape
1038        if count < hi_cnt {
1039            // Symbol found - re-iterate to find it
1040            let mut cum = 0u32;
1041            for j in 0..num_stats {
1042                let state_ptr = stats as usize + (j as usize) * 6;
1043                let sym = self.read_state_symbol(state_ptr);
1044                if self.char_mask[sym as usize] != self.esc_count {
1045                    let freq = self.read_state_freq(state_ptr) as u32;
1046                    cum += freq;
1047                    if cum > count {
1048                        let lo_cnt = cum - freq;
1049
1050                        #[cfg(test)]
1051                        if self.debug_count == 0 || self.debug_count == 58 {
1052                            eprintln!(
1053                                "[DS2 pos={}] Selected j={} sym='{}' ({}) at cum={} lo={} freq={}",
1054                                self.debug_count, j, sym as char, sym, cum, lo_cnt, freq
1055                            );
1056                        }
1057
1058                        #[cfg(test)]
1059                        if self.debug_count == 13 || self.debug_count == 58 {
1060                            let (code, low, range) = coder.debug_state();
1061                            eprintln!(
1062                                "[DS2 pos={}] FOUND lo={} hi={} scale={}",
1063                                self.debug_count, lo_cnt, cum, scale
1064                            );
1065                            eprintln!(
1066                                "[DS2 pos={}] Before decode: low={} range={} code={}",
1067                                self.debug_count, low, range, code
1068                            );
1069                        }
1070
1071                        let sub = SubRange {
1072                            low_count: lo_cnt,
1073                            high_count: cum,
1074                            scale,
1075                        };
1076                        coder.decode(&sub);
1077
1078                        #[cfg(test)]
1079                        if self.debug_count == 13 || self.debug_count == 58 {
1080                            let (code, low, range) = coder.debug_state();
1081                            eprintln!(
1082                                "[DS2 pos={}] After decode: low={} range={} code={}",
1083                                self.debug_count, low, range, code
1084                            );
1085                        }
1086
1087                        // Update SEE2 context (matching unrar's psee2c->update())
1088                        if !is_root {
1089                            self.see2_cont[see2_row][see2_col].update();
1090                        }
1091
1092                        self.found_state = state_ptr as u32;
1093
1094                        // Update frequency and check for rescale (update2)
1095                        let new_freq = freq + 4;
1096                        self.write_state_freq(state_ptr, new_freq as u8);
1097
1098                        let summ = self.read_context_summ_freq(self.min_context as usize);
1099                        self.write_context_summ_freq(self.min_context as usize, summ + 4);
1100
1101                        // Check if rescale needed
1102                        if new_freq > MAX_FREQ {
1103                            self.rescale();
1104                        }
1105
1106                        self.esc_count = self.esc_count.wrapping_add(1);
1107                        self.run_length = self.init_rl;
1108
1109                        return Ok(());
1110                    }
1111                }
1112            }
1113        }
1114
1115        // Escape - add scale to SEE2 Summ (matching unrar's psee2c->Summ += scale)
1116        if !is_root {
1117            self.see2_cont[see2_row][see2_col].summ = self.see2_cont[see2_row][see2_col]
1118                .summ
1119                .wrapping_add(scale as u16);
1120        }
1121
1122        let sub = SubRange {
1123            low_count: hi_cnt,
1124            high_count: scale,
1125            scale,
1126        };
1127        coder.decode(&sub);
1128
1129        // Mask remaining unmasked symbols
1130        for j in 0..num_stats {
1131            let state_ptr = stats as usize + (j as usize) * 6;
1132            let sym = self.read_state_symbol(state_ptr);
1133            if self.char_mask[sym as usize] != self.esc_count {
1134                self.char_mask[sym as usize] = self.esc_count;
1135            }
1136        }
1137        self.num_masked = num_stats as usize;
1138
1139        Ok(())
1140    }
1141
1142    /// Update the model after decoding.
1143    /// Create a child context.
1144    /// Returns the new context pointer, or 0 on failure.
1145    fn create_child(
1146        &mut self,
1147        parent_ctx: u32,
1148        p_stats: usize,
1149        first_state_symbol: u8,
1150        first_state_freq: u8,
1151        first_state_successor: u32,
1152    ) -> u32 {
1153        let pc = match self.sub_alloc.alloc_context() {
1154            Some(ctx) => ctx as u32,
1155            None => return 0,
1156        };
1157
1158        // NumStats = 1 (binary context)
1159        self.write_context_num_stats(pc as usize, 1);
1160
1161        // OneState = FirstState (stored inline at offset 2, in the union with SummFreq+Stats)
1162        // Layout: Symbol(1) + Freq(1) + Successor(4) = 6 bytes at offset 2-7
1163        self.write_state(
1164            pc as usize + 2,
1165            first_state_symbol,
1166            first_state_freq,
1167            first_state_successor,
1168        );
1169
1170        // Suffix = parent context
1171        self.write_context_suffix(pc as usize, parent_ctx);
1172
1173        // Update pStats->Successor to point to new context
1174        self.write_state_successor(p_stats, pc);
1175
1176        pc
1177    }
1178
1179    /// Rescale frequencies in the current context when they exceed MAX_FREQ.
1180    /// This halves all frequencies while maintaining sorted order.
1181    fn rescale(&mut self) {
1182        let ctx = self.min_context as usize;
1183        let old_ns = self.read_context_num_stats(ctx);
1184        let stats = self.read_context_stats(ctx);
1185
1186        // Move FoundState to front (swap chain)
1187        let mut p = self.found_state as usize;
1188        while p != stats as usize {
1189            // Swap p with p-6 (previous state)
1190            let prev_p = p - 6;
1191            let p_sym = self.read_state_symbol(p);
1192            let p_freq = self.read_state_freq(p);
1193            let p_succ = self.read_state_successor(p);
1194            let prev_sym = self.read_state_symbol(prev_p);
1195            let prev_freq = self.read_state_freq(prev_p);
1196            let prev_succ = self.read_state_successor(prev_p);
1197            self.write_state(p, prev_sym, prev_freq, prev_succ);
1198            self.write_state(prev_p, p_sym, p_freq, p_succ);
1199            p = prev_p;
1200        }
1201
1202        // Add 4 to first symbol's freq and SummFreq
1203        let first_freq = self.read_state_freq(stats as usize);
1204        self.write_state_freq(stats as usize, first_freq.saturating_add(4));
1205        let summ = self.read_context_summ_freq(ctx);
1206        self.write_context_summ_freq(ctx, summ.saturating_add(4));
1207
1208        // Calculate EscFreq and Adder
1209        let new_first_freq = self.read_state_freq(stats as usize) as u32;
1210        let mut esc_freq = self.read_context_summ_freq(ctx) as i32 - new_first_freq as i32;
1211        let adder = if self.order_fall != 0 { 1 } else { 0 };
1212
1213        // Halve first symbol's freq
1214        let halved = ((new_first_freq + adder) >> 1) as u8;
1215        self.write_state_freq(stats as usize, halved);
1216        let mut new_summ = halved as u16;
1217
1218        // Halve all other frequencies, maintaining sorted order
1219        for i in 1..old_ns as usize {
1220            let state_ptr = stats as usize + i * 6;
1221            let freq = self.read_state_freq(state_ptr);
1222            esc_freq -= freq as i32;
1223
1224            let halved = ((freq as u32 + adder) >> 1) as u8;
1225            self.write_state_freq(state_ptr, halved);
1226            new_summ += halved as u16;
1227
1228            // Bubble up if needed (maintain sorted order by freq)
1229            if halved > self.read_state_freq(state_ptr - 6) {
1230                // Save current state
1231                let sym = self.read_state_symbol(state_ptr);
1232                let succ = self.read_state_successor(state_ptr);
1233
1234                // Find insertion point
1235                let mut j = state_ptr - 6;
1236                while j >= stats as usize + 6 && halved > self.read_state_freq(j - 6) {
1237                    j -= 6;
1238                }
1239
1240                // Shift states down
1241                let mut k = state_ptr;
1242                while k > j {
1243                    let prev_sym = self.read_state_symbol(k - 6);
1244                    let prev_freq = self.read_state_freq(k - 6);
1245                    let prev_succ = self.read_state_successor(k - 6);
1246                    self.write_state(k, prev_sym, prev_freq, prev_succ);
1247                    k -= 6;
1248                }
1249
1250                // Insert at j
1251                self.write_state(j, sym, halved, succ);
1252            }
1253        }
1254
1255        // Handle zero-frequency states (remove them)
1256        let mut num_zeros = 0;
1257        for i in (0..old_ns as usize).rev() {
1258            let state_ptr = stats as usize + i * 6;
1259            if self.read_state_freq(state_ptr) == 0 {
1260                num_zeros += 1;
1261            } else {
1262                break;
1263            }
1264        }
1265
1266        if num_zeros > 0 {
1267            esc_freq += num_zeros;
1268            let new_ns = old_ns - num_zeros as u16;
1269
1270            if new_ns == 1 {
1271                // Convert back to binary context
1272                let sym = self.read_state_symbol(stats as usize);
1273                let mut freq = self.read_state_freq(stats as usize);
1274                let succ = self.read_state_successor(stats as usize);
1275
1276                // Halve freq until EscFreq <= 1
1277                while esc_freq > 1 {
1278                    freq = freq.saturating_sub(freq >> 1);
1279                    esc_freq >>= 1;
1280                }
1281
1282                // Free the stats array
1283                let units = (old_ns as usize + 1) >> 1;
1284                self.sub_alloc.free_units(stats as usize, units);
1285
1286                // Write OneState
1287                self.write_context_num_stats(ctx, 1);
1288                self.write_state(ctx + 2, sym, freq, succ);
1289                self.found_state = (ctx + 2) as u32;
1290                return;
1291            }
1292
1293            self.write_context_num_stats(ctx, new_ns);
1294
1295            // TODO: Shrink stats array if needed (requires shrink_units in allocator)
1296            // For now, we just leave the extra space allocated
1297        }
1298
1299        // Update SummFreq with remaining escape frequency
1300        new_summ += (esc_freq - (esc_freq >> 1)) as u16;
1301        self.write_context_summ_freq(ctx, new_summ);
1302
1303        // FoundState is now the first state
1304        let new_stats = self.read_context_stats(ctx);
1305        self.found_state = new_stats;
1306    }
1307
1308    /// Create successors for the current context chain.
1309    /// Returns the new context, or 0 on failure.
1310    fn create_successors(&mut self, skip: bool, p1: Option<usize>) -> u32 {
1311        let up_branch = self.read_state_successor(self.found_state as usize);
1312        let fs_symbol = self.read_state_symbol(self.found_state as usize);
1313
1314        #[cfg(test)]
1315        if self.debug_count == 12 {
1316            eprintln!(
1317                "[CS pos=12] Entry: skip={} p1={:?} up_branch={} fs_symbol='{}'",
1318                skip, p1, up_branch, fs_symbol as char
1319            );
1320        }
1321
1322        let mut pc = self.min_context;
1323        // Initialize array - optimizer may elide this when it sees writes before reads
1324        let mut ps: [usize; MAX_O] = [0; MAX_O];
1325        let mut pps_idx = 0;
1326
1327        if !skip {
1328            ps[pps_idx] = self.found_state as usize;
1329            pps_idx += 1;
1330            let suffix = self.read_context_suffix(pc as usize);
1331            if suffix == 0 {
1332                // goto NO_LOOP
1333                if pps_idx == 0 {
1334                    return pc;
1335                }
1336                return self.create_successors_finish(pc, &ps, pps_idx, up_branch, fs_symbol);
1337            }
1338        }
1339
1340        let mut p: usize;
1341        let mut start_in_loop = false;
1342        if let Some(p1_val) = p1 {
1343            p = p1_val;
1344            pc = self.read_context_suffix(pc as usize);
1345            start_in_loop = true;
1346        } else {
1347            p = 0; // Will be set in loop
1348        }
1349
1350        // Main loop
1351        loop {
1352            if !start_in_loop {
1353                pc = self.read_context_suffix(pc as usize);
1354                if pc == 0 {
1355                    break;
1356                }
1357
1358                let num_stats = self.read_context_num_stats(pc as usize);
1359                if num_stats != 1 {
1360                    let stats = self.read_context_stats(pc as usize);
1361                    p = stats as usize;
1362                    if self.read_state_symbol(p) != fs_symbol {
1363                        loop {
1364                            p += 6;
1365                            if self.read_state_symbol(p) == fs_symbol {
1366                                break;
1367                            }
1368                        }
1369                    }
1370                } else {
1371                    // OneState at context+2 (in union)
1372                    p = pc as usize + 2;
1373                }
1374            }
1375            start_in_loop = false; // Only skip to LOOP_ENTRY on first iteration
1376
1377            // LOOP_ENTRY
1378            let p_successor = self.read_state_successor(p);
1379            if p_successor != up_branch {
1380                pc = p_successor;
1381                break;
1382            }
1383
1384            if pps_idx >= MAX_O {
1385                return 0;
1386            }
1387            ps[pps_idx] = p;
1388            pps_idx += 1;
1389
1390            let suffix = self.read_context_suffix(pc as usize);
1391            if suffix == 0 {
1392                break;
1393            }
1394        }
1395
1396        self.create_successors_finish(pc, &ps, pps_idx, up_branch, fs_symbol)
1397    }
1398
1399    fn create_successors_finish(
1400        &mut self,
1401        mut pc: u32,
1402        ps: &[usize; MAX_O],
1403        pps_idx: usize,
1404        up_branch: u32,
1405        fs_symbol: u8,
1406    ) -> u32 {
1407        #[cfg(test)]
1408        if self.debug_count == 12 {
1409            eprintln!(
1410                "[CS_FINISH pos=12] pc={} pps_idx={} up_branch={} fs_symbol='{}'",
1411                pc, pps_idx, up_branch, fs_symbol as char
1412            );
1413            for i in 0..pps_idx {
1414                let sym = self.read_state_symbol(ps[i]);
1415                eprintln!(
1416                    "[CS_FINISH pos=12] ps[{}]={} sym='{}'",
1417                    i, ps[i], sym as char
1418                );
1419            }
1420        }
1421
1422        // Suppress unused warning when not in test mode
1423        let _ = fs_symbol;
1424
1425        if pps_idx == 0 {
1426            return pc;
1427        }
1428
1429        // UpState.Symbol = *(byte*)UpBranch
1430        let up_state_symbol = self.sub_alloc.read_byte(up_branch as usize);
1431        // UpState.Successor = (byte*)UpBranch + 1
1432        let up_state_successor = up_branch + 1;
1433
1434        let up_state_freq: u8;
1435        let num_stats = self.read_context_num_stats(pc as usize);
1436        if num_stats != 1 {
1437            let text_ptr = self.sub_alloc.get_text_ptr();
1438            if pc as usize <= text_ptr {
1439                return 0;
1440            }
1441
1442            let stats = self.read_context_stats(pc as usize);
1443            let mut p = stats as usize;
1444            if self.read_state_symbol(p) != up_state_symbol {
1445                loop {
1446                    p += 6;
1447                    if self.read_state_symbol(p) == up_state_symbol {
1448                        break;
1449                    }
1450                }
1451            }
1452
1453            let cf = self.read_state_freq(p) as u32 - 1;
1454            let s0 = self.read_context_summ_freq(pc as usize) as u32 - num_stats as u32 - cf;
1455            // unrar: UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0)));
1456            // Note: the 1+ applies to the entire expression!
1457            up_state_freq = (1 + if 2 * cf <= s0 {
1458                if 5 * cf > s0 {
1459                    1
1460                } else {
1461                    0
1462                }
1463            } else {
1464                (2 * cf + 3 * s0 - 1) / (2 * s0)
1465            })
1466            .min(255) as u8;
1467        } else {
1468            // OneState.Freq (at offset 2+1=3)
1469            up_state_freq = self.read_state_freq(pc as usize + 2);
1470        }
1471
1472        // Create children in reverse order
1473        let mut i = pps_idx;
1474        while i > 0 {
1475            i -= 1;
1476            pc = self.create_child(
1477                pc,
1478                ps[i],
1479                up_state_symbol,
1480                up_state_freq,
1481                up_state_successor,
1482            );
1483            if pc == 0 {
1484                return 0;
1485            }
1486        }
1487
1488        pc
1489    }
1490
1491    fn update_model(&mut self) {
1492        #[cfg(test)]
1493        if self.debug_count == 11 || self.debug_count == 12 {
1494            eprintln!(
1495                "[UPDATE pos={}] Before: min_context={} max_context={} order_fall={}",
1496                self.debug_count, self.min_context, self.max_context, self.order_fall
1497            );
1498        }
1499
1500        // Read the found state
1501        let fs_symbol = self.read_state_symbol(self.found_state as usize);
1502        let fs_freq = self.read_state_freq(self.found_state as usize);
1503        let fs_successor = self.read_state_successor(self.found_state as usize);
1504
1505        #[cfg(test)]
1506        if self.debug_count == 12 {
1507            eprintln!(
1508                "[UPDATE pos=12] found_state={} fs_sym='{}' fs_freq={} fs_successor={}",
1509                self.found_state, fs_symbol as char, fs_freq, fs_successor
1510            );
1511            let text_ptr = self.sub_alloc.get_text_ptr();
1512            eprintln!(
1513                "[UPDATE pos=12] text_ptr={}, fs_successor<=text_ptr: {}",
1514                text_ptr,
1515                (fs_successor as usize) <= text_ptr
1516            );
1517        }
1518
1519        // Update frequency in parent context (suffix) and find p
1520        let mut p: Option<usize> = None;
1521        let suffix = self.read_context_suffix(self.min_context as usize);
1522        if suffix != 0 && (fs_freq as u32) < MAX_FREQ / 4 {
1523            let num_stats = self.read_context_num_stats(suffix as usize);
1524            if num_stats != 1 {
1525                // Find the symbol in parent's stats
1526                let stats = self.read_context_stats(suffix as usize);
1527                let mut state_ptr = stats as usize;
1528                if self.read_state_symbol(state_ptr) != fs_symbol {
1529                    loop {
1530                        state_ptr += 6;
1531                        if self.read_state_symbol(state_ptr) == fs_symbol {
1532                            break;
1533                        }
1534                    }
1535                    // Swap with previous if freq >= prev freq (move to front)
1536                    let freq = self.read_state_freq(state_ptr);
1537                    let prev_freq = self.read_state_freq(state_ptr - 6);
1538                    if freq >= prev_freq {
1539                        // Swap states
1540                        let prev_ptr = state_ptr - 6;
1541                        let curr_sym = self.read_state_symbol(state_ptr);
1542                        let curr_freq = self.read_state_freq(state_ptr);
1543                        let curr_succ = self.read_state_successor(state_ptr);
1544                        let prev_sym = self.read_state_symbol(prev_ptr);
1545                        let prev_freq = self.read_state_freq(prev_ptr);
1546                        let prev_succ = self.read_state_successor(prev_ptr);
1547                        self.write_state(state_ptr, prev_sym, prev_freq, prev_succ);
1548                        self.write_state(prev_ptr, curr_sym, curr_freq, curr_succ);
1549                        state_ptr = prev_ptr;
1550                    }
1551                }
1552                p = Some(state_ptr);
1553                let freq = self.read_state_freq(state_ptr);
1554                if (freq as u32) < MAX_FREQ - 9 {
1555                    self.write_state_freq(state_ptr, freq + 2);
1556                    let sf = self.read_context_summ_freq(suffix as usize);
1557                    self.write_context_summ_freq(suffix as usize, sf + 2);
1558                }
1559            } else {
1560                // Binary context - OneState at suffix+2 (in union)
1561                let one_state_ptr = suffix as usize + 2;
1562                p = Some(one_state_ptr);
1563                let freq = self.read_state_freq(one_state_ptr);
1564                if freq < 32 {
1565                    self.write_state_freq(one_state_ptr, freq + 1);
1566                }
1567            }
1568        }
1569
1570        // If order_fall == 0, just create successors and return
1571        if self.order_fall == 0 {
1572            let new_ctx = self.create_successors(true, p);
1573            if new_ctx == 0 {
1574                self.restart_model();
1575                return;
1576            }
1577            self.write_state_successor(self.found_state as usize, new_ctx);
1578            self.min_context = new_ctx;
1579            self.max_context = new_ctx;
1580            return;
1581        }
1582
1583        // Write symbol to text memory
1584        let text_ptr = self.sub_alloc.get_text_ptr();
1585        let units_start = self.sub_alloc.get_units_start();
1586        if text_ptr >= units_start {
1587            self.restart_model();
1588            return;
1589        }
1590        self.sub_alloc.write_byte(text_ptr, fs_symbol);
1591        self.sub_alloc.advance_text_ptr();
1592
1593        let mut successor = self.sub_alloc.get_text_ptr() as u32;
1594
1595        // fs_successor_new tracks what we'll use for max/min context at the end
1596        let fs_successor_new: u32;
1597
1598        if fs_successor != 0 {
1599            let text_ptr = self.sub_alloc.get_text_ptr();
1600            if (fs_successor as usize) <= text_ptr {
1601                let new_succ = self.create_successors(false, p);
1602                if new_succ == 0 {
1603                    self.restart_model();
1604                    return;
1605                }
1606                self.write_state_successor(self.found_state as usize, new_succ);
1607                fs_successor_new = new_succ;
1608            } else {
1609                fs_successor_new = fs_successor;
1610            }
1611            self.order_fall -= 1;
1612            if self.order_fall == 0 {
1613                // Update successor to use fs.Successor instead of text pointer
1614                successor = fs_successor_new;
1615                if self.max_context != self.min_context {
1616                    // Undo text ptr advance
1617                    self.sub_alloc.retreat_text_ptr();
1618                }
1619                // NOTE: Don't return early! Continue to expansion loop.
1620                // This is the key fix - unrar doesn't return here either.
1621            }
1622        } else {
1623            // First time seeing this symbol in this context chain
1624            self.write_state_successor(self.found_state as usize, successor);
1625            // fs.Successor = MinContext (for the final assignment)
1626            fs_successor_new = self.min_context;
1627        }
1628
1629        // Add symbol to contexts from max_context to min_context
1630        let ns = self.read_context_num_stats(self.min_context as usize) as u32;
1631        let summ_freq = self.read_context_summ_freq(self.min_context as usize) as u32;
1632        let s0 = summ_freq
1633            .saturating_sub(ns)
1634            .saturating_sub(fs_freq as u32)
1635            .saturating_add(1);
1636
1637        let mut pc = self.max_context;
1638        while pc != self.min_context {
1639            let ns1 = self.read_context_num_stats(pc as usize);
1640
1641            if ns1 != 1 {
1642                // Multi-symbol context - expand if needed
1643                if (ns1 & 1) == 0 {
1644                    // Need to expand stats array
1645                    let old_stats = self.read_context_stats(pc as usize);
1646                    let new_stats = self
1647                        .sub_alloc
1648                        .expand_units(old_stats as usize, (ns1 >> 1) as usize);
1649                    if new_stats.is_none() {
1650                        self.restart_model();
1651                        return;
1652                    }
1653                    self.write_context_stats(pc as usize, new_stats.unwrap() as u32);
1654                }
1655
1656                // Update summ_freq based on symbol distribution
1657                let mut sf_inc = 0u16;
1658                if 2 * ns1 < ns as u16 {
1659                    sf_inc += 1;
1660                }
1661                let summ = self.read_context_summ_freq(pc as usize);
1662                if 4 * ns1 as u32 <= ns && summ <= 8 * ns1 {
1663                    sf_inc += 2;
1664                }
1665                self.write_context_summ_freq(pc as usize, summ + sf_inc);
1666            } else {
1667                // Binary context - convert to multi-symbol
1668                let new_stats = self.sub_alloc.alloc_units(1);
1669                if new_stats.is_none() {
1670                    self.restart_model();
1671                    return;
1672                }
1673                let new_stats = new_stats.unwrap();
1674
1675                // Copy OneState (at offset 2) to new stats
1676                let one_state_sym = self.read_state_symbol(pc as usize + 2);
1677                let one_state_freq = self.read_state_freq(pc as usize + 2);
1678                let one_state_succ = self.read_state_successor(pc as usize + 2);
1679                self.write_state(new_stats, one_state_sym, one_state_freq, one_state_succ);
1680
1681                self.write_context_stats(pc as usize, new_stats as u32);
1682
1683                // Update freq
1684                let freq = self.read_state_freq(new_stats);
1685                let new_freq = if (freq as u32) < MAX_FREQ / 4 - 1 {
1686                    freq * 2
1687                } else {
1688                    (MAX_FREQ - 4) as u8
1689                };
1690                self.write_state_freq(new_stats, new_freq);
1691
1692                // Set summ_freq - use self.init_esc (dynamic, set during binary escape)
1693                let init_esc_extra = if ns > 3 { 1 } else { 0 };
1694                let new_summ = new_freq as u16 + self.init_esc as u16 + init_esc_extra as u16;
1695                self.write_context_summ_freq(pc as usize, new_summ);
1696                #[cfg(test)]
1697                if pc == 15728580 {
1698                    eprintln!("[UPDATE_MODEL pos={}] context {} promoted: new_freq={} init_esc={} init_esc_extra={} → SummFreq={}", 
1699                             self.debug_count, pc, new_freq, self.init_esc, init_esc_extra, new_summ);
1700                }
1701            }
1702
1703            // Calculate new symbol's frequency
1704            let summ = self.read_context_summ_freq(pc as usize) as u32;
1705            let cf = 2 * fs_freq as u32 * (summ + 6);
1706            let sf = s0 + summ;
1707
1708            let sym_freq: u8;
1709            if cf < 6 * sf {
1710                sym_freq = 1 + (cf > sf) as u8 + (cf >= 4 * sf) as u8;
1711                let summ = self.read_context_summ_freq(pc as usize);
1712                self.write_context_summ_freq(pc as usize, summ + 3);
1713                #[cfg(test)]
1714                if pc == 15728580 {
1715                    eprintln!(
1716                        "[UPDATE_MODEL pos={}] context {} SummFreq: {} → {} (branch1, sym_freq={})",
1717                        self.debug_count,
1718                        pc,
1719                        summ,
1720                        summ + 3,
1721                        sym_freq
1722                    );
1723                }
1724            } else {
1725                sym_freq = 4 + (cf >= 9 * sf) as u8 + (cf >= 12 * sf) as u8 + (cf >= 15 * sf) as u8;
1726                let summ = self.read_context_summ_freq(pc as usize);
1727                self.write_context_summ_freq(pc as usize, summ + sym_freq as u16);
1728                #[cfg(test)]
1729                if pc == 15728580 {
1730                    eprintln!(
1731                        "[UPDATE_MODEL pos={}] context {} SummFreq: {} → {} (branch2, sym_freq={})",
1732                        self.debug_count,
1733                        pc,
1734                        summ,
1735                        summ + sym_freq as u16,
1736                        sym_freq
1737                    );
1738                }
1739            }
1740
1741            // Add new symbol at end of stats
1742            let stats = self.read_context_stats(pc as usize);
1743            let new_state_ptr = stats as usize + (ns1 as usize) * 6;
1744
1745            #[cfg(test)]
1746            if ns1 >= 256 {
1747                eprintln!(
1748                    "[UPDATE] ERROR: Adding state at ns1={} to context {} - exceeds 256!",
1749                    ns1, pc
1750                );
1751            }
1752
1753            self.write_state(new_state_ptr, fs_symbol, sym_freq, successor);
1754
1755            // Increment NumStats
1756            self.write_context_num_stats(pc as usize, ns1 + 1);
1757
1758            // Move to suffix
1759            pc = self.read_context_suffix(pc as usize);
1760        }
1761
1762        // Update context pointers to fs.Successor
1763        self.max_context = fs_successor_new;
1764        self.min_context = fs_successor_new;
1765
1766        #[cfg(test)]
1767        if self.debug_count == 11 || self.debug_count == 12 {
1768            eprintln!(
1769                "[UPDATE pos={}] After: min_context={} max_context={}",
1770                self.debug_count, self.min_context, self.max_context
1771            );
1772        }
1773    }
1774
1775    /// Clear the character mask.
1776    fn clear_mask(&mut self) {
1777        // Increment esc_count instead of zeroing array - much faster
1778        // Skip 0 since that's the uninitialized state
1779        self.esc_count = self.esc_count.wrapping_add(1);
1780        if self.esc_count == 0 {
1781            // Wrapped around - must zero the array and restart at 1
1782            self.esc_count = 1;
1783            self.char_mask = [0; 256];
1784        }
1785    }
1786
1787    // Helper methods for reading/writing context and state structures
1788
1789    #[inline]
1790    fn read_context_num_stats(&self, offset: usize) -> u16 {
1791        self.sub_alloc.read_u16(offset)
1792    }
1793
1794    #[inline]
1795    fn write_context_num_stats(&mut self, offset: usize, val: u16) {
1796        self.sub_alloc.write_u16(offset, val);
1797    }
1798
1799    #[inline]
1800    fn read_context_summ_freq(&self, offset: usize) -> u16 {
1801        self.sub_alloc.read_u16(offset + 2)
1802    }
1803
1804    #[inline]
1805    fn write_context_summ_freq(&mut self, offset: usize, val: u16) {
1806        self.sub_alloc.write_u16(offset + 2, val);
1807    }
1808
1809    #[inline]
1810    fn read_context_stats(&self, offset: usize) -> u32 {
1811        self.sub_alloc.read_u32(offset + 4)
1812    }
1813
1814    #[inline]
1815    fn write_context_stats(&mut self, offset: usize, val: u32) {
1816        self.sub_alloc.write_u32(offset + 4, val);
1817    }
1818
1819    #[inline]
1820    fn read_context_suffix(&self, offset: usize) -> u32 {
1821        self.sub_alloc.read_u32(offset + 8)
1822    }
1823
1824    #[inline]
1825    fn write_context_suffix(&mut self, offset: usize, val: u32) {
1826        self.sub_alloc.write_u32(offset + 8, val);
1827    }
1828
1829    #[inline]
1830    fn read_context_one_state(&self, offset: usize) -> State {
1831        // OneState is at offset 2 (in the union with SummFreq+Stats)
1832        // Layout: Symbol(1) + Freq(1) + Successor(4) = 6 bytes at offset 2-7
1833        State {
1834            symbol: self.sub_alloc.read_byte(offset + 2),
1835            freq: self.sub_alloc.read_byte(offset + 3),
1836            successor: self.sub_alloc.read_u32(offset + 4),
1837        }
1838    }
1839
1840    #[inline]
1841    fn write_context_one_state_freq(&mut self, offset: usize, freq: u8) {
1842        // OneState.Freq is at offset+3 (Symbol at +2, Freq at +3)
1843        self.sub_alloc.write_byte(offset + 3, freq);
1844    }
1845
1846    #[inline]
1847    fn read_state_symbol(&self, offset: usize) -> u8 {
1848        self.sub_alloc.read_byte(offset)
1849    }
1850
1851    #[inline]
1852    fn read_state_freq(&self, offset: usize) -> u8 {
1853        self.sub_alloc.read_byte(offset + 1)
1854    }
1855
1856    #[inline]
1857    fn write_state_freq(&mut self, offset: usize, freq: u8) {
1858        self.sub_alloc.write_byte(offset + 1, freq);
1859    }
1860
1861    #[inline]
1862    fn read_state_successor(&self, offset: usize) -> u32 {
1863        self.sub_alloc.read_u32(offset + 2)
1864    }
1865
1866    #[inline]
1867    fn write_state_successor(&mut self, offset: usize, successor: u32) {
1868        self.sub_alloc.write_u32(offset + 2, successor);
1869    }
1870
1871    #[inline]
1872    fn write_state(&mut self, offset: usize, symbol: u8, freq: u8, successor: u32) {
1873        self.sub_alloc.write_byte(offset, symbol);
1874        self.sub_alloc.write_byte(offset + 1, freq);
1875        self.sub_alloc.write_u32(offset + 2, successor);
1876    }
1877}
1878
1879impl Default for PpmModel {
1880    fn default() -> Self {
1881        Self::new()
1882    }
1883}