Skip to main content

qrcode_core/
ec.rs

1//! Reed-Solomon error correction for QR codes.
2//!
3//! QR codes use Reed-Solomon codes over GF(256) to add redundancy, allowing
4//! the code to be read even when partially damaged or obscured. The error
5//! correction level (L/M/Q/H) determines how much data can be recovered:
6//!
7//! | Level | Recovery capacity |
8//! |-------|-------------------|
9//! | L     | ~7%               |
10//! | M     | ~15%              |
11//! | Q     | ~25%              |
12//! | H     | ~30%              |
13//!
14//! The main entry point is [`construct_codewords`], which takes encoded data
15//! and produces the final data + error correction codewords ready for canvas placement.
16
17#[cfg(not(feature = "std"))]
18#[allow(unused_imports)]
19use alloc::{
20    borrow::ToOwned,
21    format,
22    string::{String, ToString},
23    vec,
24    vec::Vec,
25};
26
27use core::ops::Deref;
28
29use crate::types::{EcLevel, QrError, QrResult, Version};
30
31//------------------------------------------------------------------------------
32//{{{ Error correction primitive
33
34/// Creates the error correction code in N bytes.
35///
36/// This method only supports computing the error-correction code up to
37/// 69 bytes. Longer blocks will result in task panic.
38///
39/// This method treats the data as a polynomial of the form
40/// (a\[0\] x<sup>m+n</sup> + a\[1\] x<sup>m+n-1</sup> + … + a\[m\] x<sup>n</sup>)
41/// in GF(2<sup>8</sup>), and then computes the polynomial modulus with a
42/// generator polynomial of degree N.
43pub fn create_error_correction_code(data: &[u8], ec_code_size: usize) -> Vec<u8> {
44    let log_den = GENERATOR_POLYNOMIALS[ec_code_size];
45    let mut work = Vec::with_capacity(data.len() + ec_code_size);
46    polynomial_remainder(data, log_den, &mut work);
47    work.split_off(data.len())
48}
49
50#[inline]
51fn polynomial_remainder<'a>(data: &[u8], log_den: &[u8], work: &'a mut Vec<u8>) -> &'a [u8] {
52    let data_len = data.len();
53    work.clear();
54    work.extend_from_slice(data);
55    work.resize(data_len + log_den.len(), 0);
56
57    // rust-lang-nursery/rust-clippy#2213
58    for i in 0..data_len {
59        let lead_coeff = work[i] as usize;
60        if lead_coeff == 0 {
61            continue;
62        }
63
64        let log_lead_coeff = usize::from(LOG_TABLE[lead_coeff]);
65        for (u, v) in work[i + 1..].iter_mut().zip(log_den.iter()) {
66            *u ^= EXP_TABLE[usize::from(*v) + log_lead_coeff];
67        }
68    }
69
70    &work[data_len..]
71}
72
73/// Benchmark-only control retaining the original modulo-based GF lookup.
74#[cfg(feature = "bench-internals")]
75#[doc(hidden)]
76pub fn create_error_correction_code_modulo_for_bench(data: &[u8], ec_code_size: usize) -> Vec<u8> {
77    let log_den = GENERATOR_POLYNOMIALS[ec_code_size];
78    let mut work = Vec::with_capacity(data.len() + ec_code_size);
79    polynomial_remainder_modulo(data, log_den, &mut work);
80    work.split_off(data.len())
81}
82
83#[cfg(feature = "bench-internals")]
84#[inline]
85fn polynomial_remainder_modulo<'a>(data: &[u8], log_den: &[u8], work: &'a mut Vec<u8>) -> &'a [u8] {
86    work.clear();
87    work.extend_from_slice(data);
88    work.resize(data.len() + log_den.len(), 0);
89    for index in 0..data.len() {
90        let coefficient = usize::from(work[index]);
91        if coefficient == 0 {
92            continue;
93        }
94        let log_coefficient = usize::from(LOG_TABLE[coefficient]);
95        for (value, log_generator) in work[index + 1..].iter_mut().zip(log_den.iter()) {
96            *value ^= EXP_TABLE[(usize::from(*log_generator) + log_coefficient) % 255];
97        }
98    }
99    &work[data.len()..]
100}
101
102#[cfg(test)]
103mod legacy {
104    use super::{DATA_BYTES_PER_BLOCK, EC_BYTES_PER_BLOCK, EXP_TABLE, GENERATOR_POLYNOMIALS, LOG_TABLE};
105    use crate::types::{EcLevel, Version};
106    use core::ops::Deref;
107
108    // Keep the original allocation and division algorithm independent of the
109    // reusable-buffer implementation so state-reset regressions are visible.
110    pub(super) fn error_correction_code(data: &[u8], ec_code_size: usize) -> Vec<u8> {
111        let log_den = GENERATOR_POLYNOMIALS[ec_code_size];
112        let mut polynomial = Vec::with_capacity(data.len() + ec_code_size);
113        polynomial.extend_from_slice(data);
114        polynomial.resize(data.len() + ec_code_size, 0);
115        for index in 0..data.len() {
116            let coefficient = usize::from(polynomial[index]);
117            if coefficient == 0 {
118                continue;
119            }
120            let log_coefficient = usize::from(LOG_TABLE[coefficient]);
121            for (value, log_generator) in polynomial[index + 1..].iter_mut().zip(log_den.iter()) {
122                *value ^= EXP_TABLE[(usize::from(*log_generator) + log_coefficient) % 255];
123            }
124        }
125        polynomial.split_off(data.len())
126    }
127
128    fn interleave<V: Deref<Target = [u8]>>(blocks: &[V]) -> Vec<u8> {
129        let max_len = blocks.last().unwrap().len();
130        let mut output = Vec::with_capacity(max_len * blocks.len());
131        for index in 0..max_len {
132            for block in blocks {
133                if index < block.len() {
134                    output.push(block[index]);
135                }
136            }
137        }
138        output
139    }
140
141    pub(super) fn construct_codewords(data: &[u8], version: Version, ec_level: EcLevel) -> (Vec<u8>, Vec<u8>) {
142        let (size_1, count_1, size_2, count_2) = version.fetch(ec_level, &DATA_BYTES_PER_BLOCK).unwrap();
143        let group_1_end = size_1 * count_1;
144        assert_eq!(data.len(), group_1_end + size_2 * count_2);
145        let mut blocks = Vec::with_capacity(count_1 + count_2);
146        blocks.extend(data[..group_1_end].chunks(size_1));
147        if size_2 > 0 {
148            blocks.extend(data[group_1_end..].chunks(size_2));
149        }
150        let degree = version.fetch(ec_level, &EC_BYTES_PER_BLOCK).unwrap();
151        let codes = blocks.iter().map(|block| error_correction_code(block, degree)).collect::<Vec<_>>();
152        (interleave(&blocks), interleave(&codes))
153    }
154}
155
156#[cfg(test)]
157mod ec_tests {
158    use crate::ec::{
159        EXP_TABLE, GENERATOR_POLYNOMIALS, LOG_TABLE, create_error_correction_code, legacy, polynomial_remainder,
160    };
161
162    #[test]
163    fn test_poly_mod_1() {
164        let res = create_error_correction_code(b" [\x0bx\xd1r\xdcMC@\xec\x11\xec\x11\xec\x11", 10);
165        assert_eq!(&*res, b"\xc4#'w\xeb\xd7\xe7\xe2]\x17");
166    }
167
168    #[test]
169    fn test_poly_mod_2() {
170        let res = create_error_correction_code(b" [\x0bx\xd1r\xdcMC@\xec\x11\xec", 13);
171        assert_eq!(&*res, b"\xa8H\x16R\xd96\x9c\x00.\x0f\xb4z\x10");
172    }
173
174    #[test]
175    fn test_poly_mod_3() {
176        let res = create_error_correction_code(b"CUF\x86W&U\xc2w2\x06\x12\x06g&", 18);
177        assert_eq!(&*res, b"\xd5\xc7\x0b-s\xf7\xf1\xdf\xe5\xf8\x9au\x9aoV\xa1o'");
178    }
179
180    #[test]
181    fn generated_gf_tables_match_inverse_relationship() {
182        assert_eq!(EXP_TABLE[0], 1);
183        assert_eq!(EXP_TABLE[255], 1);
184        assert_eq!(LOG_TABLE[0], 0xff);
185
186        for (log, &value) in EXP_TABLE[..255].iter().enumerate() {
187            assert_eq!(usize::from(LOG_TABLE[usize::from(value)]), log);
188        }
189    }
190
191    #[test]
192    fn expanded_exp_table_matches_original_modulo_lookup() {
193        for (exponent, &value) in EXP_TABLE.iter().enumerate() {
194            assert_eq!(value, EXP_TABLE[exponent % 255], "exponent {exponent}");
195        }
196    }
197
198    #[test]
199    fn reused_remainder_buffer_matches_legacy_for_every_supported_degree() {
200        let mut work = Vec::new();
201        for (degree, log_den) in GENERATOR_POLYNOMIALS.iter().enumerate() {
202            for len in [0, 1, 2, 3, 15, 16, 31, 123, 256] {
203                let mixed = (0..len).map(|index| ((index * 73 + 19) % 256) as u8).collect::<Vec<_>>();
204                for data in [vec![0; len], vec![0xff; len], mixed] {
205                    let expected = legacy::error_correction_code(&data, degree);
206                    assert_eq!(
207                        polynomial_remainder(&data, log_den, &mut work),
208                        expected,
209                        "degree {degree}, len {len}, data {data:?}"
210                    );
211                    assert_eq!(create_error_correction_code(&data, degree), expected);
212                    #[cfg(feature = "bench-internals")]
213                    assert_eq!(crate::ec::create_error_correction_code_modulo_for_bench(&data, degree), expected);
214                }
215            }
216        }
217    }
218}
219
220//}}}
221//------------------------------------------------------------------------------
222//{{{ Interleave support
223
224/// This method interleaves a vector of slices into a single vector.
225///
226/// It will first insert all the first elements of the slices in `blocks`, then
227/// all the second elements, then all the third elements, and so on.
228///
229/// The longest slice must be at the last of `blocks`, and `blocks` must not be
230/// empty.
231fn interleave<T: Copy, V: Deref<Target = [T]>>(blocks: &[V]) -> Vec<T> {
232    let last_block_len = blocks.last().expect("non-empty blocks").len();
233    let mut res = Vec::with_capacity(last_block_len * blocks.len());
234    for i in 0..last_block_len {
235        for t in blocks {
236            if i < t.len() {
237                res.push(t[i]);
238            }
239        }
240    }
241    res
242}
243
244#[test]
245fn test_interleave() {
246    let res = interleave(&[&b"1234"[..], b"5678", b"abcdef", b"ghijkl"]);
247    assert_eq!(&*res, b"15ag26bh37ci48djekfl");
248}
249
250//}}}
251//------------------------------------------------------------------------------
252//{{{ QR code error correction
253
254/// Constructs data and error correction codewords ready to be put in the QR
255/// code matrix.
256///
257/// # Errors
258///
259/// Returns `Err(QrError::InvalidVersion)` if it is not valid to use the
260///  `ec_level` for the given version (e.g. `Version::Micro(1)` with
261/// `EcLevel::H`).
262///
263/// Returns [`QrError::InvalidDataLength`] if `rawbits` does not contain exactly
264/// the padded data bytes required by this version and correction level. For
265/// Micro M1 and M3, this includes the byte containing the final half codeword.
266pub fn construct_codewords(rawbits: &[u8], version: Version, ec_level: EcLevel) -> QrResult<(Vec<u8>, Vec<u8>)> {
267    let (block_1_size, block_1_count, block_2_size, block_2_count) = version.fetch(ec_level, &DATA_BYTES_PER_BLOCK)?;
268
269    let blocks_count = block_1_count + block_2_count;
270    let block_1_end = block_1_size * block_1_count;
271    let total_size = block_1_end + block_2_size * block_2_count;
272
273    if rawbits.len() != total_size {
274        return Err(QrError::InvalidDataLength { expected: total_size, actual: rawbits.len() });
275    }
276    let ec_bytes = version.fetch(ec_level, &EC_BYTES_PER_BLOCK)?;
277
278    // Divide the data into blocks.
279    let mut blocks = Vec::with_capacity(blocks_count);
280    blocks.extend(rawbits[..block_1_end].chunks(block_1_size));
281    if block_2_size > 0 {
282        blocks.extend(rawbits[block_1_end..].chunks(block_2_size));
283    }
284
285    // Generate EC codes.
286    let mut ec_vec = vec![0; ec_bytes * blocks_count];
287    let mut work = Vec::with_capacity(block_1_size.max(block_2_size) + ec_bytes);
288    let log_den = GENERATOR_POLYNOMIALS[ec_bytes];
289    for (block_index, block) in blocks.iter().enumerate() {
290        let remainder = polynomial_remainder(block, log_den, &mut work);
291        for (byte_index, &byte) in remainder.iter().enumerate() {
292            ec_vec[byte_index * blocks_count + block_index] = byte;
293        }
294    }
295
296    let blocks_vec = interleave(&blocks);
297
298    Ok((blocks_vec, ec_vec))
299}
300
301#[cfg(test)]
302mod construct_codewords_test {
303    use crate::bits::{Bits, data_capacity_bits};
304    use crate::ec::{DATA_BYTES_PER_BLOCK, construct_codewords, legacy};
305    use crate::types::{EcLevel, QrError, Version};
306
307    #[test]
308    fn test_add_ec_simple() {
309        let msg = b" [\x0bx\xd1r\xdcMC@\xec\x11\xec\x11\xec\x11";
310        let (blocks_vec, ec_vec) = construct_codewords(msg, Version::Normal(1), EcLevel::M).unwrap();
311        assert_eq!(&*blocks_vec, msg);
312        assert_eq!(&*ec_vec, b"\xc4#'w\xeb\xd7\xe7\xe2]\x17");
313    }
314
315    #[test]
316    fn test_add_ec_complex() {
317        let msg = b"CUF\x86W&U\xc2w2\x06\x12\x06g&\xf6\xf6B\x07v\x86\xf2\x07&V\x16\xc6\xc7\x92\x06\
318                    \xb6\xe6\xf7w2\x07v\x86W&R\x06\x86\x972\x07F\xf7vV\xc2\x06\x972\x10\xec\x11\xec\
319                    \x11\xec\x11\xec";
320        let expected_blocks = b"C\xf6\xb6FU\xf6\xe6\xf7FB\xf7v\x86\x07wVWv2\xc2&\x86\x07\x06U\xf2v\
321                                \x97\xc2\x07\x862w&W\x102V&\xec\x06\x16R\x11\x12\xc6\x06\xec\x06\
322                                \xc7\x86\x11g\x92\x97\xec&\x062\x11\x07\xec";
323        let expected_ec = b"\xd5W\x94\xeb\xc7\xcct\x9f\x0b`\xb1\x05-<\xd4\xads\xcaL\x18\xf7\xb6\x85\
324                            \x93\xf1|K;\xdf\x9d\xf2!\xe5\xc8\xeej\xf8\x86L(\x9a\x1b\xc3\xffu\x81\
325                            \xe6\xac\x9a\xd1\xbdRo\x11\n\x02V\xa3l\x83\xa1\xa3\xf0 ox\xc0\xb2'\x85\
326                            \x8d\xec";
327
328        let (blocks_vec, ec_vec) = construct_codewords(msg, Version::Normal(5), EcLevel::Q).unwrap();
329        assert_eq!(&*blocks_vec, &expected_blocks[..]);
330        assert_eq!(&*ec_vec, &expected_ec[..]);
331    }
332
333    #[test]
334    fn codewords_match_legacy_for_every_valid_version_and_correction_level() {
335        let versions = (1..=40).map(Version::Normal).chain((1..=4).map(Version::Micro));
336        let mut checked_combinations = 0;
337        for version in versions {
338            for ec_level in [EcLevel::L, EcLevel::M, EcLevel::Q, EcLevel::H] {
339                let Ok((size_1, count_1, size_2, count_2)) = version.fetch(ec_level, &DATA_BYTES_PER_BLOCK) else {
340                    continue;
341                };
342                checked_combinations += 1;
343                let expected_len = size_1 * count_1 + size_2 * count_2;
344                let mixed = (0..expected_len).map(|index| ((index * 73 + 19) % 256) as u8).collect::<Vec<_>>();
345                let mut bits = Bits::new(version);
346                bits.push_numeric_data(b"1").unwrap();
347                bits.push_terminator(ec_level).unwrap();
348                let padded = bits.into_bytes();
349                assert_eq!(padded.len(), expected_len);
350                assert_eq!(expected_len, data_capacity_bits(version, ec_level).unwrap().div_ceil(8));
351                for data in [vec![0; expected_len], vec![0xff; expected_len], mixed, padded] {
352                    assert_eq!(
353                        construct_codewords(&data, version, ec_level).unwrap(),
354                        legacy::construct_codewords(&data, version, ec_level),
355                        "{version:?} {ec_level:?} data {data:?}"
356                    );
357                }
358            }
359        }
360        assert_eq!(checked_combinations, 168);
361    }
362
363    #[test]
364    fn codeword_construction_rejects_short_and_long_padded_data() {
365        let versions = (1..=40).map(Version::Normal).chain((1..=4).map(Version::Micro));
366        for version in versions {
367            for ec_level in [EcLevel::L, EcLevel::M, EcLevel::Q, EcLevel::H] {
368                let Ok(capacity) = data_capacity_bits(version, ec_level) else {
369                    continue;
370                };
371                let expected = capacity.div_ceil(8);
372                for actual in [0, expected - 1, expected + 1, expected + 2] {
373                    assert_eq!(
374                        construct_codewords(&vec![0; actual], version, ec_level),
375                        Err(QrError::InvalidDataLength { expected, actual }),
376                        "{version:?} {ec_level:?}"
377                    );
378                }
379            }
380        }
381    }
382
383    #[test]
384    fn invalid_version_precedes_padded_data_length_errors() {
385        for (version, ec_level) in [
386            (Version::Normal(0), EcLevel::L),
387            (Version::Normal(41), EcLevel::H),
388            (Version::Micro(0), EcLevel::L),
389            (Version::Micro(5), EcLevel::L),
390            (Version::Micro(1), EcLevel::M),
391            (Version::Micro(2), EcLevel::Q),
392            (Version::Micro(3), EcLevel::Q),
393            (Version::Micro(4), EcLevel::H),
394        ] {
395            assert_eq!(construct_codewords(&[], version, ec_level), Err(QrError::InvalidVersion { version, ec_level }));
396        }
397    }
398}
399
400//}}}
401//------------------------------------------------------------------------------
402//{{{ Number of allowed errors
403
404/// Computes the maximum allowed number of erratic modules can be introduced to
405/// the QR code, before the data becomes truly corrupted.
406///
407/// # Errors
408///
409/// Returns `Err(QrError::InvalidVersion)` if it is not valid to use the
410///  `ec_level` for the given version (e.g. `Version::Micro(1)` with
411/// `EcLevel::H`).
412pub fn max_allowed_errors(version: Version, ec_level: EcLevel) -> QrResult<usize> {
413    use crate::EcLevel::{L, M};
414    use crate::Version::{Micro, Normal};
415
416    let p = match (version, ec_level) {
417        (Micro(2) | Normal(1), L) => 3,
418        (Micro(_) | Normal(2), L) | (Micro(2) | Normal(1), M) => 2,
419        (Normal(1), _) | (Normal(3), L) => 1,
420        _ => 0,
421    };
422
423    let ec_bytes_per_block = version.fetch(ec_level, &EC_BYTES_PER_BLOCK)?;
424    let (_, count1, _, count2) = version.fetch(ec_level, &DATA_BYTES_PER_BLOCK)?;
425    let ec_bytes = (count1 + count2) * ec_bytes_per_block;
426
427    Ok((ec_bytes - p) / 2)
428}
429
430#[cfg(test)]
431mod max_allowed_errors_test {
432    use crate::ec::max_allowed_errors;
433    use crate::types::{EcLevel, Version};
434
435    #[test]
436    fn test_low_versions() {
437        assert_eq!(Ok(0), max_allowed_errors(Version::Micro(1), EcLevel::L));
438
439        assert_eq!(Ok(1), max_allowed_errors(Version::Micro(2), EcLevel::L));
440        assert_eq!(Ok(2), max_allowed_errors(Version::Micro(2), EcLevel::M));
441
442        assert_eq!(Ok(2), max_allowed_errors(Version::Micro(3), EcLevel::L));
443        assert_eq!(Ok(4), max_allowed_errors(Version::Micro(3), EcLevel::M));
444
445        assert_eq!(Ok(3), max_allowed_errors(Version::Micro(4), EcLevel::L));
446        assert_eq!(Ok(5), max_allowed_errors(Version::Micro(4), EcLevel::M));
447        assert_eq!(Ok(7), max_allowed_errors(Version::Micro(4), EcLevel::Q));
448
449        assert_eq!(Ok(2), max_allowed_errors(Version::Normal(1), EcLevel::L));
450        assert_eq!(Ok(4), max_allowed_errors(Version::Normal(1), EcLevel::M));
451        assert_eq!(Ok(6), max_allowed_errors(Version::Normal(1), EcLevel::Q));
452        assert_eq!(Ok(8), max_allowed_errors(Version::Normal(1), EcLevel::H));
453
454        assert_eq!(Ok(4), max_allowed_errors(Version::Normal(2), EcLevel::L));
455        assert_eq!(Ok(8), max_allowed_errors(Version::Normal(2), EcLevel::M));
456        assert_eq!(Ok(11), max_allowed_errors(Version::Normal(2), EcLevel::Q));
457        assert_eq!(Ok(14), max_allowed_errors(Version::Normal(2), EcLevel::H));
458
459        assert_eq!(Ok(7), max_allowed_errors(Version::Normal(3), EcLevel::L));
460        assert_eq!(Ok(13), max_allowed_errors(Version::Normal(3), EcLevel::M));
461        assert_eq!(Ok(18), max_allowed_errors(Version::Normal(3), EcLevel::Q));
462        assert_eq!(Ok(22), max_allowed_errors(Version::Normal(3), EcLevel::H));
463
464        assert_eq!(Ok(10), max_allowed_errors(Version::Normal(4), EcLevel::L));
465        assert_eq!(Ok(18), max_allowed_errors(Version::Normal(4), EcLevel::M));
466        assert_eq!(Ok(26), max_allowed_errors(Version::Normal(4), EcLevel::Q));
467        assert_eq!(Ok(32), max_allowed_errors(Version::Normal(4), EcLevel::H));
468    }
469
470    #[test]
471    fn test_high_versions() {
472        assert_eq!(Ok(375), max_allowed_errors(Version::Normal(40), EcLevel::L));
473        assert_eq!(Ok(686), max_allowed_errors(Version::Normal(40), EcLevel::M));
474        assert_eq!(Ok(1020), max_allowed_errors(Version::Normal(40), EcLevel::Q));
475        assert_eq!(Ok(1215), max_allowed_errors(Version::Normal(40), EcLevel::H));
476    }
477}
478
479//}}}
480//------------------------------------------------------------------------------
481//{{{ Precomputed tables for GF(256).
482
483/// `EXP_TABLE` encodes the value of 2<sup>n</sup> in the Galois Field GF(256).
484///
485/// Powers repeat every 255 entries. Covering every sum of two byte-sized logs
486/// lets the division loop index the table directly without reducing modulo 255.
487const EXP_TABLE: [u8; 512] = generate_exp_table();
488
489/// `LOG_TABLE` is the inverse of the first nonzero cycle in `EXP_TABLE`.
490const LOG_TABLE: [u8; 256] = generate_log_table();
491
492const fn generate_exp_table() -> [u8; 512] {
493    let mut table = [0; 512];
494    let mut value = 1_u16;
495    let mut i = 0;
496    while i < table.len() {
497        table[i] = value as u8;
498        value <<= 1;
499        if value & 0x100 != 0 {
500            value ^= 0x11d;
501        }
502        i += 1;
503    }
504    table
505}
506
507const fn generate_log_table() -> [u8; 256] {
508    let exp = generate_exp_table();
509    let mut table = [0xff; 256];
510    let mut i = 0;
511    while i < 255 {
512        table[exp[i] as usize] = i as u8;
513        i += 1;
514    }
515    table
516}
517
518/// The generator polynomial list.
519///
520/// `GENERATOR_POLYNOMIALS[i]` is the polynomial for `i` error correction code
521/// words. Each entry encodes the log coefficients of the expanded polynomial
522/// (x − 2<sup>0</sup>)(x − 2<sup>1</sup>)…(x − 2<sup>i-1</sup>). Each entry is
523/// used as the denominator for polynomial division to obtain the modulus which
524/// is the Reed-Solomon error correction code.
525///
526/// A partial list can be found from ISO/IEC 18004:2006 Annex A.
527#[rustfmt::skip]
528// ^ this attribute is currently useless, see rust-lang-nursery/rustfmt#1080 and 1298
529static GENERATOR_POLYNOMIALS: [&[u8]; 70] = [
530    b"",
531    b"\x00",
532    b"\x19\x01",
533    b"\xc6\xc7\x03",
534    b"\x4b\xf9\x4e\x06",
535    b"\x71\xa4\xa6\x77\x0a",
536    b"\xa6\x00\x86\x05\xb0\x0f",
537    b"\x57\xe5\x92\x95\xee\x66\x15",
538    b"\xaf\xee\xd0\xf9\xd7\xfc\xc4\x1c",
539    b"\x5f\xf6\x89\xe7\xeb\x95\x0b\x7b\x24",
540    b"\xfb\x43\x2e\x3d\x76\x46\x40\x5e\x20\x2d",
541    b"\xdc\xc0\x5b\xc2\xac\xb1\xd1\x74\xe3\x0a\x37",
542    b"\x66\x2b\x62\x79\xbb\x71\xc6\x8f\x83\x57\x9d\x42",
543    b"\x4a\x98\xb0\x64\x56\x64\x6a\x68\x82\xda\xce\x8c\x4e",
544    b"\xc7\xf9\x9b\x30\xbe\x7c\xda\x89\xd8\x57\xcf\x3b\x16\x5b",
545    b"\x08\xb7\x3d\x5b\xca\x25\x33\x3a\x3a\xed\x8c\x7c\x05\x63\x69",
546    b"\x78\x68\x6b\x6d\x66\xa1\x4c\x03\x5b\xbf\x93\xa9\xb6\xc2\xe1\x78",
547    b"\x2b\x8b\xce\x4e\x2b\xef\x7b\xce\xd6\x93\x18\x63\x96\x27\xf3\xa3\x88",
548    b"\xd7\xea\x9e\x5e\xb8\x61\x76\xaa\x4f\xbb\x98\x94\xfc\xb3\x05\x62\x60\x99",
549    b"\x43\x03\x69\x99\x34\x5a\x53\x11\x96\x9f\x2c\x80\x99\x85\xfc\xde\x8a\xdc\xab",
550    b"\x11\x3c\x4f\x32\x3d\xa3\x1a\xbb\xca\xb4\xdd\xe1\x53\xef\x9c\xa4\xd4\xd4\xbc\xbe",
551    b"\xf0\xe9\x68\xf7\xb5\x8c\x43\x62\x55\xc8\xd2\x73\x94\x89\xe6\x24\x7a\xfe\x94\xaf\xd2",
552    b"\xd2\xab\xf7\xf2\x5d\xe6\x0e\x6d\xdd\x35\xc8\x4a\x08\xac\x62\x50\xdb\x86\xa0\x69\xa5\xe7",
553    b"\xab\x66\x92\x5b\x31\x67\x41\x11\xc1\x96\x0e\x19\xb7\xf8\x5e\xa4\xe0\xc0\x01\x4e\x38\x93\xfd",
554    b"\xe5\x79\x87\x30\xd3\x75\xfb\x7e\x9f\xb4\xa9\x98\xc0\xe2\xe4\xda\x6f\x00\x75\xe8\x57\x60\xe3\x15",
555    b"\xe7\xb5\x9c\x27\xaa\x1a\x0c\x3b\x0f\x94\xc9\x36\x42\xed\xd0\x63\xa7\x90\xb6\x5f\xf3\x81\xb2\xfc\x2d",
556    b"\xad\x7d\x9e\x02\x67\xb6\x76\x11\x91\xc9\x6f\x1c\xa5\x35\xa1\x15\xf5\x8e\x0d\x66\x30\xe3\x99\x91\xda\x46",
557    b"\x4f\xe4\x08\xa5\xe3\x15\xb4\x1d\x09\xed\x46\x63\x2d\x3a\x8a\x87\x49\x7e\xac\x5e\xd8\xc1\x9d\x1a\x11\x95\x60",
558    b"\xa8\xdf\xc8\x68\xe0\xea\x6c\xb4\x6e\xbe\xc3\x93\xcd\x1b\xe8\xc9\x15\x2b\xf5\x57\x2a\xc3\xd4\x77\xf2\x25\x09\x7b",
559    b"\x9c\x2d\xb7\x1d\x97\xdb\x36\x60\xf9\x18\x88\x05\xf1\xaf\xbd\x1c\x4b\xea\x96\x94\x17\x09\xca\xa2\x44\xfa\x8c\x18\x97",
560    b"\x29\xad\x91\x98\xd8\x1f\xb3\xb6\x32\x30\x6e\x56\xef\x60\xde\x7d\x2a\xad\xe2\xc1\xe0\x82\x9c\x25\xfb\xd8\xee\x28\xc0\xb4",
561    b"\x14\x25\xfc\x5d\x3f\x4b\xe1\x1f\x73\x53\x71\x27\x2c\x49\x7a\x89\x76\x77\x90\xf8\xf8\x37\x01\xe1\x69\x7b\xb7\x75\xbb\xc8\xd2",
562    b"\x0a\x06\x6a\xbe\xf9\xa7\x04\x43\xd1\x8a\x8a\x20\xf2\x7b\x59\x1b\x78\xb9\x50\x9c\x26\x45\xab\x3c\x1c\xde\x50\x34\xfe\xb9\xdc\xf1",
563    b"\xf5\xe7\x37\x18\x47\x4e\x4c\x51\xe1\xd4\xad\x25\xd7\x2e\x77\xe5\xf5\xa7\x7e\x48\xb5\x5e\xa5\xd2\x62\x7d\x9f\xb8\xa9\xe8\xb9\xe7\x12",
564    b"\x6f\x4d\x92\x5e\x1a\x15\x6c\x13\x69\x5e\x71\xc1\x56\x8c\xa3\x7d\x3a\x9e\xe5\xef\xda\x67\x38\x46\x72\x3d\xb7\x81\xa7\x0d\x62\x3e\x81\x33",
565    b"\x07\x5e\x8f\x51\xf7\x7f\xca\xca\xc2\x7d\x92\x1d\x8a\xa2\x99\x41\x69\x7a\x74\xee\x1a\x24\xd8\x70\x7d\xe4\x0f\x31\x08\xa2\x1e\x7e\x6f\x3a\x55",
566    b"\xc8\xb7\x62\x10\xac\x1f\xf6\xea\x3c\x98\x73\x00\xa7\x98\x71\xf8\xee\x6b\x12\x3f\xda\x25\x57\xd2\x69\xb1\x78\x4a\x79\xc4\x75\xfb\x71\xe9\x1e\x78",
567    b"\x9a\x4b\x8d\xb4\x3d\xa5\x68\xe8\x2e\xe3\x60\xb2\x5c\x87\x39\xa2\x78\xc2\xd4\xae\xfc\xb7\x2a\x23\x9d\x6f\x17\x85\x64\x08\x69\x25\xc0\xbd\x9f\x13\x9c",
568    b"\x9f\x22\x26\xe4\xe6\x3b\xf3\x5f\x31\xda\xb0\xa4\x14\x41\x2d\x6f\x27\x51\x31\x76\x71\xde\xc1\xfa\xf2\xa8\xd9\x29\xa4\xf7\xb1\x1e\xee\x12\x78\x99\x3c\xc1",
569    b"\x51\xd8\xae\x2f\xc8\x96\x3b\x9c\x59\x8f\x59\xa6\xb7\xaa\x98\x15\xa5\xb1\x71\x84\xea\x05\x9a\x44\x7c\xaf\xc4\x9d\xf9\xe9\x53\x18\x99\xf1\x7e\x24\x74\x13\xe7",
570    b"\x3b\x74\x4f\xa1\xfc\x62\x80\xcd\x80\xa1\xf7\x39\xa3\x38\xeb\x6a\x35\x1a\xbb\xae\xe2\x68\xaa\x07\xaf\x23\xb5\x72\x58\x29\x2f\xa3\x7d\x86\x48\x14\xe8\x35\x23\x0f",
571    b"\x84\xa7\x34\x8b\xb8\xdf\x95\x5c\xfa\x12\x53\x21\x7f\x6d\xc2\x07\xd3\xf2\x6d\x42\x56\xa9\x57\x60\xbb\x9f\x72\xac\x76\xd0\xb7\xc8\x52\xb3\x26\x27\x22\xf2\x8e\x93\x37",
572    b"\xfa\x67\xdd\xe6\x19\x12\x89\xe7\x00\x03\x3a\xf2\xdd\xbf\x6e\x54\xe6\x08\xbc\x6a\x60\x93\x0f\x83\x8b\x22\x65\xdf\x27\x65\xd5\xc7\xed\xfe\xc9\x7b\xab\xa2\xc2\x75\x32\x60",
573    b"\x60\x43\x03\xf5\xd9\xd7\x21\x41\xf0\x6d\x90\x3f\x15\x83\x26\x65\x99\x80\x37\x1f\xed\x03\x5e\xa0\x14\x57\x4d\x38\xbf\x7b\xcf\x4b\x52\x00\x7a\x84\x65\x91\xd7\x0f\x79\xc0\x8a",
574    b"\xbe\x07\x3d\x79\x47\xf6\x45\x37\xa8\xbc\x59\xf3\xbf\x19\x48\x7b\x09\x91\x0e\xf7\x01\xee\x2c\x4e\x8f\x3e\xe0\x7e\x76\x72\x44\xa3\x34\xc2\xd9\x93\xcc\xa9\x25\x82\x71\x66\x49\xb5",
575    b"\x06\xac\x48\xfa\x12\xab\xab\xa2\xe5\xbb\xef\x04\xbb\x0b\x25\xe4\x66\x48\x66\x16\x21\x49\x5f\x63\x84\x01\x0f\x59\x04\x70\x82\x5f\xd3\xeb\xe3\x3a\x23\x58\x84\x17\x2c\xa5\x36\xbb\xe1",
576    b"\x70\x5e\x58\x70\xfd\xe0\xca\x73\xbb\x63\x59\x05\x36\x71\x81\x2c\x3a\x10\x87\xd8\xa9\xd3\x24\x01\x04\x60\x3c\xf1\x49\x68\xea\x08\xf9\xf5\x77\xae\x34\x19\x9d\xe0\x2b\xca\xdf\x13\x52\x0f",
577    b"\x4c\xa4\xe5\x5c\x4f\xa8\xdb\x6e\x68\x15\xdc\x4a\x13\xc7\xc3\x64\x5d\xbf\x2b\xd5\x48\x38\x8a\xa1\x7d\xbb\x77\xfa\xbd\x89\xbe\x4c\x7e\xf7\x5d\x1e\x84\x06\x3a\xd5\xd0\xa5\xe0\x98\x85\x5b\x3d",
578    b"\xe4\x19\xc4\x82\xd3\x92\x3c\x18\xfb\x5a\x27\x66\xf0\x3d\xb2\x3f\x2e\x7b\x73\x12\xdd\x6f\x87\xa0\xb6\xcd\x6b\xce\x5f\x96\x78\xb8\x5b\x15\xf7\x9c\x8c\xee\xbf\x0b\x5e\xe3\x54\x32\xa3\x27\x22\x6c",
579    b"\xac\x79\x01\x29\xc1\xde\xed\x40\x6d\xb5\x34\x78\xd4\xe2\xef\xf5\xd0\x14\xf6\x22\xe1\xcc\x86\x65\x7d\xce\x45\x8a\xfa\x00\x4d\x3a\x8f\xb9\xdc\xfe\xd2\xbe\x70\x58\x5b\x39\x5a\x6d\x05\x0d\xb5\x19\x9c",
580    b"\xe8\x7d\x9d\xa1\xa4\x09\x76\x2e\xd1\x63\xcb\xc1\x23\x03\xd1\x6f\xc3\xf2\xcb\xe1\x2e\x0d\x20\xa0\x7e\xd1\x82\xa0\xf2\xd7\xf2\x4b\x4d\x2a\xbd\x20\x71\x41\x7c\x45\xe4\x72\xeb\xaf\x7c\xaa\xd7\xe8\x85\xcd",
581    b"\xd5\xa6\x8e\x2b\x0a\xd8\x8d\xa3\xac\xb4\x66\x46\x59\x3e\xde\x3e\x2a\xd2\x97\xa3\xda\x46\x4d\x27\xa6\xbf\x72\xca\xf5\xbc\xb7\xdd\x4b\xd4\x1b\xed\x7f\xcc\xeb\x3e\xbe\xe8\x12\x2e\xab\x0f\x62\xf7\x42\xa3\x00",
582    b"\x74\x32\x56\xba\x32\xdc\xfb\x59\xc0\x2e\x56\x7f\x7c\x13\xb8\xe9\x97\xd7\x16\x0e\x3b\x91\x25\xf2\xcb\x86\xfe\x59\xbe\x5e\x3b\x41\x7c\x71\x64\xe9\xeb\x79\x16\x4c\x56\x61\x27\xf2\xc8\xdc\x65\x21\xef\xfe\x74\x33",
583    b"\x7a\xd6\xe7\x88\xc7\x0b\x06\xcd\x7c\x48\xd5\x75\xbb\x3c\x93\xc9\x49\x4b\x21\x92\xab\xf7\x76\xd0\x9d\xb1\xcb\xeb\x53\x2d\xe2\xca\xe5\xa8\x07\x39\xed\xeb\xc8\x7c\x6a\xfe\xa5\x0e\x93\x00\x39\x2a\x1f\xb2\xd5\xad\x67",
584    b"\xb7\x1a\xc9\x57\xd2\xdd\x71\x15\x2e\x41\x2d\x32\xee\xb8\xf9\xe1\x66\x3a\xd1\xda\x6d\xa5\x1a\x5f\xb8\xc0\x34\xf5\x23\xfe\xee\xaf\xac\x4f\x7b\x19\x7a\x2b\x78\x6c\xd7\x50\x80\xc9\xeb\x08\x99\x3b\x65\x1f\xc6\x4c\x1f\x9c",
585    b"\x26\xc5\x7b\xa7\x10\x57\xb2\xee\xe3\x61\x94\xf7\x1a\x5a\xe4\xb6\xec\xc5\x2f\xf9\x24\xd5\x36\x71\xb5\x4a\xb1\xcc\x9b\x3d\x2f\x2a\x00\x84\x90\xfb\xc8\x26\x26\x8a\x36\x2c\x40\x13\x16\xce\x10\x0a\xe4\xd3\xa1\xab\x2c\xc2\xd2",
586    b"\x6a\x78\x6b\x9d\xa4\xd8\x70\x74\x02\x5b\xf8\xa3\x24\xc9\xca\xe5\x06\x90\xfe\x9b\x87\xd0\xaa\xd1\x0c\x8b\x7f\x8e\xb6\xf9\xb1\xae\xbe\x1c\x0a\x55\xef\xb8\x65\x7c\x98\xce\x60\x17\xa3\x3d\x1b\xc4\xf7\x97\x9a\xca\xcf\x14\x3d\x0a",
587    b"\x3a\x8c\xed\x5d\x6a\x3d\xc1\x02\x57\x49\xc2\xd7\x9f\xa3\x0a\x9b\x05\x79\x99\x3b\xf8\x04\x75\x16\x3c\xb1\x90\x2c\x48\xe4\x3e\x01\x13\xaa\x71\x9e\x19\xaf\xc7\x8b\x5a\x01\xd2\x07\x77\x9a\x59\x9f\x82\x7a\x2e\x93\xbe\x87\x5e\x44\x42",
588    b"\x52\x74\x1a\xf7\x42\x1b\x3e\x6b\xfc\xb6\xc8\xb9\xeb\x37\xfb\xf2\xd2\x90\x9a\xed\xb0\x8d\xc0\xf8\x98\xf9\xce\x55\xfd\x8e\x41\xa5\x7d\x17\x18\x1e\x7a\xf0\xd6\x06\x81\xda\x1d\x91\x7f\x86\xce\xf5\x75\x1d\x29\x3f\x9f\x8e\xe9\x7d\x94\x7b",
589    b"\x39\x73\xe8\x0b\xc3\xd9\x03\xce\x4d\x43\x1d\xa6\xb4\x6a\x76\xcb\x11\x45\x98\xd5\x4a\x2c\x31\x2b\x62\x3d\xfd\x7a\x0e\x2b\xd1\x8f\x09\x68\x6b\xab\xe0\x39\xfe\xfb\xe2\xe8\xdd\xc2\xf0\x75\xa1\x52\xb2\xf6\xb2\x21\x32\x56\xd7\xef\xb4\xb4\xb5",
590    b"\x6b\x8c\x1a\x0c\x09\x8d\xf3\xc5\xe2\xc5\xdb\x2d\xd3\x65\xdb\x78\x1c\xb5\x7f\x06\x64\xf7\x02\xcd\xc6\x39\x73\xdb\x65\x6d\xa0\x52\x25\x26\xee\x31\xa0\xd1\x79\x56\x0b\x7c\x1e\xb5\x54\x19\xc2\x57\x41\x66\xbe\xdc\x46\x1b\xd1\x10\x59\x07\x21\xf0",
591    b"\xa1\xf4\x69\x73\x40\x09\xdd\xec\x10\x91\x94\x22\x90\xba\x0d\x14\xfe\xf6\x26\x23\xca\x48\x04\xd4\x9f\xd3\xa5\x87\xfc\xfa\x19\x57\x1e\x78\xe2\xea\x5c\xc7\x48\x07\x9b\xda\xe7\x2c\x7d\xb2\x9c\xae\x7c\x2b\x64\x1f\x38\x65\xcc\x40\xaf\xe1\xa9\x92\x2d",
592    b"\x41\xca\x71\x62\x47\xdf\xf8\x76\xd6\x5e\x00\x7a\x25\x17\x02\xe4\x3a\x79\x07\x69\x87\x4e\xf3\x76\x46\x4c\xdf\x59\x48\x32\x46\x6f\xc2\x11\xd4\x7e\xb5\x23\xdd\x75\xeb\x0b\xe5\x95\x93\x7b\xd5\x28\x73\x06\xc8\x64\x1a\xf6\xb6\xda\x7f\xd7\x24\xba\x6e\x6a",
593    b"\x1e\x47\x24\x47\x13\xc3\xac\x6e\x3d\x02\xa9\xc2\x5a\x88\x3b\xb6\xe7\x91\x66\x27\xaa\xe7\xd6\x43\xc4\xcf\x35\x70\xf6\x5a\x5a\x79\xb7\x92\x4a\x4d\x26\x59\x16\xe7\x37\x38\xf2\x70\xd9\x6e\x7b\x3e\xc9\xd9\x80\xa5\x3c\xb5\x25\xa1\xf6\x84\xf6\x12\x73\x88\xa8",
594    b"\x2d\x33\xaf\x09\x07\x9e\x9f\x31\x44\x77\x5c\x7b\xb1\xcc\xbb\xfe\xc8\x4e\x8d\x95\x77\x1a\x7f\x35\xa0\x5d\xc7\xd4\x1d\x18\x91\x9c\xd0\x96\xda\xd1\x04\xd8\x5b\x2f\xb8\x92\x2f\x8c\xc3\xc3\x7d\xf2\xee\x3f\x63\x6c\x8c\xe6\xf2\x1f\xcc\x0b\xb2\xf3\xd9\x9c\xd5\xe7",
595    b"\x89\x9e\xf7\xf0\x25\xee\xd6\x80\x63\xda\x2e\x8a\xc6\x80\x5c\xdb\x6d\x8b\xa6\x19\x42\x43\x0e\x3a\xee\x95\xb1\xc3\xdd\x9a\xab\x30\x50\x0c\x3b\xbe\xe4\x13\x37\xd0\x5c\x70\xe5\x25\x3c\x0a\x2f\x51\x00\xc0\x25\xab\xaf\x93\x80\x49\xa6\x3d\x95\x0c\x18\x5f\x46\x71\x28",
596    b"\x05\x76\xde\xb4\x88\x88\xa2\x33\x2e\x75\x0d\xd7\x51\x11\x8b\xf7\xc5\xab\x5f\xad\x41\x89\xb2\x44\x6f\x5f\x65\x29\x48\xd6\xa9\xc5\x5f\x07\x2c\x9a\x4d\x6f\xec\x28\x79\x8f\x3f\x57\x50\xfd\xf0\x7e\xd9\x4d\x22\xe8\x6a\x32\xa8\x52\x4c\x92\x43\x6a\xab\x19\x84\x5d\x2d\x69",
597    b"\xbf\xac\x71\x56\x07\xa6\xf6\xb9\x9b\xfa\x62\x71\x59\x56\xd6\xe1\x9c\xbe\x3a\x21\x90\x43\xb3\xa3\x34\x9a\xe9\x97\x68\xfb\xa0\x7e\xaf\xd0\xe1\x46\xe3\x92\x04\x98\x8b\x67\x19\x6b\x3d\xcc\x9f\xfa\xc1\xe1\x69\xa0\x62\xa7\x02\x35\x10\xf2\x53\xd2\xc4\x67\xf8\x56\xd3\x29\xab",
598    b"\xf7\x9f\xdf\x21\xe0\x5d\x4d\x46\x5a\xa0\x20\xfe\x2b\x96\x54\x65\xbe\xcd\x85\x34\x3c\xca\xa5\xdc\xcb\x97\x5d\x54\x0f\x54\xfd\xad\xa0\x59\xe3\x34\xc7\x61\x5f\xe7\x34\xb1\x29\x7d\x89\xf1\xa6\xe1\x76\x02\x36\x20\x52\xd7\xaf\xc6\x2b\xee\xeb\x1b\x65\xb8\x7f\x03\x05\x08\xa3\xee",
599    b"\x69\x49\x44\x01\x1d\xa8\x75\x0e\x58\xd0\x37\x2e\x2a\xd9\x06\x54\xb3\x61\x06\xf0\xc0\xe7\x9e\x40\x76\xa0\xcb\x39\x3d\x6c\xc7\x7c\x41\xbb\xdd\xa7\x27\xb6\x9f\xb4\xf4\xcb\xe4\xfe\x0d\xaf\x3d\x5a\xce\x28\xc7\x5e\x43\x39\x51\xe5\x2e\x7b\x59\x25\x1f\xca\x42\xfa\x23\xaa\xf3\x58\x33",
600];
601
602//}}}
603//------------------------------------------------------------------------------
604//{{{ Tables for error correction sizes
605
606/// `EC_BYTES_PER_BLOCK` provides the number of codewords (bytes) used for error
607/// correction per block in each version.
608///
609/// This is a copy of ISO/IEC 18004:2006, §6.5.1, Table 9 (The 4th column divide
610/// by the sum of the 6th column).
611static EC_BYTES_PER_BLOCK: [[usize; 4]; 44] = [
612    // Normal versions.
613    [7, 10, 13, 17],  // 1
614    [10, 16, 22, 28], // 2
615    [15, 26, 18, 22], // 3
616    [20, 18, 26, 16], // 4
617    [26, 24, 18, 22], // 5
618    [18, 16, 24, 28], // 6
619    [20, 18, 18, 26], // 7
620    [24, 22, 22, 26], // 8
621    [30, 22, 20, 24], // 9
622    [18, 26, 24, 28], // 10
623    [20, 30, 28, 24], // 11
624    [24, 22, 26, 28], // 12
625    [26, 22, 24, 22], // 13
626    [30, 24, 20, 24], // 14
627    [22, 24, 30, 24], // 15
628    [24, 28, 24, 30], // 16
629    [28, 28, 28, 28], // 17
630    [30, 26, 28, 28], // 18
631    [28, 26, 26, 26], // 19
632    [28, 26, 30, 28], // 20
633    [28, 26, 28, 30], // 21
634    [28, 28, 30, 24], // 22
635    [30, 28, 30, 30], // 23
636    [30, 28, 30, 30], // 24
637    [26, 28, 30, 30], // 25
638    [28, 28, 28, 30], // 26
639    [30, 28, 30, 30], // 27
640    [30, 28, 30, 30], // 28
641    [30, 28, 30, 30], // 29
642    [30, 28, 30, 30], // 30
643    [30, 28, 30, 30], // 31
644    [30, 28, 30, 30], // 32
645    [30, 28, 30, 30], // 33
646    [30, 28, 30, 30], // 34
647    [30, 28, 30, 30], // 35
648    [30, 28, 30, 30], // 36
649    [30, 28, 30, 30], // 37
650    [30, 28, 30, 30], // 38
651    [30, 28, 30, 30], // 39
652    [30, 28, 30, 30], // 40
653    // Micro versions.
654    [2, 0, 0, 0],   // M1
655    [5, 6, 0, 0],   // M2
656    [6, 8, 0, 0],   // M3
657    [8, 10, 14, 0], // M4
658];
659
660/// `DATA_BYTES_PER_BLOCK` provides the number of codewords (bytes) used for
661/// real data per block in each version.
662///
663/// This is a copy of ISO/IEC 18004:2006, §6.5.1, Table 9 (The value "k" of the
664/// 7th column, followed by the 6th column).
665///
666/// Every entry is a 4-tuple. Take `DATA_BYTES_PER_BLOCK[39][3] == (15, 20, 16, 61)`
667/// as an example, this means in version 40 with correction level H, there are
668/// 20 blocks with 15 bytes in size, and 61 blocks with 16 bytes in size.
669static DATA_BYTES_PER_BLOCK: [[(usize, usize, usize, usize); 4]; 44] = [
670    // Normal versions.
671    [(19, 1, 0, 0), (16, 1, 0, 0), (13, 1, 0, 0), (9, 1, 0, 0)], // 1
672    [(34, 1, 0, 0), (28, 1, 0, 0), (22, 1, 0, 0), (16, 1, 0, 0)], // 2
673    [(55, 1, 0, 0), (44, 1, 0, 0), (17, 2, 0, 0), (13, 2, 0, 0)], // 3
674    [(80, 1, 0, 0), (32, 2, 0, 0), (24, 2, 0, 0), (9, 4, 0, 0)], // 4
675    [(108, 1, 0, 0), (43, 2, 0, 0), (15, 2, 16, 2), (11, 2, 12, 2)], // 5
676    [(68, 2, 0, 0), (27, 4, 0, 0), (19, 4, 0, 0), (15, 4, 0, 0)], // 6
677    [(78, 2, 0, 0), (31, 4, 0, 0), (14, 2, 15, 4), (13, 4, 14, 1)], // 7
678    [(97, 2, 0, 0), (38, 2, 39, 2), (18, 4, 19, 2), (14, 4, 15, 2)], // 8
679    [(116, 2, 0, 0), (36, 3, 37, 2), (16, 4, 17, 4), (12, 4, 13, 4)], // 9
680    [(68, 2, 69, 2), (43, 4, 44, 1), (19, 6, 20, 2), (15, 6, 16, 2)], // 10
681    [(81, 4, 0, 0), (50, 1, 51, 4), (22, 4, 23, 4), (12, 3, 13, 8)], // 11
682    [(92, 2, 93, 2), (36, 6, 37, 2), (20, 4, 21, 6), (14, 7, 15, 4)], // 12
683    [(107, 4, 0, 0), (37, 8, 38, 1), (20, 8, 21, 4), (11, 12, 12, 4)], // 13
684    [(115, 3, 116, 1), (40, 4, 41, 5), (16, 11, 17, 5), (12, 11, 13, 5)], // 14
685    [(87, 5, 88, 1), (41, 5, 42, 5), (24, 5, 25, 7), (12, 11, 13, 7)], // 15
686    [(98, 5, 99, 1), (45, 7, 46, 3), (19, 15, 20, 2), (15, 3, 16, 13)], // 16
687    [(107, 1, 108, 5), (46, 10, 47, 1), (22, 1, 23, 15), (14, 2, 15, 17)], // 17
688    [(120, 5, 121, 1), (43, 9, 44, 4), (22, 17, 23, 1), (14, 2, 15, 19)], // 18
689    [(113, 3, 114, 4), (44, 3, 45, 11), (21, 17, 22, 4), (13, 9, 14, 16)], // 19
690    [(107, 3, 108, 5), (41, 3, 42, 13), (24, 15, 25, 5), (15, 15, 16, 10)], // 20
691    [(116, 4, 117, 4), (42, 17, 0, 0), (22, 17, 23, 6), (16, 19, 17, 6)], // 21
692    [(111, 2, 112, 7), (46, 17, 0, 0), (24, 7, 25, 16), (13, 34, 0, 0)], // 22
693    [(121, 4, 122, 5), (47, 4, 48, 14), (24, 11, 25, 14), (15, 16, 16, 14)], // 23
694    [(117, 6, 118, 4), (45, 6, 46, 14), (24, 11, 25, 16), (16, 30, 17, 2)], // 24
695    [(106, 8, 107, 4), (47, 8, 48, 13), (24, 7, 25, 22), (15, 22, 16, 13)], // 25
696    [(114, 10, 115, 2), (46, 19, 47, 4), (22, 28, 23, 6), (16, 33, 17, 4)], // 26
697    [(122, 8, 123, 4), (45, 22, 46, 3), (23, 8, 24, 26), (15, 12, 16, 28)], // 27
698    [(117, 3, 118, 10), (45, 3, 46, 23), (24, 4, 25, 31), (15, 11, 16, 31)], // 28
699    [(116, 7, 117, 7), (45, 21, 46, 7), (23, 1, 24, 37), (15, 19, 16, 26)], // 29
700    [(115, 5, 116, 10), (47, 19, 48, 10), (24, 15, 25, 25), (15, 23, 16, 25)], // 30
701    [(115, 13, 116, 3), (46, 2, 47, 29), (24, 42, 25, 1), (15, 23, 16, 28)], // 31
702    [(115, 17, 0, 0), (46, 10, 47, 23), (24, 10, 25, 35), (15, 19, 16, 35)], // 32
703    [(115, 17, 116, 1), (46, 14, 47, 21), (24, 29, 25, 19), (15, 11, 16, 46)], // 33
704    [(115, 13, 116, 6), (46, 14, 47, 23), (24, 44, 25, 7), (16, 59, 17, 1)], // 34
705    [(121, 12, 122, 7), (47, 12, 48, 26), (24, 39, 25, 14), (15, 22, 16, 41)], // 35
706    [(121, 6, 122, 14), (47, 6, 48, 34), (24, 46, 25, 10), (15, 2, 16, 64)], // 36
707    [(122, 17, 123, 4), (46, 29, 47, 14), (24, 49, 25, 10), (15, 24, 16, 46)], // 37
708    [(122, 4, 123, 18), (46, 13, 47, 32), (24, 48, 25, 14), (15, 42, 16, 32)], // 38
709    [(117, 20, 118, 4), (47, 40, 48, 7), (24, 43, 25, 22), (15, 10, 16, 67)], // 39
710    [(118, 19, 119, 6), (47, 18, 48, 31), (24, 34, 25, 34), (15, 20, 16, 61)], // 40
711    // Micro versions.
712    [(3, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M1
713    [(5, 1, 0, 0), (4, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M2
714    [(11, 1, 0, 0), (9, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M3
715    [(16, 1, 0, 0), (14, 1, 0, 0), (10, 1, 0, 0), (0, 0, 0, 0)], // M4
716];
717
718//}}}