1use crate::stream::ReadExt;
2use crate::tvpgl::*;
3use crate::*;
4use overf::wrapping;
5use std::io::SeekFrom;
6
7fn load_tlg5<T: Read + Seek>(src: &mut T) -> Result<Tlg> {
8 let colors = src.read_u8()?;
9 let width = src.read_u32()?;
10 let height = src.read_u32()?;
11 let blockheight = src.read_u32()?;
12 let color = match colors {
13 3 => TlgColorType::Bgr24,
14 4 => TlgColorType::Bgra32,
15 1 => TlgColorType::Grayscale8,
16 _ => return Err(TlgError::UnsupportedColorType(colors)),
17 };
18 let blockcount = ((height - 1) / blockheight) + 1;
19 src.seek_relative(blockcount as i64 * 4)?;
20 let stride = width as usize * colors as usize;
21 let mut output_data = vec![0u8; width as usize * height as usize * colors as usize];
22 let mut text = [0u8; 4096];
23 let mut inbuf = vec![0u8; blockheight as usize * width as usize + 10];
24 let mut outbuf = vec![vec![0u8; blockheight as usize * width as usize + 10]; colors as usize];
25 let mut prevline: Option<Vec<u8>> = None;
26 let mut r = 0;
27 for y_blk in (0..height).step_by(blockheight as usize) {
28 for c in 0..colors {
29 let mark = src.read_u8()?;
30 let size = src.read_u32()?;
31 if mark == 0 {
32 src.read_exact(&mut inbuf[..size as usize])?;
33 r = tlg5_decompress_slide(
34 &mut outbuf[c as usize],
35 &inbuf[..size as usize],
36 size as usize,
37 &mut text,
38 r,
39 );
40 } else {
41 src.read_exact(&mut outbuf[c as usize][..size as usize])?;
42 }
43 }
44 let y_lim = (y_blk + blockheight).min(height);
45 let mut outbufp = Vec::new();
46 for c in 0..colors {
47 outbufp.push(outbuf[c as usize].as_slice());
48 }
49 for y in y_blk..y_lim {
50 let current = &mut output_data[(y as usize * stride)..(y as usize * stride + stride)];
51 match prevline.take() {
52 Some(prev) => match color {
53 TlgColorType::Bgr24 => {
54 tlg5_compose_colors3(current, &prev, &outbufp, width);
55 outbufp[0] = &outbufp[0][width as usize..];
56 outbufp[1] = &outbufp[1][width as usize..];
57 outbufp[2] = &outbufp[2][width as usize..];
58 }
59 TlgColorType::Bgra32 => {
60 tlg5_compose_colors4(current, &prev, &outbufp, width);
61 outbufp[0] = &outbufp[0][width as usize..];
62 outbufp[1] = &outbufp[1][width as usize..];
63 outbufp[2] = &outbufp[2][width as usize..];
64 outbufp[3] = &outbufp[3][width as usize..];
65 }
66 TlgColorType::Grayscale8 => {
67 tlg5_compose_colors1(current, &prev, &outbufp, width);
68 outbufp[0] = &outbufp[0][width as usize..];
69 }
70 },
71 None => match color {
72 TlgColorType::Bgra32 => {
73 let mut current_pos = 0usize;
74 let mut pr = 0u8;
75 let mut pg = 0u8;
76 let mut pb = 0u8;
77 let mut pa = 0u8;
78 for x in 0..width as usize {
79 let mut b = outbufp[0][x];
80 let g = outbufp[1][x];
81 let mut r = outbufp[2][x];
82 let a = outbufp[3][x];
83 wrapping! {
84 b += g;
85 r += g;
86 pb += b;
87 pg += g;
88 pr += r;
89 pa += a;
90 }
91 current[current_pos] = pb;
92 current_pos += 1;
93 current[current_pos] = pg;
94 current_pos += 1;
95 current[current_pos] = pr;
96 current_pos += 1;
97 current[current_pos] = pa;
98 current_pos += 1;
99 }
100 outbufp[0] = &outbufp[0][width as usize..];
101 outbufp[1] = &outbufp[1][width as usize..];
102 outbufp[2] = &outbufp[2][width as usize..];
103 outbufp[3] = &outbufp[3][width as usize..];
104 }
105 TlgColorType::Bgr24 => {
106 let mut current_pos = 0usize;
107 let mut pr = 0u8;
108 let mut pg = 0u8;
109 let mut pb = 0u8;
110 for x in 0..width as usize {
111 let mut b = outbufp[0][x];
112 let g = outbufp[1][x];
113 let mut r = outbufp[2][x];
114 wrapping! {
115 b += g;
116 r += g;
117 pb += b;
118 pg += g;
119 pr += r;
120 }
121 current[current_pos] = pb;
122 current_pos += 1;
123 current[current_pos] = pg;
124 current_pos += 1;
125 current[current_pos] = pr;
126 current_pos += 1;
127 }
128 outbufp[0] = &outbufp[0][width as usize..];
129 outbufp[1] = &outbufp[1][width as usize..];
130 outbufp[2] = &outbufp[2][width as usize..];
131 }
132 TlgColorType::Grayscale8 => {
133 let mut current_pos = 0usize;
134 let mut pb = 0u8;
135 for x in 0..width as usize {
136 let b = outbufp[0][x];
137 wrapping! {
138 pb += b;
139 }
140 current[current_pos] = pb;
141 current_pos += 1;
142 }
143 outbufp[0] = &outbufp[0][width as usize..];
144 }
145 },
146 }
147 prevline = Some(current.to_vec());
148 }
149 }
150 Ok(Tlg {
151 tags: Default::default(),
152 version: 5,
153 width,
154 height,
155 color,
156 data: output_data,
157 })
158}
159
160fn load_tlg6<T: Read + Seek>(src: &mut T) -> Result<Tlg> {
161 let mut buf = [0u8; 4];
162 src.read_exact(&mut buf)?;
163 let colors = buf[0];
164 let color_type = match colors {
165 3 => TlgColorType::Bgr24,
166 4 => TlgColorType::Bgra32,
167 1 => TlgColorType::Grayscale8,
168 _ => return Err(TlgError::UnsupportedColorType(colors)),
169 };
170 if buf[1] != 0 {
171 return Err(TlgError::Str("Data flags must be 0".to_string()));
172 }
173 if buf[2] != 0 {
174 return Err(TlgError::Str("Color types must be 0".to_string()));
175 }
176 if buf[3] != 0 {
177 return Err(TlgError::Str(
178 "External golomb bit length table is not yet supported.".to_string(),
179 ));
180 }
181 let width = src.read_u32()?;
182 let height = src.read_u32()?;
183 let max_bit_length = src.read_u32()?;
184 let x_block_count = (width - 1) / (TLG6_W_BLOCK_SIZE as u32) + 1;
185 let y_block_count = (height - 1) / (TLG6_H_BLOCK_SIZE as u32) + 1;
186 let main_count = width / (TLG6_W_BLOCK_SIZE as u32);
187 let fraction = width - main_count * TLG6_W_BLOCK_SIZE as u32;
188 let mut bit_pool = vec![0u8; max_bit_length as usize / 8 + 5];
189 let mut pixelbuf = vec![0u32; width as usize * TLG6_H_BLOCK_SIZE + 1];
190 let mut filter_types = vec![0u8; x_block_count as usize * y_block_count as usize];
191 let mut lzss_text = [0u8; 4096];
192 let zero = if colors == 3 { 0xff_00_00_00u32 } else { 0 };
193 let zeroline = vec![zero; width as usize];
194 {
195 let mut p = 0;
196 let mut i = 0;
197 while i < 0x20u8 {
198 let mut j = 0;
199 while j < 0x10u8 {
200 lzss_text[p] = i;
201 p += 1;
202 lzss_text[p] = i;
203 p += 1;
204 lzss_text[p] = i;
205 p += 1;
206 lzss_text[p] = i;
207 p += 1;
208 lzss_text[p] = j;
209 p += 1;
210 lzss_text[p] = j;
211 p += 1;
212 lzss_text[p] = j;
213 p += 1;
214 lzss_text[p] = j;
215 p += 1;
216 j += 1;
217 }
218 i += 1;
219 }
220 }
221 {
222 let inbuf_size = src.read_u32()? as usize;
223 let mut inbuf = vec![0u8; inbuf_size];
224 src.read_exact(&mut inbuf)?;
225 tlg5_decompress_slide(&mut filter_types, &inbuf, inbuf_size, &mut lzss_text, 0);
226 }
227 let mut prevline = zeroline;
228 let mut outbuf = vec![0u32; width as usize * height as usize];
229 for y in (0..height).step_by(TLG6_H_BLOCK_SIZE) {
230 let y_lim = (y + TLG6_H_BLOCK_SIZE as u32).min(height);
231 let pixel_count = (y_lim - y) as usize * width as usize;
232 for c in 0..colors {
233 let mut bit_length = src.read_u32()?;
234 let method = (bit_length >> 30) & 3;
235 bit_length &= 0x3fff_ffff;
236 let byte_length = (bit_length + 7) / 8;
237 if byte_length as usize >= bit_pool.len() {
238 return Err(TlgError::Str(
239 "Bit pool is too small for the given bit length".to_string(),
240 ));
241 }
242 src.read_exact(&mut bit_pool[..byte_length as usize])?;
243 match method {
244 0 => {
245 tlg6_decode_golomb_values(
246 &mut pixelbuf,
247 pixel_count,
248 &bit_pool,
249 c == 0 && colors != 1,
250 c,
251 )?;
252 }
253 _ => return Err(TlgError::UnsupportedCompressedMethod(method as u8)),
254 }
255 }
256 let ft = &filter_types[(y as usize / TLG6_H_BLOCK_SIZE) * x_block_count as usize..];
257 let skip_bytes = (y_lim - y) as usize * TLG6_W_BLOCK_SIZE;
258 for yy in y..y_lim {
259 let curline =
260 &mut outbuf[(yy as usize * width as usize)..(yy as usize + 1) * width as usize];
261 let dir = (yy & 1) ^ 1 != 0;
262 let oddskip = ((y_lim - yy - 1) as isize) - (yy - y) as isize;
263 if main_count != 0 {
264 let start = TLG6_W_BLOCK_SIZE.min(width as usize) * (yy - y) as usize;
265 tlg6_decode_line(
266 &prevline,
267 curline,
268 width,
269 0,
270 main_count as usize,
271 ft,
272 skip_bytes,
273 &pixelbuf,
274 start,
275 zero,
276 oddskip,
277 dir,
278 )?;
279 }
280 if main_count != x_block_count {
281 let ww = TLG6_W_BLOCK_SIZE.min(fraction as usize);
282 let start = ww * (yy - y) as usize;
283 tlg6_decode_line(
284 &prevline,
285 curline,
286 width,
287 main_count as usize,
288 x_block_count as usize,
289 ft,
290 skip_bytes,
291 &pixelbuf,
292 start,
293 zero,
294 oddskip,
295 dir,
296 )?;
297 }
298 prevline = curline.to_vec();
299 }
300 }
301 let mut data = Vec::with_capacity(outbuf.len() * colors as usize);
302 for p in outbuf {
303 let t = p.to_le_bytes();
304 let b = t[0];
305 let g = t[1];
306 let r = t[2];
307 let a = t[3];
308 match color_type {
309 TlgColorType::Bgr24 => {
310 data.extend_from_slice(&[b, g, r]);
311 }
312 TlgColorType::Bgra32 => {
313 data.extend_from_slice(&[b, g, r, a]);
314 }
315 TlgColorType::Grayscale8 => {
316 data.extend_from_slice(&[b]);
317 }
318 };
319 }
320 Ok(Tlg {
321 tags: Default::default(),
322 version: 6,
323 width,
324 height,
325 color: color_type,
326 data,
327 })
328}
329
330fn internal_load_tlg<T: Read + Seek>(src: &mut T) -> Result<Tlg> {
331 let mut mark = [0; 11];
332 src.read_exact(&mut mark)?;
333 if &mark == b"TLG5.0\x00raw\x1a" {
334 load_tlg5(src)
335 } else if &mark == b"TLG6.0\x00raw\x1a" {
336 load_tlg6(src)
337 } else {
338 Err(TlgError::InvalidFormat)
339 }
340}
341
342pub fn load_tlg<T: Read + Seek>(mut src: T) -> Result<Tlg> {
344 src.rewind()?;
345 let mut mark = [0; 11];
346 src.read_exact(&mut mark)?;
347 if &mark == b"TLG0.0\x00sds\x1a" {
348 let rawlen = src.read_u32()?;
349 let mut tlg = internal_load_tlg(&mut src)?;
350 let newlen = rawlen as u64 + 15;
351 src.seek(SeekFrom::Start(newlen))?;
352 let mut check = true;
353 while check {
354 let mut chunkname = [0; 4];
355 if src.read(&mut chunkname)? != 4 {
356 break;
357 }
358 let chunksize = src.read_u32()?;
359 if &chunkname == b"tags" {
360 let mut tag = vec![0; chunksize as usize];
361 src.read_exact(&mut tag)?;
362 let mut i = 0;
363 let len = tag.len();
364 while i < len {
365 let mut namelen = 0usize;
366 let mut c = tag[i];
367 let mut ok = true;
368 while c >= b'0' && c <= b'9' {
369 namelen = namelen * 10 + (c - b'0') as usize;
370 i += 1;
371 if i >= len {
372 ok = false;
373 break;
374 }
375 c = tag[i];
376 }
377 if !ok {
378 break;
379 }
380 if c != b':' {
381 check = false;
382 break;
383 }
384 i += 1;
385 let name = tag[i..i + namelen].to_vec();
386 i += namelen;
387 if i >= len {
388 break;
389 }
390 c = tag[i];
391 if c != b'=' {
392 check = false;
393 break;
394 }
395 i += 1;
396 let mut valuelen = 0usize;
397 c = tag[i];
398 ok = true;
399 while c >= b'0' && c <= b'9' {
400 valuelen = valuelen * 10 + (c - b'0') as usize;
401 i += 1;
402 if i >= len {
403 ok = false;
404 break;
405 }
406 c = tag[i];
407 }
408 if !ok {
409 break;
410 }
411 if c != b':' {
412 check = false;
413 break;
414 }
415 i += 1;
416 let value = tag[i..i + valuelen].to_vec();
417 i += valuelen;
418 if i >= len {
419 check = false;
420 break;
421 }
422 c = tag[i];
423 if c != b',' {
424 check = false;
425 break;
426 }
427 i += 1;
428 tlg.tags.insert(name, value);
429 }
430 } else {
431 src.seek_relative(chunksize as i64)?;
433 }
434 }
435 Ok(tlg)
436 } else {
437 src.rewind()?;
438 internal_load_tlg(&mut src)
439 }
440}