///|
/// ECC codewords per block, indexed by [ec][version]. Index 0 of each row is unused.
let ecc_codewords_per_block : Array[Array[Int32]] = [
// L
[
-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28,
28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30,
],
// M
[
-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26,
26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28,
],
// Q
[
-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26,
30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30,
],
// H
[
-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26,
28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30,
],
]
///|
/// Number of error correction blocks, indexed by [ec][version].
let num_error_correction_blocks : Array[Array[Int32]] = [
// L
[
-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10,
12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25,
],
// M
[
-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17,
18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49,
],
// Q
[
-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23,
23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68,
],
// H
[
-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25,
34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81,
],
]
///|
fn ec_index(ec : EcLevel) -> Int32 {
match ec {
L => 0
M => 1
Q => 2
H => 3
}
}
///|
/// Number of data + ECC modules available for codewords, divided by 8.
/// Derived from ISO Table 1; remainder bits are not counted.
///
/// 可用于码字的数据 + ECC 模块数除以 8。
/// 源自 ISO Table 1;不计余留位。
pub fn total_codewords(version : Int32) -> Int32 {
let mut result = (16 * version + 128) * version + 64
if version >= 2 {
let num_align = version / 7 + 2
result = result - ((25 * num_align - 10) * num_align - 55)
if version >= 7 {
result = result - 36
}
}
result / 8
}
///|
pub fn ecc_codewords(version : Int32, ec : EcLevel) -> Int32 {
ecc_codewords_per_block[ec_index(ec)][version]
}
///|
pub fn block_count(version : Int32, ec : EcLevel) -> Int32 {
num_error_correction_blocks[ec_index(ec)][version]
}
///|
pub fn data_codewords(version : Int32, ec : EcLevel) -> Int32 {
total_codewords(version) -
ecc_codewords(version, ec) * block_count(version, ec)
}
///|
pub fn data_capacity_bits(version : Int32, ec : EcLevel) -> Int32 {
data_codewords(version, ec) * 8
}
///|
pub fn char_count_bits(version : Int32, mode : Mode) -> Int32 {
match mode {
Numeric => if version <= 9 { 10 } else if version <= 26 { 12 } else { 14 }
Alphanumeric =>
if version <= 9 {
9
} else if version <= 26 {
11
} else {
13
}
Byte => if version <= 9 { 8 } else { 16 }
}
}
///|
fn numeric_capacity(bits : Int32) -> Int32 {
if bits <= 0 {
0
} else {
bits / 10 * 3 +
({
let rem = bits % 10
if rem >= 7 {
2
} else if rem >= 4 {
1
} else {
0
}
})
}
}
///|
fn alphanumeric_capacity(bits : Int32) -> Int32 {
if bits <= 0 {
0
} else {
bits / 11 * 2 + (if bits % 11 >= 6 { 1 } else { 0 })
}
}
///|
fn byte_capacity(bits : Int32) -> Int32 {
if bits <= 0 {
0
} else {
bits / 8
}
}
///|
/// Maximum number of characters of the given mode that fit in a version/EC pair.
///
/// 给定版本/纠错等级下,指定模式可容纳的最大字符数。
pub fn character_capacity(version : Int32, ec : EcLevel, mode : Mode) -> Int32 {
let payload = data_capacity_bits(version, ec) -
4 -
char_count_bits(version, mode)
match mode {
Numeric => numeric_capacity(payload)
Alphanumeric => alphanumeric_capacity(payload)
Byte => byte_capacity(payload)
}
}
///|
pub fn Version::total_codewords(self : Version) -> Int32 {
total_codewords(self.0)
}
///|
pub fn Version::data_codewords(self : Version, ec : EcLevel) -> Int32 {
data_codewords(self.0, ec)
}
///|
pub fn Version::data_capacity_bits(self : Version, ec : EcLevel) -> Int32 {
data_capacity_bits(self.0, ec)
}
///|
pub fn Version::char_count_bits(self : Version, mode : Mode) -> Int32 {
char_count_bits(self.0, mode)
}
///|
pub fn Version::character_capacity(
self : Version,
ec : EcLevel,
mode : Mode,
) -> Int32 {
character_capacity(self.0, ec, mode)
}