Skip to main content

lerc_reader/
lib.rs

1//! Pure-Rust LERC decoder.
2//!
3//! The public API distinguishes strict single-blob entry points from
4//! concatenated-band helpers:
5//!
6//! - inspect a single blob with [`get_blob_info`]
7//! - inspect only the first blob with [`inspect_first`]
8//! - pass an explicit shared or external mask with the `*_with_mask` single-blob variants
9//! - count concatenated blobs with [`get_band_count`]
10//! - decode a single blob with [`decode`]
11//! - decode only the first blob with [`decode_first`]
12//! - decode concatenated band sets with [`decode_band_set`]
13//! - seed a first-band external mask with the band-set `*_with_mask` variants
14//! - decode promoted `f64` buffers with [`decode_to_f64`]
15//! - decode only the first promoted `f64` blob with [`decode_first_to_f64`]
16//! - decode directly into `ndarray::ArrayD` with [`decode_ndarray`]
17
18mod bitstuff;
19mod huffman;
20mod io;
21mod lerc1;
22mod lerc2;
23mod pixel;
24mod types;
25
26#[cfg(test)]
27mod tests;
28
29use lerc_band_materialize::{BandLayout as MaterializeLayout, BandMaterializer, BandSink};
30use lerc_core::{BandLayout, BandSetInfo, BlobInfo, Error, Result};
31use ndarray::ArrayD;
32
33use crate::pixel::Sample;
34pub use crate::types::{
35    into_band_mask_ndarray, BandElement, BandElementKind, Decoded, DecodedBandSet, DecodedF64,
36    NdArrayElement,
37};
38
39macro_rules! dispatch_band_element {
40    ($target:ty, |$concrete:ident| $body:block) => {
41        match <$target as BandElement>::KIND {
42            BandElementKind::I8 => {
43                type $concrete = i8;
44                $body
45            }
46            BandElementKind::U8 => {
47                type $concrete = u8;
48                $body
49            }
50            BandElementKind::I16 => {
51                type $concrete = i16;
52                $body
53            }
54            BandElementKind::U16 => {
55                type $concrete = u16;
56                $body
57            }
58            BandElementKind::I32 => {
59                type $concrete = i32;
60                $body
61            }
62            BandElementKind::U32 => {
63                type $concrete = u32;
64                $body
65            }
66            BandElementKind::F32 => {
67                type $concrete = f32;
68                $body
69            }
70            BandElementKind::F64 => {
71                type $concrete = f64;
72                $body
73            }
74        }
75    };
76}
77
78pub fn inspect_first(blob: &[u8]) -> Result<BlobInfo> {
79    if lerc1::is_lerc1(blob) {
80        return lerc1::inspect(blob, None);
81    }
82    if lerc2::is_lerc2(blob) {
83        return lerc2::inspect(blob, None);
84    }
85    Err(Error::InvalidMagic)
86}
87
88pub fn inspect_first_with_mask(blob: &[u8], mask: &[u8]) -> Result<BlobInfo> {
89    let (info, _) = inspect_first_mask_with_info(blob, Some(mask), Some(mask))?;
90    Ok(info)
91}
92
93pub fn get_blob_info(blob: &[u8]) -> Result<BlobInfo> {
94    let info = inspect_first(blob)?;
95    ensure_single_blob_consumed(blob.len(), info.blob_size, "get_blob_info", "inspect_first")?;
96    Ok(info)
97}
98
99pub fn get_blob_info_with_mask(blob: &[u8], mask: &[u8]) -> Result<BlobInfo> {
100    let info = inspect_first_with_mask(blob, mask)?;
101    ensure_single_blob_consumed(
102        blob.len(),
103        info.blob_size,
104        "get_blob_info_with_mask",
105        "inspect_first_with_mask",
106    )?;
107    Ok(info)
108}
109
110pub fn get_band_count(blob: &[u8]) -> Result<usize> {
111    let mut offset = 0usize;
112    let mut count = 0usize;
113    let mut lerc1_mask: Option<Vec<u8>> = None;
114
115    while offset < blob.len() {
116        let slice = &blob[offset..];
117        let next_len = if lerc1::is_lerc1(slice) {
118            let parsed = lerc1::parse(slice, lerc1_mask.as_deref())?;
119            let next_len = parsed.info.blob_size;
120            lerc1_mask = parsed.mask;
121            next_len
122        } else if lerc2::is_lerc2(slice) {
123            let (parsed, _) = lerc2::parse(slice)?;
124            parsed.info.blob_size
125        } else {
126            return Err(Error::InvalidMagic);
127        };
128
129        offset = checked_next_offset(offset, next_len, blob.len())?;
130        count += 1;
131    }
132
133    Ok(count)
134}
135
136pub fn decode_first(blob: &[u8]) -> Result<Decoded> {
137    decode_first_with_masks(blob, None, None)
138}
139
140pub fn decode_first_with_mask(blob: &[u8], mask: &[u8]) -> Result<Decoded> {
141    decode_first_with_masks(blob, Some(mask), Some(mask))
142}
143
144pub fn decode(blob: &[u8]) -> Result<Decoded> {
145    let decoded = decode_first(blob)?;
146    ensure_single_blob_consumed(blob.len(), decoded.info.blob_size, "decode", "decode_first")?;
147    Ok(decoded)
148}
149
150pub fn decode_with_mask(blob: &[u8], mask: &[u8]) -> Result<Decoded> {
151    let decoded = decode_first_with_mask(blob, mask)?;
152    ensure_single_blob_consumed(
153        blob.len(),
154        decoded.info.blob_size,
155        "decode_with_mask",
156        "decode_first_with_mask",
157    )?;
158    Ok(decoded)
159}
160
161pub fn decode_band_set(blob: &[u8]) -> Result<DecodedBandSet> {
162    decode_band_set_with_lerc2_mask(blob, None)
163}
164
165pub fn decode_band_set_with_mask(blob: &[u8], mask: &[u8]) -> Result<DecodedBandSet> {
166    decode_band_set_with_lerc2_mask(blob, Some(mask))
167}
168
169pub fn decode_band_set_vec<T: BandElement>(
170    blob: &[u8],
171    layout: BandLayout,
172) -> Result<(BandSetInfo, Vec<T>)> {
173    decode_band_set_owned(blob, layout, None)
174}
175
176pub fn decode_band_set_vec_with_mask<T: BandElement>(
177    blob: &[u8],
178    mask: &[u8],
179    layout: BandLayout,
180) -> Result<(BandSetInfo, Vec<T>)> {
181    decode_band_set_owned(blob, layout, Some(mask))
182}
183
184pub fn decode_band_set_into<T: BandElement>(
185    blob: &[u8],
186    layout: BandLayout,
187    out: &mut [T],
188) -> Result<BandSetInfo> {
189    decode_band_set_into_direct(blob, layout, None, out)
190}
191
192pub fn decode_band_set_into_with_mask<T: BandElement>(
193    blob: &[u8],
194    mask: &[u8],
195    layout: BandLayout,
196    out: &mut [T],
197) -> Result<BandSetInfo> {
198    decode_band_set_into_direct(blob, layout, Some(mask), out)
199}
200
201pub fn decode_band_set_ndarray<T: BandElement>(blob: &[u8]) -> Result<ArrayD<T>> {
202    decode_band_set_ndarray_with_layout(blob, BandLayout::Interleaved)
203}
204
205pub fn decode_band_set_ndarray_with_mask<T: BandElement>(
206    blob: &[u8],
207    mask: &[u8],
208) -> Result<ArrayD<T>> {
209    decode_band_set_ndarray_with_layout_and_mask(blob, BandLayout::Interleaved, mask)
210}
211
212pub fn decode_band_set_ndarray_with_layout<T: BandElement>(
213    blob: &[u8],
214    layout: BandLayout,
215) -> Result<ArrayD<T>> {
216    decode_band_set_ndarray_with_layout_impl(blob, layout, None)
217}
218
219pub fn decode_band_set_ndarray_with_layout_and_mask<T: BandElement>(
220    blob: &[u8],
221    layout: BandLayout,
222    mask: &[u8],
223) -> Result<ArrayD<T>> {
224    decode_band_set_ndarray_with_layout_impl(blob, layout, Some(mask))
225}
226
227pub fn decode_band_set_ndarray_f64(blob: &[u8]) -> Result<ArrayD<f64>> {
228    decode_band_set_ndarray_f64_with_optional_mask(blob, None)
229}
230
231pub fn decode_band_set_ndarray_f64_with_mask(blob: &[u8], mask: &[u8]) -> Result<ArrayD<f64>> {
232    decode_band_set_ndarray_f64_with_optional_mask(blob, Some(mask))
233}
234
235pub fn decode_band_mask_ndarray(blob: &[u8]) -> Result<Option<ArrayD<u8>>> {
236    let (info, band_masks) = inspect_band_masks(blob, None)?;
237    into_band_mask_ndarray(info, band_masks)
238}
239
240pub fn decode_band_mask_ndarray_with_mask(blob: &[u8], mask: &[u8]) -> Result<Option<ArrayD<u8>>> {
241    let (info, band_masks) = inspect_band_masks(blob, Some(mask))?;
242    into_band_mask_ndarray(info, band_masks)
243}
244
245fn decode_band_set_with_lerc2_mask(
246    blob: &[u8],
247    initial_lerc2_mask: Option<&[u8]>,
248) -> Result<DecodedBandSet> {
249    let mut offset = 0usize;
250    let mut bands = Vec::new();
251    let mut infos = Vec::new();
252    let mut band_masks = Vec::new();
253    let mut lerc1_mask: Option<Vec<u8>> = None;
254    let mut lerc2_mask = initial_lerc2_mask.map(|mask| mask.to_vec());
255
256    while offset < blob.len() {
257        let decoded = decode_first_with_masks(
258            &blob[offset..],
259            lerc1_mask.as_deref(),
260            lerc2_mask.as_deref(),
261        )?;
262
263        if lerc1::is_lerc1(&blob[offset..]) {
264            lerc1_mask = decoded.mask.clone();
265            lerc2_mask = None;
266        } else {
267            lerc2_mask = decoded.mask.clone();
268            lerc1_mask = None;
269        }
270
271        offset = checked_next_offset(offset, decoded.info.blob_size, blob.len())?;
272        infos.push(decoded.info);
273        bands.push(decoded.pixels);
274        band_masks.push(decoded.mask);
275    }
276
277    Ok(DecodedBandSet {
278        info: BandSetInfo::new(infos)?,
279        bands,
280        band_masks,
281    })
282}
283
284fn decode_band_set_ndarray_with_layout_impl<T: BandElement>(
285    blob: &[u8],
286    layout: BandLayout,
287    initial_lerc2_mask: Option<&[u8]>,
288) -> Result<ArrayD<T>> {
289    let (info, values) = decode_band_set_owned(blob, layout, initial_lerc2_mask)?;
290    let shape = info.ndarray_shape_for_layout(layout);
291    ArrayD::from_shape_vec(ndarray::IxDyn(&shape), values).map_err(|e| {
292        Error::InvalidBlob(format!(
293            "failed to build ndarray from decoded band set: {e}"
294        ))
295    })
296}
297
298fn decode_band_set_ndarray_f64_with_optional_mask(
299    blob: &[u8],
300    initial_lerc2_mask: Option<&[u8]>,
301) -> Result<ArrayD<f64>> {
302    let band_info = decode_band_set_to_f64_info(blob, BandLayout::Interleaved, initial_lerc2_mask)?;
303    let shape = band_info
304        .0
305        .ndarray_shape_for_layout(BandLayout::Interleaved);
306    ArrayD::from_shape_vec(ndarray::IxDyn(&shape), band_info.1).map_err(|e| {
307        Error::InvalidBlob(format!(
308            "failed to build ndarray from decoded band set: {e}"
309        ))
310    })
311}
312
313pub fn decode_to_f64(blob: &[u8]) -> Result<DecodedF64> {
314    let decoded = decode_first_to_f64(blob)?;
315    ensure_single_blob_consumed(
316        blob.len(),
317        decoded.info.blob_size,
318        "decode_to_f64",
319        "decode_first_to_f64",
320    )?;
321    Ok(decoded)
322}
323
324pub fn decode_to_f64_with_mask(blob: &[u8], mask: &[u8]) -> Result<DecodedF64> {
325    let decoded = decode_first_to_f64_with_mask(blob, mask)?;
326    ensure_single_blob_consumed(
327        blob.len(),
328        decoded.info.blob_size,
329        "decode_to_f64_with_mask",
330        "decode_first_to_f64_with_mask",
331    )?;
332    Ok(decoded)
333}
334
335pub fn decode_first_to_f64(blob: &[u8]) -> Result<DecodedF64> {
336    decode_first_f64(blob)
337}
338
339pub fn decode_first_to_f64_with_mask(blob: &[u8], mask: &[u8]) -> Result<DecodedF64> {
340    decode_first_f64_with_masks(blob, Some(mask), Some(mask))
341}
342
343pub fn decode_ndarray<T: NdArrayElement>(blob: &[u8]) -> Result<ArrayD<T>> {
344    decode(blob)?.into_ndarray()
345}
346
347pub fn decode_ndarray_with_mask<T: NdArrayElement>(blob: &[u8], mask: &[u8]) -> Result<ArrayD<T>> {
348    decode_with_mask(blob, mask)?.into_ndarray()
349}
350
351pub fn decode_ndarray_f64(blob: &[u8]) -> Result<ArrayD<f64>> {
352    decode_to_f64(blob)?.into_ndarray()
353}
354
355pub fn decode_ndarray_f64_with_mask(blob: &[u8], mask: &[u8]) -> Result<ArrayD<f64>> {
356    decode_to_f64_with_mask(blob, mask)?.into_ndarray()
357}
358
359pub fn decode_mask_ndarray(blob: &[u8]) -> Result<Option<ArrayD<u8>>> {
360    let (info, mask) = inspect_first_mask_with_info(blob, None, None)?;
361    ensure_single_blob_consumed(
362        blob.len(),
363        info.blob_size,
364        "decode_mask_ndarray",
365        "inspect_first",
366    )?;
367    mask_to_ndarray(&info, mask)
368}
369
370pub fn decode_mask_ndarray_with_mask(blob: &[u8], mask: &[u8]) -> Result<Option<ArrayD<u8>>> {
371    let (info, decoded_mask) = inspect_first_mask_with_info(blob, Some(mask), Some(mask))?;
372    ensure_single_blob_consumed(
373        blob.len(),
374        info.blob_size,
375        "decode_mask_ndarray_with_mask",
376        "inspect_first_with_mask",
377    )?;
378    mask_to_ndarray(&info, decoded_mask)
379}
380
381fn decode_first_with_masks(
382    blob: &[u8],
383    lerc1_shared_mask: Option<&[u8]>,
384    lerc2_shared_mask: Option<&[u8]>,
385) -> Result<Decoded> {
386    if lerc1::is_lerc1(blob) {
387        return lerc1::decode(blob, lerc1_shared_mask);
388    }
389    if lerc2::is_lerc2(blob) {
390        return lerc2::decode(blob, lerc2_shared_mask);
391    }
392    Err(Error::InvalidMagic)
393}
394
395fn inspect_first_mask_with_info(
396    blob: &[u8],
397    lerc1_shared_mask: Option<&[u8]>,
398    lerc2_shared_mask: Option<&[u8]>,
399) -> Result<(BlobInfo, Option<Vec<u8>>)> {
400    if lerc1::is_lerc1(blob) {
401        return lerc1::inspect_mask(blob, lerc1_shared_mask);
402    }
403    if lerc2::is_lerc2(blob) {
404        return lerc2::inspect_with_mask(blob, lerc2_shared_mask);
405    }
406    Err(Error::InvalidMagic)
407}
408
409fn decode_first_f64(blob: &[u8]) -> Result<DecodedF64> {
410    decode_first_f64_with_masks(blob, None, None)
411}
412
413fn decode_first_f64_with_masks(
414    blob: &[u8],
415    lerc1_shared_mask: Option<&[u8]>,
416    lerc2_shared_mask: Option<&[u8]>,
417) -> Result<DecodedF64> {
418    if lerc1::is_lerc1(blob) {
419        return lerc1::decode_f64(blob, lerc1_shared_mask);
420    }
421    if lerc2::is_lerc2(blob) {
422        return lerc2::decode_f64(blob, lerc2_shared_mask);
423    }
424    Err(Error::InvalidMagic)
425}
426
427fn decode_band_set_owned<T: BandElement>(
428    blob: &[u8],
429    layout: BandLayout,
430    initial_lerc2_mask: Option<&[u8]>,
431) -> Result<(BandSetInfo, Vec<T>)> {
432    let band_info = scan_band_infos(blob)?;
433    decode_band_set_owned_direct(blob, layout, band_info, initial_lerc2_mask)
434}
435
436fn decode_band_set_into_direct<T: BandElement>(
437    blob: &[u8],
438    layout: BandLayout,
439    initial_lerc2_mask: Option<&[u8]>,
440    out: &mut [T],
441) -> Result<BandSetInfo> {
442    dispatch_band_element!(T, |Concrete| {
443        decode_band_set_into_impl::<Concrete>(
444            blob,
445            layout,
446            initial_lerc2_mask,
447            cast_slice_mut::<T, Concrete>(out),
448        )
449    })
450}
451
452fn decode_band_set_owned_direct<T: BandElement>(
453    blob: &[u8],
454    layout: BandLayout,
455    band_info: BandSetInfo,
456    initial_lerc2_mask: Option<&[u8]>,
457) -> Result<(BandSetInfo, Vec<T>)> {
458    dispatch_band_element!(T, |Concrete| {
459        decode_band_set_owned_direct_impl::<Concrete>(blob, layout, band_info, initial_lerc2_mask)
460            .map(|(info, values)| (info, cast_vec::<T, Concrete>(values)))
461    })
462}
463
464fn decode_band_set_into_impl<T: Sample + NdArrayElement>(
465    blob: &[u8],
466    layout: BandLayout,
467    initial_lerc2_mask: Option<&[u8]>,
468    out: &mut [T],
469) -> Result<BandSetInfo> {
470    let band_info = scan_band_infos(blob)?;
471    decode_band_set_into_impl_with_info(blob, layout, initial_lerc2_mask, &band_info, out)?;
472    Ok(band_info)
473}
474
475fn decode_band_set_into_impl_with_info<T: Sample + NdArrayElement>(
476    blob: &[u8],
477    layout: BandLayout,
478    initial_lerc2_mask: Option<&[u8]>,
479    band_info: &BandSetInfo,
480    out: &mut [T],
481) -> Result<()> {
482    let band_count = band_info.band_count();
483    let expected_len = band_info.value_count()?;
484    if out.len() != expected_len {
485        return Err(Error::InvalidBlob(format!(
486            "output slice length {} does not match decoded band set length {}",
487            out.len(),
488            expected_len
489        )));
490    }
491
492    let pixel_count = band_info.bands[0].pixel_count()?;
493    let depth = band_info.depth() as usize;
494    let mut offset = 0usize;
495    let mut band_index = 0usize;
496    let mut lerc1_mask: Option<Vec<u8>> = None;
497    let mut lerc2_mask = initial_lerc2_mask.map(|mask| mask.to_vec());
498
499    while offset < blob.len() {
500        let slice = &blob[offset..];
501        let is_lerc1 = lerc1::is_lerc1(slice);
502        let mut sink = BandSink::new(
503            out,
504            pixel_count,
505            depth,
506            band_index,
507            band_count,
508            materialize_layout(layout),
509        );
510        let (info, mask) = if is_lerc1 {
511            lerc1::decode_into(slice, lerc1_mask.as_deref(), &mut sink)?
512        } else if lerc2::is_lerc2(slice) {
513            lerc2::decode_into(slice, lerc2_mask.as_deref(), &mut sink)?
514        } else {
515            return Err(Error::InvalidMagic);
516        };
517
518        if is_lerc1 {
519            lerc1_mask = mask;
520            lerc2_mask = None;
521        } else {
522            lerc2_mask = mask;
523            lerc1_mask = None;
524        }
525
526        offset = checked_next_offset(offset, info.blob_size, blob.len())?;
527        band_index += 1;
528    }
529
530    Ok(())
531}
532
533fn decode_band_set_to_f64_info(
534    blob: &[u8],
535    layout: BandLayout,
536    initial_lerc2_mask: Option<&[u8]>,
537) -> Result<(BandSetInfo, Vec<f64>)> {
538    let band_info = scan_band_infos(blob)?;
539    decode_band_set_owned_direct_impl::<f64>(blob, layout, band_info, initial_lerc2_mask)
540}
541
542fn inspect_band_masks(
543    blob: &[u8],
544    initial_lerc2_mask: Option<&[u8]>,
545) -> Result<(BandSetInfo, Vec<Option<Vec<u8>>>)> {
546    let mut offset = 0usize;
547    let mut infos = Vec::new();
548    let mut band_masks = Vec::new();
549    let mut lerc1_mask: Option<Vec<u8>> = None;
550    let mut lerc2_mask = initial_lerc2_mask.map(|mask| mask.to_vec());
551
552    while offset < blob.len() {
553        let slice = &blob[offset..];
554        let is_lerc1 = lerc1::is_lerc1(slice);
555        let (info, mask) =
556            inspect_first_mask_with_info(slice, lerc1_mask.as_deref(), lerc2_mask.as_deref())?;
557
558        if is_lerc1 {
559            lerc1_mask = mask.clone();
560            lerc2_mask = None;
561        } else {
562            lerc2_mask = mask.clone();
563            lerc1_mask = None;
564        }
565
566        offset = checked_next_offset(offset, info.blob_size, blob.len())?;
567        infos.push(info);
568        band_masks.push(mask);
569    }
570
571    Ok((BandSetInfo::new(infos)?, band_masks))
572}
573
574fn scan_band_infos(blob: &[u8]) -> Result<BandSetInfo> {
575    let mut offset = 0usize;
576    let mut infos = Vec::new();
577    let mut lerc1_mask: Option<Vec<u8>> = None;
578
579    while offset < blob.len() {
580        let slice = &blob[offset..];
581        let (info, next_lerc1_mask) = if lerc1::is_lerc1(slice) {
582            let parsed = lerc1::parse(slice, lerc1_mask.as_deref())?;
583            let info = parsed.info;
584            let next_mask = parsed.mask;
585            (info, next_mask)
586        } else if lerc2::is_lerc2(slice) {
587            let (parsed, _) = lerc2::parse(slice)?;
588            (parsed.info, None)
589        } else {
590            return Err(Error::InvalidMagic);
591        };
592
593        offset = checked_next_offset(offset, info.blob_size, blob.len())?;
594        lerc1_mask = next_lerc1_mask;
595        infos.push(info);
596    }
597
598    BandSetInfo::new(infos)
599}
600
601fn ensure_single_blob_consumed(
602    blob_len: usize,
603    decoded_len: usize,
604    strict_api: &str,
605    permissive_api: &str,
606) -> Result<()> {
607    if blob_len == decoded_len {
608        return Ok(());
609    }
610    Err(Error::InvalidBlob(format!(
611        "{strict_api} only accepts a single LERC blob; found {} trailing bytes, use {permissive_api} for first-blob decoding or decode_band_set for concatenated rasters",
612        blob_len - decoded_len
613    )))
614}
615
616fn checked_next_offset(offset: usize, next_len: usize, total_len: usize) -> Result<usize> {
617    let next = offset
618        .checked_add(next_len)
619        .ok_or_else(|| Error::InvalidBlob("band offset overflow".into()))?;
620    if next <= offset || next > total_len {
621        return Err(Error::InvalidBlob(
622            "invalid concatenated band blob size".into(),
623        ));
624    }
625    Ok(next)
626}
627
628fn materialize_layout(layout: BandLayout) -> MaterializeLayout {
629    match layout {
630        BandLayout::Interleaved => MaterializeLayout::Interleaved,
631        BandLayout::Bsq => MaterializeLayout::Bsq,
632    }
633}
634
635fn materialize_error(err: lerc_band_materialize::MaterializeError) -> Error {
636    Error::InvalidBlob(err.to_string())
637}
638
639fn mask_to_ndarray(info: &BlobInfo, mask: Option<Vec<u8>>) -> Result<Option<ArrayD<u8>>> {
640    let shape = info.mask_ndarray_shape();
641    mask.map(|mask| {
642        ArrayD::from_shape_vec(ndarray::IxDyn(&shape), mask).map_err(|e| {
643            Error::InvalidBlob(format!("failed to build ndarray from decoded mask: {e}"))
644        })
645    })
646    .transpose()
647}
648
649fn decode_band_set_owned_direct_impl<T: Sample + NdArrayElement + Copy + Default>(
650    blob: &[u8],
651    layout: BandLayout,
652    band_info: BandSetInfo,
653    initial_lerc2_mask: Option<&[u8]>,
654) -> Result<(BandSetInfo, Vec<T>)> {
655    let expected_len = band_info.value_count()?;
656    if expected_len == 0 {
657        return Ok((band_info, Vec::new()));
658    }
659
660    let pixel_count = band_info.bands[0].pixel_count()?;
661    let depth = band_info.depth() as usize;
662    let band_count = band_info.band_count();
663    let mut materializer =
664        BandMaterializer::new(pixel_count, depth, band_count, materialize_layout(layout))
665            .map_err(materialize_error)?;
666    let mut offset = 0usize;
667    let mut band_index = 0usize;
668    let mut lerc1_mask: Option<Vec<u8>> = None;
669    let mut lerc2_mask = initial_lerc2_mask.map(|mask| mask.to_vec());
670
671    while offset < blob.len() {
672        let slice = &blob[offset..];
673        let is_lerc1 = lerc1::is_lerc1(slice);
674        let (info, mask) = {
675            let mut writer = materializer
676                .band_writer(band_index)
677                .map_err(materialize_error)?;
678            let decoded = if is_lerc1 {
679                lerc1::decode_into(slice, lerc1_mask.as_deref(), &mut writer)?
680            } else if lerc2::is_lerc2(slice) {
681                lerc2::decode_into(slice, lerc2_mask.as_deref(), &mut writer)?
682            } else {
683                return Err(Error::InvalidMagic);
684            };
685            writer.finish().map_err(materialize_error)?;
686            decoded
687        };
688
689        if is_lerc1 {
690            lerc1_mask = mask;
691            lerc2_mask = None;
692        } else {
693            lerc2_mask = mask;
694            lerc1_mask = None;
695        }
696
697        offset = checked_next_offset(offset, info.blob_size, blob.len())?;
698        band_index += 1;
699    }
700
701    Ok((band_info, materializer.finish().map_err(materialize_error)?))
702}
703
704fn cast_slice_mut<T, U>(slice: &mut [T]) -> &mut [U] {
705    unsafe { &mut *(slice as *mut [T] as *mut [U]) }
706}
707
708fn cast_vec<T, U>(values: Vec<U>) -> Vec<T> {
709    let len = values.len();
710    let cap = values.capacity();
711    let ptr = values.as_ptr() as *mut T;
712    std::mem::forget(values);
713    unsafe { Vec::from_raw_parts(ptr, len, cap) }
714}