package rdpgfx // RLGR1/RLGR3 (Run-Length Golomb-Rice) decoder for RFX codec. // Reference: MS-RDPRFX 3.1.8.1.7.3 RLGR1/RLGR3 Pseudocode // Matches FreeRDP's rfx_rlgr.c implementation. import "math/bits" const ( rlgrLSGR = 3 // shift count to convert kp to k rlgrKPMax = 80 // max value for kp or krp rlgrUPGR = 4 // increase in kp after a zero run in RL mode rlgrDNGR = 6 // decrease in kp after a nonzero symbol in RL mode rlgrUQGR = 3 // increase in kp after zero symbol in GR mode rlgrDQGR = 3 // decrease in kp after nonzero symbol in GR mode ) // rlgr1Decode decodes RLGR1-encoded data into signed 16-bit DWT coefficients. // If dst is non-nil and has sufficient capacity, it is reused (zeroed first). func rlgr1Decode(data []byte, outputSize int, dst []int16) []int16 { var output []int16 if cap(dst) >= outputSize { output = dst[:outputSize] clear(output) } else { output = make([]int16, outputSize) } br := &rlgrBitReader{data: data} cnt := 0 k := uint32(1) kp := uint32(1 << rlgrLSGR) // 8 kr := uint32(1) krp := uint32(1 << rlgrLSGR) // 8 for br.remaining() > 0 && cnt < outputSize { if k > 0 { // RL (Run-Length) Mode // Count leading 0-bits → number of full run groups vk := br.countLeadingZeros() // Each leading 0 adds (1 << k) to run, with k adapting upward run := uint32(0) for range vk { run += 1 << k kp += rlgrUPGR if kp > rlgrKPMax { kp = rlgrKPMax } k = kp >> rlgrLSGR } // Read k bits for run remainder if k > 0 { run += br.readBits(int(k)) } // Read sign bit for the non-zero value sign := br.readBits(1) // Decode non-zero magnitude using GR code with leading 1-bits vk2 := br.countLeadingOnes() // Read kr bits for code remainder code := uint32(0) if kr > 0 { code = br.readBits(int(kr)) } code |= vk2 << kr // Update kr/krp if vk2 == 0 { if krp > 2 { krp -= 2 } else { krp = 0 } kr = krp >> rlgrLSGR } else if vk2 != 1 { krp += vk2 if krp > rlgrKPMax { krp = rlgrKPMax } kr = krp >> rlgrLSGR } // Update k/kp (decrease after non-zero) if kp > rlgrDNGR { kp -= rlgrDNGR } else { kp = 0 } k = kp >> rlgrLSGR // Compute magnitude (code + 1, guaranteed non-zero) mag := int16(code + 1) if sign != 0 { mag = -mag } // Output: run zeros (already 0 from init), then the non-zero value runEnd := min(cnt+int(run), outputSize) cnt = runEnd if cnt < outputSize { output[cnt] = mag cnt++ } } else { // GR (Golomb-Rice) Mode // Count leading 1-bits vk := br.countLeadingOnes() // Read kr bits for code remainder code := uint32(0) if kr > 0 { code = br.readBits(int(kr)) } code |= vk << kr // Update kr/krp if vk == 0 { if krp > 2 { krp -= 2 } else { krp = 0 } kr = krp >> rlgrLSGR } else if vk != 1 { krp += vk if krp > rlgrKPMax { krp = rlgrKPMax } kr = krp >> rlgrLSGR } // RLGR1: sign embedded in code as code = 2*magnitude - sign if code == 0 { kp += rlgrUQGR if kp > rlgrKPMax { kp = rlgrKPMax } k = kp >> rlgrLSGR if cnt < outputSize { cnt++ // zero already set from init } } else { if kp > rlgrDQGR { kp -= rlgrDQGR } else { kp = 0 } k = kp >> rlgrLSGR var mag int16 if code&1 != 0 { // odd code → negative mag = -int16((code + 1) >> 1) } else { // even code → positive mag = int16(code >> 1) } if cnt < outputSize { output[cnt] = mag cnt++ } } } } return output } // rlgr3Decode decodes RLGR3-encoded data into signed 16-bit DWT coefficients. // RLGR3 differs from RLGR1 only in GR mode: it encodes/decodes TWO values // per GR code by encoding their sum then splitting. // Reference: MS-RDPRFX 3.1.8.1.7.3, FreeRDP rfx_rlgr.c func rlgr3Decode(data []byte, outputSize int, dst []int16) []int16 { var output []int16 if cap(dst) >= outputSize { output = dst[:outputSize] clear(output) } else { output = make([]int16, outputSize) } br := &rlgrBitReader{data: data} cnt := 0 k := uint32(1) kp := uint32(1 << rlgrLSGR) kr := uint32(1) krp := uint32(1 << rlgrLSGR) for br.remaining() > 0 && cnt < outputSize { if k > 0 { // RL Mode — identical to RLGR1 vk := br.countLeadingZeros() run := uint32(0) for range vk { run += 1 << k kp += rlgrUPGR if kp > rlgrKPMax { kp = rlgrKPMax } k = kp >> rlgrLSGR } if k > 0 { run += br.readBits(int(k)) } sign := br.readBits(1) vk2 := br.countLeadingOnes() code := uint32(0) if kr > 0 { code = br.readBits(int(kr)) } code |= vk2 << kr if vk2 == 0 { if krp > 2 { krp -= 2 } else { krp = 0 } kr = krp >> rlgrLSGR } else if vk2 != 1 { krp += vk2 if krp > rlgrKPMax { krp = rlgrKPMax } kr = krp >> rlgrLSGR } if kp > rlgrDNGR { kp -= rlgrDNGR } else { kp = 0 } k = kp >> rlgrLSGR mag := int16(code + 1) if sign != 0 { mag = -mag } runEnd3 := min(cnt+int(run), outputSize) cnt = runEnd3 if cnt < outputSize { output[cnt] = mag cnt++ } } else { // GR Mode — RLGR3 variant: decode TWO values from one GR code vk := br.countLeadingOnes() code := uint32(0) if kr > 0 { code = br.readBits(int(kr)) } code |= vk << kr if vk == 0 { if krp > 2 { krp -= 2 } else { krp = 0 } kr = krp >> rlgrLSGR } else if vk != 1 { krp += vk if krp > rlgrKPMax { krp = rlgrKPMax } kr = krp >> rlgrLSGR } // RLGR3: code = val1 + val2 (sum of two 2*mag-sign encoded values) // Read nIdx bits to split: nIdx = bit-length of code nIdx := uint32(0) if code != 0 { nIdx = uint32(bits.Len(uint(code))) } if br.remaining() < int(nIdx) { break } val1 := uint32(0) if nIdx > 0 { val1 = br.readBits(int(nIdx)) } val2 := code - val1 // Update k/kp based on both values if val1 != 0 && val2 != 0 { if kp > 2*rlgrDQGR { kp -= 2 * rlgrDQGR } else { kp = 0 } k = kp >> rlgrLSGR } else if val1 == 0 && val2 == 0 { kp += 2 * rlgrUQGR if kp > rlgrKPMax { kp = rlgrKPMax } k = kp >> rlgrLSGR } // Decode val1 as 2*mag-sign var mag1 int16 if val1&1 != 0 { mag1 = -int16((val1 + 1) >> 1) } else { mag1 = int16(val1 >> 1) } if cnt < outputSize { output[cnt] = mag1 cnt++ } // Decode val2 as 2*mag-sign var mag2 int16 if val2&1 != 0 { mag2 = -int16((val2 + 1) >> 1) } else { mag2 = int16(val2 >> 1) } if cnt < outputSize { output[cnt] = mag2 cnt++ } } } return output } // rlgrBitReader reads bits MSB-first from a byte slice. // // To minimise the per-bit cost on the RLGR hot path we keep a 64-bit // shift-register (`acc`, MSB-aligned with `bitsInAcc` valid bits at the top) // fed from `data[bytePos:]`. Reads up to 32 bits are a shift+mask, and runs // of identical bits are extracted with a single `bits.LeadingZeros64`. // // Invariant: bits consumed == bytePos*8 - bitsInAcc, so // // remaining() == (len(data)-bytePos)*8 + bitsInAcc // // which lets us drop the separate `total` and `read` counters entirely. type rlgrBitReader struct { data []byte bytePos int // next byte to load into acc acc uint64 // bits aligned to MSB bitsInAcc int // number of valid bits in acc (MSB-aligned) } func (br *rlgrBitReader) remaining() int { return (len(br.data)-br.bytePos)*8 + br.bitsInAcc } // fill loads bytes into the high end of acc until at least `need` bits are // buffered or the input is exhausted. need must be <= 56. func (br *rlgrBitReader) fill(need int) { for br.bitsInAcc < need && br.bytePos < len(br.data) { br.acc |= uint64(br.data[br.bytePos]) << uint(56-br.bitsInAcc) br.bytePos++ br.bitsInAcc += 8 } } // readBits extracts n bits (n > 0) from the accumulator. // Inlinable: when bitsInAcc is already sufficient the slow path is never // compiled into the call site; when fill is also inlinable the whole hot // path reduces to a shift + mask without a call frame. func (br *rlgrBitReader) readBits(n int) uint32 { if br.bitsInAcc < n { br.fill(n) if br.bitsInAcc < n { // EOF (bytePos == len(data)): zero bitsInAcc so remaining() // returns 0 and the decode loop terminates cleanly. br.bitsInAcc = 0 return 0 } } val := uint32(br.acc >> uint(64-n)) br.acc <<= uint(n) br.bitsInAcc -= n return val } // countLeadingZeros counts consecutive 0-bits and consumes the first 1-bit terminator. func (br *rlgrBitReader) countLeadingZeros() uint32 { count := uint32(0) for { if br.bitsInAcc < 56 && br.bytePos < len(br.data) { br.fill(56) } if br.bitsInAcc == 0 { return count } lz := bits.LeadingZeros64(br.acc) if lz >= br.bitsInAcc { count += uint32(br.bitsInAcc) br.acc = 0 br.bitsInAcc = 0 continue } count += uint32(lz) consume := lz + 1 br.acc <<= uint(consume) br.bitsInAcc -= consume return count } } // countLeadingOnes counts consecutive 1-bits and consumes the first 0-bit terminator. func (br *rlgrBitReader) countLeadingOnes() uint32 { count := uint32(0) for { if br.bitsInAcc < 56 && br.bytePos < len(br.data) { br.fill(56) } if br.bitsInAcc == 0 { return count } lo := bits.LeadingZeros64(^br.acc) if lo >= br.bitsInAcc { count += uint32(br.bitsInAcc) br.acc = 0 br.bitsInAcc = 0 continue } count += uint32(lo) consume := lo + 1 br.acc <<= uint(consume) br.bitsInAcc -= consume return count } } // DecodeRLGR3ForDebug exposes the RLGR3 decoder for offline verification. func DecodeRLGR3ForDebug(data []byte, outputSize int) []int16 { return rlgr3Decode(data, outputSize, nil) }