1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 // IP's ACM-stream unpacker.
28 0, 1, 2, 4, 5, 6, 8, 9, 10, 16, 17, 18, 20, 21, 22, 24, 25, 26, 32, 33,
29 34, 36, 37, 38, 40, 41, 42
31 //Eng: in base-4 system it is:
32 //Rus: â ÷åòâåðè÷íîé ñèñòåìå ýòî áóäåò:
33 // 000 001 002 010 011 012 020 021 022
34 // 100 101 102 110 111 112 120 121 122
35 // 200 201 202 210 211 212 220 221 222
37 0, 1, 2, 3, 4, 8, 9, 10, 11, 12, 16, 17, 18, 19, 20, 24, 25, 26, 27, 28,
38 32, 33, 34, 35, 36, 64, 65, 66, 67, 68, 72, 73, 74, 75, 76, 80, 81, 82,
39 83, 84, 88, 89, 90, 91, 92, 96, 97, 98, 99, 100, 128, 129, 130, 131, 132,
40 136, 137, 138, 139, 140, 144, 145, 146, 147, 148, 152, 153, 154, 155, 156,
41 160, 161, 162, 163, 164, 192, 193, 194, 195, 196, 200, 201, 202, 203, 204,
42 208, 209, 210, 211, 212, 216, 217, 218, 219, 220, 224, 225, 226, 227, 228,
43 256, 257, 258, 259, 260, 264, 265, 266, 267, 268, 272, 273, 274, 275, 276,
44 280, 281, 282, 283, 284, 288, 289, 290, 291, 292
46 //Eng: in base-8 system:
47 //Rus: â âîñüìåðè÷íîé ñèñòåìå:
48 // 000 001 002 003 004 010 011 012 013 014 ...
49 // 100 101 102 103 104 ...
52 unsigned char Table3
[121] = {
53 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x10,
54 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x20, 0x21,
55 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x30, 0x31, 0x32,
56 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x40, 0x41, 0x42, 0x43,
57 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x50, 0x51, 0x52, 0x53, 0x54,
58 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65,
59 0x66, 0x67, 0x68, 0x69, 0x6A, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
60 0x77, 0x78, 0x79, 0x7A, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
61 0x88, 0x89, 0x8A, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
62 0x99, 0x9A, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
66 FillerProc Fillers
[32] = {
67 &CValueUnpacker::zero_fill
, & CValueUnpacker::return0
,
68 & CValueUnpacker::return0
, & CValueUnpacker::linear_fill
,
69 & CValueUnpacker::linear_fill
, & CValueUnpacker::linear_fill
,
70 & CValueUnpacker::linear_fill
, & CValueUnpacker::linear_fill
,
71 & CValueUnpacker::linear_fill
, & CValueUnpacker::linear_fill
,
72 & CValueUnpacker::linear_fill
, & CValueUnpacker::linear_fill
,
73 & CValueUnpacker::linear_fill
, & CValueUnpacker::linear_fill
,
74 & CValueUnpacker::linear_fill
, & CValueUnpacker::linear_fill
,
75 & CValueUnpacker::linear_fill
, & CValueUnpacker::k1_3bits
,
76 & CValueUnpacker::k1_2bits
, & CValueUnpacker::t1_5bits
,
77 & CValueUnpacker::k2_4bits
, & CValueUnpacker::k2_3bits
,
78 & CValueUnpacker::t2_7bits
, & CValueUnpacker::k3_5bits
,
79 & CValueUnpacker::k3_4bits
, & CValueUnpacker::return0
,
80 & CValueUnpacker::k4_5bits
, & CValueUnpacker::k4_4bits
,
81 & CValueUnpacker::return0
, & CValueUnpacker::t3_7bits
,
82 & CValueUnpacker::return0
, & CValueUnpacker::return0
85 void CValueUnpacker::prepare_bits(int bits
)
87 while (bits
> avail_bits
) {
88 unsigned char one_byte
;
89 //our stream read returns -1 instead of 0 on failure
90 //comparing with 1 will solve annoying interface changes
91 if (stream
->Read( &one_byte
, 1 )!=1) {
94 next_bits
|= ( ( unsigned int ) one_byte
<< avail_bits
);
98 int CValueUnpacker::get_bits(int bits
)
100 prepare_bits( bits
);
106 int CValueUnpacker::init_unpacker()
108 //using malloc, supposed to be faster
109 amp_buffer
=(short *) malloc(sizeof(short)*0x10000);
113 buff_middle
= amp_buffer
+ 0x8000;
116 int CValueUnpacker::get_one_block(int* block
)
119 int pwr
= get_bits( 4 ) & 0xF, val
= get_bits( 16 ) & 0xFFFF,
120 count
= 1 << pwr
, v
= 0;
122 for (i
= 0; i
< count
; i
++) {
123 buff_middle
[i
] = ( short ) v
;
127 for (i
= 0; i
< count
; i
++) {
128 buff_middle
[-i
- 1] = ( short ) v
;
132 for (int pass
= 0; pass
< sb_size
; pass
++) {
133 int ind
= get_bits( 5 ) & 0x1F;
134 if (!( ( this->*Fillers
[ind
] ) ( pass
, ind
) )) {
142 // Filling functions:
143 // int CValueUnpacker::FillerProc (int pass, int ind)
144 int CValueUnpacker::return0(int /*pass*/, int /*ind*/)
148 int CValueUnpacker::zero_fill(int pass
, int /*ind*/)
150 //Eng: used when the whole column #pass is zero-filled
151 //Rus: èñïîëüçóåòñÿ, êîãäà âåñü ñòîëáåö ñ íîìåðîì pass çàïîëíåí íóëÿìè
152 int* sb_ptr
= &block_ptr
[pass
], step
= sb_size
, i
= subblocks
;
156 } while (( --i
) != 0);
159 int CValueUnpacker::linear_fill(int pass
, int ind
)
161 int mask
= ( 1 << ind
) - 1;
162 short* lb_ptr
= buff_middle
+ ( ( -1l ) << ( ind
- 1 ) );
164 for (int i
= 0; i
< subblocks
; i
++)
165 block_ptr
[i
* sb_size
+ pass
] = lb_ptr
[get_bits( ind
) & mask
];
168 int CValueUnpacker::k1_3bits(int pass
, int /*ind*/)
170 //Eng: column with number pass is filled with zeros, and also +/-1, zeros are repeated frequently
171 //Rus: còîëáåö pass çàïîëíåí íóëÿìè, à òàêæå +/- 1, íî íóëè ÷àñòî èäóò ïîäðÿä
172 // efficiency (bits per value): 3-p0-2.5*p00, p00 - cnt of paired zeros, p0 - cnt of single zeros.
173 //Eng: it makes sense to use, when the freqnecy of paired zeros (p00) is greater than 2/3
174 //Rus: èìååò ñìûñë èñïîëüçîâàòü, êîãäà âåðîÿòíîñòü ïàðíûõ íóëåé (p00) áîëüøå 2/3
175 for (int i
= 0; i
< subblocks
; i
++) {
177 if (( next_bits
& 1 ) == 0) {
180 block_ptr
[i
* sb_size
+ pass
] = 0; if (( ++i
) == subblocks
)
182 block_ptr
[i
* sb_size
+ pass
] = 0;
183 } else if (( next_bits
& 2 ) == 0) {
186 block_ptr
[i
* sb_size
+ pass
] = 0;
188 block_ptr
[i
* sb_size
+ pass
] = ( next_bits
& 4 ) ?
197 int CValueUnpacker::k1_2bits(int pass
, int /*ind*/)
199 //Eng: column is filled with zero and +/-1
200 //Rus: còîëáåö pass çàïîëíåí íóëÿìè, à òàêæå +/- 1
201 // efficiency: 2-P0. P0 - cnt of any zero (P0 = p0 + p00)
202 //Eng: use it when P0 > 1/3
203 //Rus: èìååò ñìûñë èñïîëüçîâàòü, êîãäà âåðîÿòíîñòü íóëÿ áîëüøå 1/3
204 for (int i
= 0; i
< subblocks
; i
++) {
206 if (( next_bits
& 1 ) == 0) {
209 block_ptr
[i
* sb_size
+ pass
] = 0;
211 block_ptr
[i
* sb_size
+ pass
] = ( next_bits
& 2 ) ?
220 int CValueUnpacker::t1_5bits(int pass
, int /*ind*/)
222 //Eng: all the -1, 0, +1 triplets
223 //Rus: âñå êîìáèíàöèè òðîåê -1, 0, +1.
224 // efficiency: always 5/3 bits per value
225 // use it when P0 <= 1/3
226 for (int i
= 0; i
< subblocks
; i
++) {
227 int bits
= ( int ) ( get_bits( 5 ) & 0x1f );
228 bits
= ( int ) Table1
[bits
];
230 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-1 + ( bits
& 3 )];
231 if (( ++i
) == subblocks
)
234 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-1 + ( bits
& 3 )];
235 if (( ++i
) == subblocks
)
238 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-1 + bits
];
242 int CValueUnpacker::k2_4bits(int pass
, int /*ind*/)
244 // -2, -1, 0, 1, 2, and repeating zeros
245 // efficiency: 4-2*p0-3.5*p00, p00 - cnt of paired zeros, p0 - cnt of single zeros.
246 //Eng: makes sense to use when p00>2/3
247 //Rus: èìååò ñìûñë èñïîëüçîâàòü, êîãäà âåðîÿòíîñòü ïàðíûõ íóëåé (p00) áîëüøå 2/3
248 for (int i
= 0; i
< subblocks
; i
++) {
250 if (( next_bits
& 1 ) == 0) {
253 block_ptr
[i
* sb_size
+ pass
] = 0; if (( ++i
) == subblocks
)
255 block_ptr
[i
* sb_size
+ pass
] = 0;
256 } else if (( next_bits
& 2 ) == 0) {
259 block_ptr
[i
* sb_size
+ pass
] = 0;
261 block_ptr
[i
* sb_size
+ pass
] = ( next_bits
& 8 ) ?
262 ( ( next_bits
& 4 ) ? buff_middle
[2] : buff_middle
[1] ) :
263 ( ( next_bits
& 4 ) ? buff_middle
[-1] : buff_middle
[-2] );
270 int CValueUnpacker::k2_3bits(int pass
, int /*ind*/)
273 // efficiency: 3-2*P0, P0 - cnt of any zero (P0 = p0 + p00)
274 //Eng: use when P0>1/3
275 //Rus: èìååò ñìûñë èñïîëüçîâàòü, êîãäà âåðîÿòíîñòü íóëÿ áîëüøå 1/3
276 for (int i
= 0; i
< subblocks
; i
++) {
278 if (( next_bits
& 1 ) == 0) {
281 block_ptr
[i
* sb_size
+ pass
] = 0;
283 block_ptr
[i
* sb_size
+ pass
] = ( next_bits
& 4 ) ?
284 ( ( next_bits
& 2 ) ? buff_middle
[2] : buff_middle
[1] ) :
285 ( ( next_bits
& 2 ) ? buff_middle
[-1] : buff_middle
[-2] );
292 int CValueUnpacker::t2_7bits(int pass
, int /*ind*/)
294 //Eng: all the +/-2, +/-1, 0 triplets
295 // efficiency: always 7/3 bits per value
296 //Rus: âñå êîìáèíàöèè òðîåê -2, -1, 0, +1, 2.
297 // ýôôåêòèâíîñòü: 7/3 áèòà íà çíà÷åíèå - âñåãäà
298 // use it when p0 <= 1/3
299 for (int i
= 0; i
< subblocks
; i
++) {
300 int bits
= ( int ) ( get_bits( 7 ) & 0x7f );
301 short val
= Table2
[bits
];
303 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-2 + ( val
& 7 )];
304 if (( ++i
) == subblocks
)
307 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-2 + ( val
& 7 )];
308 if (( ++i
) == subblocks
)
311 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-2 + val
];
315 int CValueUnpacker::k3_5bits(int pass
, int /*ind*/)
317 // fills with values: -3, -2, -1, 0, 1, 2, 3, and double zeros
318 // efficiency: 5-3*p0-4.5*p00-p1, p00 - cnt of paired zeros, p0 - cnt of single zeros, p1 - cnt of +/- 1.
319 // can be used when frequency of paired zeros (p00) is greater than 2/3
320 for (int i
= 0; i
< subblocks
; i
++) {
322 if (( next_bits
& 1 ) == 0) {
325 block_ptr
[i
* sb_size
+ pass
] = 0; if (( ++i
) == subblocks
)
327 block_ptr
[i
* sb_size
+ pass
] = 0;
328 } else if (( next_bits
& 2 ) == 0) {
331 block_ptr
[i
* sb_size
+ pass
] = 0;
332 } else if (( next_bits
& 4 ) == 0) {
333 block_ptr
[i
* sb_size
+ pass
] = ( next_bits
& 8 ) ?
340 int val
= ( next_bits
& 0x18 ) >> 3;
344 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-3 + val
];
349 int CValueUnpacker::k3_4bits(int pass
, int /*ind*/)
351 // fills with values: -3, -2, -1, 0, 1, 2, 3.
352 // efficiency: 4-3*P0-p1, P0 - cnt of all zeros (P0 = p0 + p00), p1 - cnt of +/- 1.
353 for (int i
= 0; i
< subblocks
; i
++) {
355 if (( next_bits
& 1 ) == 0) {
358 block_ptr
[i
* sb_size
+ pass
] = 0;
359 } else if (( next_bits
& 2 ) == 0) {
361 block_ptr
[i
* sb_size
+ pass
] = ( next_bits
& 4 ) ?
366 int val
= ( next_bits
&0xC ) >> 2;
371 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-3 + val
];
376 int CValueUnpacker::k4_5bits(int pass
, int /*ind*/)
378 // fills with values: +/-4, +/-3, +/-2, +/-1, 0, and double zeros
379 // efficiency: 5-3*p0-4.5*p00, p00 - cnt of paired zeros, p0 - cnt of single zeros.
380 //Eng: makes sense to use when p00>2/3
381 //Rus: èìååò ñìûñë èñïîëüçîâàòü, êîãäà âåðîÿòíîñòü ïàðíûõ íóëåé (p00) áîëüøå 2/3
382 for (int i
= 0; i
< subblocks
; i
++) {
384 if (( next_bits
& 1 ) == 0) {
387 block_ptr
[i
* sb_size
+ pass
] = 0; if (( ++i
) == subblocks
)
389 block_ptr
[i
* sb_size
+ pass
] = 0;
390 } else if (( next_bits
& 2 ) == 0) {
393 block_ptr
[i
* sb_size
+ pass
] = 0;
395 int val
= ( next_bits
&0x1C ) >> 2;
398 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-4 + val
];
405 int CValueUnpacker::k4_4bits(int pass
, int /*ind*/)
407 // fills with values: +/-4, +/-3, +/-2, +/-1, 0, and double zeros
408 // efficiency: 4-3*P0, P0 - cnt of all zeros (both single and paired).
409 for (int i
= 0; i
< subblocks
; i
++) {
411 if (( next_bits
& 1 ) == 0) {
414 block_ptr
[i
* sb_size
+ pass
] = 0;
416 int val
= ( next_bits
&0xE ) >> 1;
421 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-4 + val
];
426 int CValueUnpacker::t3_7bits(int pass
, int /*ind*/)
428 //Eng: all the pairs of values from -5 to +5
429 // efficiency: 7/2 bits per value
430 //Rus: âñå êîìáèíàöèè ïàð îò -5 äî +5
431 // ýôôåêòèâíîñòü: 7/2 áèòà íà çíà÷åíèå - âñåãäà
432 for (int i
= 0; i
< subblocks
; i
++) {
433 int bits
= ( int ) ( get_bits( 7 ) & 0x7f );
434 unsigned char val
= Table3
[bits
];
436 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-5 + ( val
& 0xF )];
437 if (( ++i
) == subblocks
)
440 block_ptr
[i
* sb_size
+ pass
] = buff_middle
[-5 + val
];