Skip to main content

otf_pixels_compress/
lzw.rs

1//! LZW, in both the GIF and TIFF dialects.
2//!
3//! # One implementation, two dialects
4//!
5//! GIF (§Appendix F) and TIFF (§Section 13) both use variable-width LZW with a
6//! clear code and an end code, and they differ in exactly two ways:
7//!
8//! - **Bit order.** GIF packs codes least-significant-bit first; TIFF packs
9//!   most-significant-bit first.
10//! - **When the code width grows.** GIF widens *after* the table reaches
11//!   `2^width` entries; TIFF widens one code *early*, a documented quirk of
12//!   the original implementation that every conforming decoder must match.
13//!
14//! Everything else — the table, the deferred-clear behaviour, the special
15//! first code — is identical. Two copies would be two chances to get the
16//! table logic wrong, with nothing testing that they agree, so this is one
17//! implementation with the differences named as [`BitOrder`].
18//!
19//! # The KwKwK case
20//!
21//! LZW's one genuinely subtle case: a code can refer to an entry that is only
22//! being defined by this very code. It happens whenever the input contains
23//! `KwKwK` — a sequence whose second occurrence begins before its first
24//! finished being added. A decoder that looks the code up naively finds
25//! nothing and either errors or reads uninitialized memory. It is handled
26//! explicitly below, and tested directly, because it is rare enough in small
27//! fixtures to escape casual testing and common enough in real images to break
28//! immediately in production.
29
30use crate::{Error, Result};
31
32/// Which end of a byte codes are packed from.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34pub enum BitOrder {
35    /// Least-significant bit first, as GIF packs codes.
36    LsbFirst,
37    /// Most-significant bit first, as TIFF packs codes.
38    ///
39    /// TIFF also widens the code one entry early; the two go together in
40    /// practice, so [`BitOrder`] selects both.
41    MsbFirst,
42}
43
44impl BitOrder {
45    /// Whether this dialect increases the code width one code early.
46    const fn early_change(self) -> bool {
47        matches!(self, Self::MsbFirst)
48    }
49}
50
51/// The largest code width either dialect permits.
52const MAX_WIDTH: u32 = 12;
53
54/// The table size at which a decoder moves to the next code width.
55///
56/// TIFF widens one entry early — a documented quirk of the original
57/// implementation that every conforming decoder must reproduce.
58const fn widen_at(width: u32, order: BitOrder) -> u16 {
59    let full = 1_u16 << width;
60    if order.early_change() {
61        full.saturating_sub(1)
62    } else {
63        full
64    }
65}
66/// The largest table any dialect can reach.
67const MAX_CODES: usize = 1 << MAX_WIDTH;
68
69/// Reads variable-width codes from a byte stream.
70#[derive(Debug)]
71struct CodeReader<'a> {
72    data: &'a [u8],
73    position: usize,
74    bits: u32,
75    count: u32,
76    order: BitOrder,
77}
78
79impl<'a> CodeReader<'a> {
80    const fn new(data: &'a [u8], order: BitOrder) -> Self {
81        Self {
82            data,
83            position: 0,
84            bits: 0,
85            count: 0,
86            order,
87        }
88    }
89
90    /// Read one code of `width` bits, or `None` at end of input.
91    fn next(&mut self, width: u32) -> Option<u16> {
92        while self.count < width {
93            let &byte = self.data.get(self.position)?;
94            self.position += 1;
95            match self.order {
96                BitOrder::LsbFirst => self.bits |= u32::from(byte) << self.count,
97                BitOrder::MsbFirst => self.bits = (self.bits << 8) | u32::from(byte),
98            }
99            self.count += 8;
100        }
101        let code = match self.order {
102            BitOrder::LsbFirst => {
103                let mask = (1_u32 << width) - 1;
104                let value = self.bits & mask;
105                self.bits >>= width;
106                self.count -= width;
107                value
108            }
109            BitOrder::MsbFirst => {
110                let shift = self.count - width;
111                let value = (self.bits >> shift) & ((1_u32 << width) - 1);
112                self.count -= width;
113                // Keep only the bits still unconsumed, so `bits` cannot grow
114                // past 32 on a long run of whole bytes.
115                self.bits &= (1_u32 << self.count).wrapping_sub(1);
116                value
117            }
118        };
119        Some(code as u16)
120    }
121}
122
123/// Writes variable-width codes to a byte stream.
124#[derive(Debug)]
125struct CodeWriter {
126    out: Vec<u8>,
127    bits: u32,
128    count: u32,
129    order: BitOrder,
130}
131
132impl CodeWriter {
133    const fn new(order: BitOrder) -> Self {
134        Self {
135            out: Vec::new(),
136            bits: 0,
137            count: 0,
138            order,
139        }
140    }
141
142    fn push(&mut self, code: u16, width: u32) {
143        match self.order {
144            BitOrder::LsbFirst => {
145                self.bits |= u32::from(code) << self.count;
146                self.count += width;
147                while self.count >= 8 {
148                    self.out.push((self.bits & 0xFF) as u8);
149                    self.bits >>= 8;
150                    self.count -= 8;
151                }
152            }
153            BitOrder::MsbFirst => {
154                self.bits = (self.bits << width) | u32::from(code);
155                self.count += width;
156                while self.count >= 8 {
157                    let shift = self.count - 8;
158                    self.out.push(((self.bits >> shift) & 0xFF) as u8);
159                    self.count -= 8;
160                    self.bits &= (1_u32 << self.count).wrapping_sub(1);
161                }
162            }
163        }
164    }
165
166    /// Flush any partial byte and return the stream.
167    fn finish(mut self) -> Vec<u8> {
168        if self.count > 0 {
169            let byte = match self.order {
170                BitOrder::LsbFirst => (self.bits & 0xFF) as u8,
171                // Pad with zeroes on the right, which is what both
172                // specifications' encoders emit.
173                BitOrder::MsbFirst => ((self.bits << (8 - self.count)) & 0xFF) as u8,
174            };
175            self.out.push(byte);
176        }
177        self.out
178    }
179}
180
181/// Decompresses an LZW stream.
182#[derive(Debug)]
183pub struct LzwDecoder {
184    order: BitOrder,
185    minimum_width: u32,
186}
187
188impl LzwDecoder {
189    /// A decoder for `order`, with `minimum_width` bits per initial code.
190    ///
191    /// GIF carries the minimum width in the image block; TIFF fixes it at 8.
192    ///
193    /// # Errors
194    ///
195    /// Returns [`Error`] if `minimum_width` is outside 2..=11. A width of 1 has
196    /// no room for both the clear and end codes, and 12 leaves none for the
197    /// table.
198    pub fn new(order: BitOrder, minimum_width: u32) -> Result<Self> {
199        if !(2..=11).contains(&minimum_width) {
200            return Err(Error::malformed(
201                "lzw",
202                format!("minimum code width {minimum_width} is outside 2..=11"),
203            ));
204        }
205        Ok(Self {
206            order,
207            minimum_width,
208        })
209    }
210
211    /// A decoder for GIF's dialect at `minimum_width`.
212    ///
213    /// # Errors
214    ///
215    /// As [`LzwDecoder::new`].
216    pub fn gif(minimum_width: u32) -> Result<Self> {
217        Self::new(BitOrder::LsbFirst, minimum_width)
218    }
219
220    /// A decoder for TIFF's dialect, whose minimum width is always 8.
221    #[must_use]
222    pub const fn tiff() -> Self {
223        Self {
224            order: BitOrder::MsbFirst,
225            minimum_width: 8,
226        }
227    }
228
229    /// Decompress `data`, refusing to produce more than `limit` bytes.
230    ///
231    /// The bound is what makes a decompression bomb a malformed-input error
232    /// rather than an allocation the caller has to survive: LZW expands by up
233    /// to 4096:1, so a caller states what it is prepared to accept.
234    ///
235    /// # Errors
236    ///
237    /// Returns [`Error`] for an invalid code, a stream that ends mid-symbol
238    /// without an end code, or output exceeding `limit`.
239    pub fn decode(&self, data: &[u8], limit: usize) -> Result<Vec<u8>> {
240        let clear = 1_u16 << self.minimum_width;
241        let end = clear + 1;
242        // Codes below this are literals. It is *not* 256: GIF derives the
243        // minimum width from the palette size, so a 4-colour image has
244        // literals 0..=3 and its table starts at code 6. Assuming 256 here
245        // decodes small-palette images as gibberish while leaving 8-bit ones
246        // perfect, which is exactly the bug that survives casual testing.
247        let literals = clear;
248
249        let mut reader = CodeReader::new(data, self.order);
250        let mut out: Vec<u8> = Vec::new();
251
252        // The table stores each entry as (prefix code, final byte), so an
253        // entry costs four bytes instead of a growing Vec. Expanding walks the
254        // prefix chain backwards, which is why `scratch` is reversed after.
255        let mut prefix = vec![0_u16; MAX_CODES];
256        let mut suffix = vec![0_u8; MAX_CODES];
257        let mut scratch: Vec<u8> = Vec::with_capacity(MAX_CODES);
258
259        let mut width = self.minimum_width + 1;
260        let mut next = end + 1;
261        let mut previous: Option<u16> = None;
262
263        // Running out of input without an end code is common enough in real
264        // files — many encoders omit it — that treating it as malformed would
265        // reject images every other decoder accepts. So the loop ends on
266        // either an end code or exhausted input, and both are success.
267        while let Some(code) = reader.next(width) {
268            if code == clear {
269                width = self.minimum_width + 1;
270                next = end + 1;
271                previous = None;
272                continue;
273            }
274            if code == end {
275                break;
276            }
277
278            // Expand this code into `scratch`, handling the KwKwK case where
279            // the code being read is the one this step is about to define.
280            scratch.clear();
281            let first = if code < next {
282                expand(code, literals, &prefix, &suffix, &mut scratch)?
283            } else if code == next {
284                let Some(previous_code) = previous else {
285                    return Err(Error::malformed(
286                        "lzw",
287                        "the first code after a clear cannot be a forward reference",
288                    ));
289                };
290                // KwKwK: the entry is `previous` followed by its own first
291                // byte, which is exactly what this branch reconstructs.
292                let first = expand(previous_code, literals, &prefix, &suffix, &mut scratch)?;
293                scratch.push(first);
294                first
295            } else {
296                return Err(Error::malformed(
297                    "lzw",
298                    format!("code {code} is beyond the {next} entries defined so far"),
299                ));
300            };
301
302            if out.len() + scratch.len() > limit {
303                return Err(Error::malformed(
304                    "lzw",
305                    format!("stream expands beyond the {limit} byte limit"),
306                ));
307            }
308            out.extend_from_slice(&scratch);
309
310            // Define the new entry: the previous string plus this one's first
311            // byte. Nothing is defined for the first code after a clear.
312            let room = (next as usize) < MAX_CODES;
313            if let Some(previous_code) = previous.filter(|_| room) {
314                if let (Some(p), Some(s)) =
315                    (prefix.get_mut(next as usize), suffix.get_mut(next as usize))
316                {
317                    *p = previous_code;
318                    *s = first;
319                }
320                next += 1;
321                if next >= widen_at(width, self.order) && width < MAX_WIDTH {
322                    width += 1;
323                }
324            }
325            previous = Some(code);
326        }
327
328        Ok(out)
329    }
330}
331
332/// Expand `code` into `out`, returning the first byte of the expansion.
333///
334/// `literals` is the number of single-byte codes, which is `2^minimum_width`
335/// and not necessarily 256. Walking the prefix chain backwards and reversing
336/// is why the length is bounded by the table size rather than by the output.
337fn expand(
338    code: u16,
339    literals: u16,
340    prefix: &[u16],
341    suffix: &[u8],
342    out: &mut Vec<u8>,
343) -> Result<u8> {
344    let start = out.len();
345    let mut current = code;
346    // A corrupt table could in principle form a cycle; the table size is a
347    // hard bound on any legitimate chain, so exceeding it is malformed input.
348    for _ in 0..=MAX_CODES {
349        if current < literals {
350            out.push(current as u8);
351            let Some(slice) = out.get_mut(start..) else {
352                break;
353            };
354            slice.reverse();
355            return Ok(current as u8);
356        }
357        let index = current as usize;
358        let (Some(&byte), Some(&parent)) = (suffix.get(index), prefix.get(index)) else {
359            return Err(Error::malformed("lzw", "code refers outside the table"));
360        };
361        out.push(byte);
362        current = parent;
363    }
364    Err(Error::malformed("lzw", "code chain does not terminate"))
365}
366
367/// Compresses to an LZW stream.
368#[derive(Debug)]
369pub struct LzwEncoder {
370    order: BitOrder,
371    minimum_width: u32,
372}
373
374impl LzwEncoder {
375    /// An encoder for `order`, with `minimum_width` bits per initial code.
376    ///
377    /// # Errors
378    ///
379    /// As [`LzwDecoder::new`].
380    pub fn new(order: BitOrder, minimum_width: u32) -> Result<Self> {
381        if !(2..=11).contains(&minimum_width) {
382            return Err(Error::malformed(
383                "lzw",
384                format!("minimum code width {minimum_width} is outside 2..=11"),
385            ));
386        }
387        Ok(Self {
388            order,
389            minimum_width,
390        })
391    }
392
393    /// An encoder for GIF's dialect at `minimum_width`.
394    ///
395    /// # Errors
396    ///
397    /// As [`LzwDecoder::new`].
398    pub fn gif(minimum_width: u32) -> Result<Self> {
399        Self::new(BitOrder::LsbFirst, minimum_width)
400    }
401
402    /// An encoder for TIFF's dialect.
403    #[must_use]
404    pub const fn tiff() -> Self {
405        Self {
406            order: BitOrder::MsbFirst,
407            minimum_width: 8,
408        }
409    }
410
411    /// Compress `data`.
412    ///
413    /// The output always begins with a clear code and ends with an end code,
414    /// which every conforming decoder accepts and some require.
415    #[must_use]
416    pub fn encode(&self, data: &[u8]) -> Vec<u8> {
417        let clear = 1_u16 << self.minimum_width;
418        let end = clear + 1;
419        let mut writer = CodeWriter::new(self.order);
420        let mut width = self.minimum_width + 1;
421
422        // The dictionary maps (prefix code, next byte) to a code. A flat map
423        // over `prefix * 256 + byte` would be 1 MB; a hash map of the pairs
424        // actually used is smaller and no slower at these sizes.
425        let mut table: std::collections::HashMap<(u16, u8), u16> = std::collections::HashMap::new();
426        let mut next = end + 1;
427
428        writer.push(clear, width);
429
430        let mut current: Option<u16> = None;
431        for &byte in data {
432            let combined = match current {
433                None => {
434                    current = Some(u16::from(byte));
435                    continue;
436                }
437                Some(code) => (code, byte),
438            };
439
440            if let Some(&found) = table.get(&combined) {
441                current = Some(found);
442                continue;
443            }
444
445            // Emit what we had, then define the extended string.
446            if let Some(code) = current {
447                writer.push(code, width);
448            }
449            if (next as usize) < MAX_CODES {
450                table.insert(combined, next);
451                next += 1;
452                // Strictly greater, where the decoder uses "at least". The
453                // asymmetry is not a choice: a decoder cannot define an entry
454                // until it has read the *following* code and knows its first
455                // byte, so its table is one behind the encoder's at the moment
456                // the width is decided. Using the same comparison on both
457                // sides makes an encoder and decoder agree with each other and
458                // disagree with the rest of the world — which passes every
459                // round-trip test and fails on the first real image.
460                if next > widen_at(width, self.order) && width < MAX_WIDTH {
461                    width += 1;
462                }
463            } else {
464                // The table is full: reset, exactly as the decoder will when
465                // it sees the clear code.
466                writer.push(clear, width);
467                table.clear();
468                width = self.minimum_width + 1;
469                next = end + 1;
470            }
471            current = Some(u16::from(byte));
472        }
473
474        if let Some(code) = current {
475            writer.push(code, width);
476        }
477        writer.push(end, width);
478        writer.finish()
479    }
480}
481
482#[cfg(test)]
483#[allow(
484    clippy::unwrap_used,
485    clippy::expect_used,
486    clippy::indexing_slicing,
487    clippy::panic,
488    reason = "tests operate on known-good values and assert shapes directly"
489)]
490mod tests {
491    use super::*;
492
493    fn round_trip(order: BitOrder, width: u32, data: &[u8]) {
494        let encoder = LzwEncoder::new(order, width).unwrap();
495        let decoder = LzwDecoder::new(order, width).unwrap();
496        let compressed = encoder.encode(data);
497        let back = decoder
498            .decode(&compressed, data.len() * 4 + 1024)
499            .unwrap_or_else(|e| panic!("{order:?} width {width}: {e}"));
500        assert_eq!(back, data, "{order:?} width {width} did not round-trip");
501    }
502
503    #[test]
504    fn both_dialects_round_trip_everything() {
505        let cases: Vec<Vec<u8>> = vec![
506            Vec::new(),
507            vec![0],
508            vec![1, 2, 3],
509            vec![7; 1000],
510            b"the quick brown fox jumps over the lazy dog. ".repeat(60),
511            (0..=255_u8).cycle().take(5000).collect(),
512            (0..4000).map(|i| ((i * 37) % 251) as u8).collect(),
513        ];
514        for order in [BitOrder::LsbFirst, BitOrder::MsbFirst] {
515            for data in &cases {
516                round_trip(order, 8, data);
517            }
518        }
519    }
520
521    #[test]
522    fn every_gif_minimum_width_round_trips() {
523        // GIF carries the minimum width per image, derived from the palette
524        // size, so every legal width has to work.
525        for width in 2..=8_u32 {
526            // The alphabet is 2^width, which is 256 at width 8 and therefore
527            // does not fit a u8 — compute it wider and narrow the result.
528            let alphabet = 1_u16 << width;
529            let data: Vec<u8> = (0..3000).map(|i| ((i * 7) % alphabet) as u8).collect();
530            round_trip(BitOrder::LsbFirst, width, &data);
531        }
532    }
533
534    #[test]
535    fn the_kwkwk_case_decodes_correctly() {
536        // The one genuinely subtle case in LZW: a code referring to the entry
537        // this very step defines. It needs input whose second occurrence of a
538        // run begins before the first finished being added — a long run of one
539        // byte is the shortest way to force it.
540        for order in [BitOrder::LsbFirst, BitOrder::MsbFirst] {
541            for length in [3_usize, 4, 5, 10, 100, 4000] {
542                let data = vec![0xAB_u8; length];
543                round_trip(order, 8, &data);
544            }
545            // The classic textbook case, spelled out.
546            round_trip(order, 8, b"ababababab");
547            round_trip(order, 8, b"aaaaaaaaaaaaaaaa");
548        }
549    }
550
551    #[test]
552    fn a_stream_longer_than_the_table_resets_cleanly() {
553        // Past 4096 entries the encoder must emit a clear and start again, and
554        // the decoder must follow it. Random-ish data fills the table fastest.
555        for order in [BitOrder::LsbFirst, BitOrder::MsbFirst] {
556            let data: Vec<u8> = (0..200_000_u32)
557                .map(|i| (i.wrapping_mul(2_654_435_761) >> 24) as u8)
558                .collect();
559            round_trip(order, 8, &data);
560        }
561    }
562
563    #[test]
564    fn a_forward_reference_is_an_error_not_a_panic() {
565        // A code beyond the table is the classic corrupt-LZW case, and the
566        // one that reads uninitialized memory in a careless implementation.
567        let decoder = LzwDecoder::gif(8).unwrap();
568        // 0x100 is clear at width 9; 0x1FF is far beyond anything defined.
569        let mut writer = CodeWriter::new(BitOrder::LsbFirst);
570        writer.push(0x100, 9);
571        writer.push(0x1FF, 9);
572        let stream = writer.finish();
573        let error = decoder.decode(&stream, 1 << 20).unwrap_err();
574        assert!(error.detail().contains("beyond"), "{error}");
575    }
576
577    #[test]
578    fn arbitrary_bytes_never_panic() {
579        // Every LZW stream a codec sees is attacker-controlled.
580        let mut seed = 0x1234_5678_u32;
581        for order in [BitOrder::LsbFirst, BitOrder::MsbFirst] {
582            for width in [2_u32, 8, 11] {
583                let decoder = LzwDecoder::new(order, width).unwrap();
584                for _ in 0..500 {
585                    let len = (seed % 200) as usize + 1;
586                    let data: Vec<u8> = (0..len)
587                        .map(|_| {
588                            seed = seed.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
589                            (seed >> 16) as u8
590                        })
591                        .collect();
592                    let _ = decoder.decode(&data, 1 << 16);
593                }
594            }
595        }
596    }
597
598    #[test]
599    fn every_truncation_of_a_valid_stream_is_an_error_or_a_short_read() {
600        // Truncation must never panic. It may legitimately produce a partial
601        // decode, because a missing end code is tolerated.
602        let data = b"the quick brown fox. ".repeat(40);
603        let stream = LzwEncoder::gif(8).unwrap().encode(&data);
604        let decoder = LzwDecoder::gif(8).unwrap();
605        for cut in 0..stream.len() {
606            let _ = decoder.decode(&stream[..cut], 1 << 20);
607        }
608    }
609
610    #[test]
611    fn the_output_limit_is_enforced() {
612        // LZW expands by up to 4096:1, so the bound is what stands between a
613        // 2 KB file and a gigabyte of memory.
614        let data = vec![0_u8; 1_000_000];
615        let stream = LzwEncoder::gif(8).unwrap().encode(&data);
616        assert!(stream.len() < 100_000, "the bomb should be small");
617        let error = LzwDecoder::gif(8)
618            .unwrap()
619            .decode(&stream, 4096)
620            .unwrap_err();
621        assert!(error.detail().contains("limit"), "{error}");
622    }
623
624    #[test]
625    fn an_out_of_range_minimum_width_is_rejected() {
626        for width in [0_u32, 1, 12, 99] {
627            assert!(
628                LzwDecoder::new(BitOrder::LsbFirst, width).is_err(),
629                "{width}"
630            );
631            assert!(
632                LzwEncoder::new(BitOrder::LsbFirst, width).is_err(),
633                "{width}"
634            );
635        }
636    }
637
638    #[test]
639    fn a_clear_code_resets_the_table_mid_stream() {
640        // Decoders must follow an encoder that clears early, which some do to
641        // bound their own memory.
642        let mut writer = CodeWriter::new(BitOrder::LsbFirst);
643        writer.push(0x100, 9); // clear
644        writer.push(b'A'.into(), 9);
645        writer.push(b'B'.into(), 9);
646        writer.push(0x100, 9); // clear again
647        writer.push(b'C'.into(), 9);
648        writer.push(0x101, 9); // end
649        let stream = writer.finish();
650        let out = LzwDecoder::gif(8).unwrap().decode(&stream, 1024).unwrap();
651        assert_eq!(out, b"ABC");
652    }
653
654    #[test]
655    fn the_two_dialects_pack_bits_differently() {
656        // If both dialects produced the same bytes, one of them would be
657        // wrong, and every round-trip test above would still pass.
658        let data = b"hello world, this is a test of bit ordering".repeat(4);
659        let lsb = LzwEncoder::new(BitOrder::LsbFirst, 8)
660            .unwrap()
661            .encode(&data);
662        let msb = LzwEncoder::new(BitOrder::MsbFirst, 8)
663            .unwrap()
664            .encode(&data);
665        assert_ne!(lsb, msb, "the two bit orders produced identical streams");
666    }
667}