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