Universal
This commit is contained in:
@@ -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)!
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user