Universal

This commit is contained in:
2026-07-12 03:38:18 +02:00
parent b6964c7943
commit da1755e78e
+202 -54
View File
@@ -25,6 +25,12 @@ fn write_lsb(mut b Bits, value u8, length u8) {
} }
} }
fn write_lsb16(mut b Bits, value u16, length u8) {
for i in 0..length {
write(mut b, u8((value >> i) & 1))
}
}
fn write_msb(mut b Bits, code u16, length u16) { fn write_msb(mut b Bits, code u16, length u16) {
mut i := int(length) - 1 mut i := int(length) - 1
for i >= 0 { for i >= 0 {
@@ -73,63 +79,132 @@ fn write_deflate_header(mut b Bits) {
write_lsb(mut b, 0x01, 2) write_lsb(mut b, 0x01, 2)
} }
fn write_foferk(mut b Bits) { fn write_text(mut b Bits, text string) {
write_msb(mut b, 0x96, 8) for byte in text.bytes() {
write_msb(mut b, 0x9f, 8) if byte <= 143 {
write_msb(mut b, 0x96, 8) write_msb(mut b, u16(byte) + 48, 8)
write_msb(mut b, 0x95, 8) } else {
write_msb(mut b, 0xA2, 8) write_msb(mut b, u16(byte) + 256, 9)
write_msb(mut b, 0x9b, 8) }
write_msb(mut b, 0x50, 8)
}
fn write_tokens(mut b Bits, repeat int) {
mut remaining := (repeat - 1) * 7
for remaining >= 252 {
write_msb(mut b, 0xC4, 8)
write_lsb(mut b, 25, 5)
write_msb(mut b, 0x05, 5)
write_lsb(mut b, 0x00, 1)
remaining -= 252
}
for remaining >= 7 {
write_msb(mut b, 0x05, 7)
write_msb(mut b, 0x05, 5)
write_lsb(mut b, 0x00, 1)
remaining -= 7
}
if remaining == 6 {
write_msb(mut b, 0x04, 7)
write_msb(mut b, 0x05, 5)
write_lsb(mut b, 0x00, 1)
} else if remaining == 5 {
write_msb(mut b, 0x03, 7)
write_msb(mut b, 0x05, 5)
write_lsb(mut b, 0x00, 1)
} else if remaining == 4 {
write_msb(mut b, 0x02, 7)
write_msb(mut b, 0x05, 5)
write_lsb(mut b, 0x00, 1)
} else if remaining == 3 {
write_msb(mut b, 0x01, 7)
write_msb(mut b, 0x05, 5)
write_lsb(mut b, 0x00, 1)
} }
} }
fn write_footer(mut b Bits, repeat int) { fn get_distance_code(dist int) (u16, u8, u16) {
if dist <= 4 {
return u16(dist - 1), 0, 0
}
mut c := u16(4)
mut extra_bits := u8(1)
mut base := 5
for {
if dist < base + (1 << extra_bits) {
return c, extra_bits, u16(dist - base)
}
base += (1 << extra_bits)
c++
if dist < base + (1 << extra_bits) {
return c, extra_bits, u16(dist - base)
}
base += (1 << extra_bits)
c++
extra_bits++
}
return 0, 0, 0
}
fn get_length_code(length int) (u16, u8, u16) {
if length == 258 {
return 285, 0, 0
}
if length <= 10 {
return u16(257 + length - 3), 0, 0
}
mut c := u16(265)
mut extra_bits := u8(1)
mut base := 11
for {
for _ in 0..4 {
if length < base + (1 << extra_bits) {
return c, extra_bits, u16(length - base)
}
base += (1 << extra_bits)
c++
if c >= 285 {
return 285, 0, 0
}
}
extra_bits++
}
return 285, 0, 0
}
fn write_tokens(mut b Bits, repeat int, text string) {
if repeat <= 1 || text.len == 0 {
return
}
if text.len > 32768 {
for _ in 0..(repeat - 1) {
write_text(mut b, text)
}
return
}
mut remaining := (repeat - 1) * text.len
dist_code, dist_extra_bits, dist_extra_val := get_distance_code(text.len)
for remaining > 0 {
mut length := 258
if remaining < 258 {
length = remaining
}
len_code, len_extra_bits, len_extra_val := get_length_code(length)
if len_code <= 279 {
write_msb(mut b, len_code - 256, 7)
} else {
write_msb(mut b, len_code - 280 + 192, 8)
}
if len_extra_bits > 0 {
write_lsb16(mut b, len_extra_val, len_extra_bits)
}
write_msb(mut b, dist_code, 5)
if dist_extra_bits > 0 {
write_lsb16(mut b, dist_extra_val, dist_extra_bits)
}
remaining -= length
}
}
fn write_footer(mut b Bits, repeat int, text string) {
write_msb(mut b, 0x00, 7) write_msb(mut b, 0x00, 7)
flush(mut b) flush(mut b)
write_u32(mut b, crc32(repeat)) write_u32(mut b, crc32(repeat, text))
write_u32(mut b, u32(repeat * 7)) write_u32(mut b, u32(repeat * text.len))
} }
// CRC32 // CRC32
fn crc32(repeat int) u32 { fn crc32(repeat int, text string) u32 {
mut table := []u32{len: 256} mut table := []u32{len: 256}
for i in 0..256 { for i in 0..256 {
mut c := u32(i) mut c := u32(i)
@@ -145,16 +220,89 @@ fn crc32(repeat int) u32 {
} }
mut crc := u32(0xffffffff) mut crc := u32(0xffffffff)
bytes := text.bytes()
for _ in 0..repeat { for _ in 0..repeat {
for byte in "foferk ".bytes() { for byte in bytes {
crc = table[(crc ^ u32(byte)) & 0xFF] ^ (crc >> 8) crc = table[(crc ^ u32(byte)) & 0xFF] ^ (crc >> 8)
} }
} }
return crc ^ 0xffffffff return crc ^ 0xffffffff
} }
// STDIN
fn read_stdin() string {
mut lines := ''
for {
line := os.get_line()
if line.len == 0 && os.stdin().eof() {
break
}
lines += line + '\n'
}
return lines
}
// ARGS
fn parse_args(text string, repeat int, file string) (string, int, string) {
mut text_ := text
mut repeat_ := repeat
mut file_ := file
args := os.args[1..]
if '-h' in args || '--help' in args {
println("Usage: foferk [options]")
println("")
println("Options:")
println(" -t, --text <text>")
println(" -r, --repeat <count>")
println(" -f, --file <path>")
println(" -h, --help")
println("")
exit(0)
}
mut next := -1
for arg in args {
if arg == '-t' || arg == '--text' {
next = 0
} else if arg == '-r' || arg == '--repeat' {
next = 1
} else if arg == '-f' || arg == '--file' {
next = 2
} else {
if next == 0 {
text_ = arg
next = -1
} else if next == 1 {
repeat_ = arg.int()
next = -1
} else if next == 2 {
file_ = arg
next = -1
}
}
}
return text_, repeat_, file_
}
fn main() { fn main() {
repeat := 1_000_000 mut text := 'foferk'
mut repeat := 1_000
mut file := 'foferk.gz'
if os.is_atty(0) == 0 {
text = read_stdin()
}
text, repeat, file = parse_args(text, repeat, file)
text += ' '
mut b := Bits { mut b := Bits {
bytes: []u8{} bytes: []u8{}
current: 0 current: 0
@@ -163,9 +311,9 @@ fn main() {
write_gzip_header(mut b) write_gzip_header(mut b)
write_deflate_header(mut b) write_deflate_header(mut b)
write_foferk(mut b) write_text(mut b, text)
write_tokens(mut b, repeat) write_tokens(mut b, repeat, text)
write_footer(mut b, repeat) write_footer(mut b, repeat, text)
os.write_bytes("foferk.gz", b.bytes)! os.write_bytes(file, b.bytes)!
} }