1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
extern crate brotli;
extern crate core;
use std::env;
use std::io;
use std::io::{Read, Write};
use std::path::Path;
use std::fs::File;
use brotli::concat::{BroCatli, BroCatliResult};
fn usage() {
writeln!(&mut ::std::io::stderr(), "Usage: [-w<window_size>] filename0 filename1 filename2...").unwrap();
}
fn read_no_interrupt<R:Read>(r: &mut R, buf: &mut [u8]) -> Result<usize, io::Error> {
loop {
match r.read(buf) {
Err(e) => {
match e.kind() {
io::ErrorKind::Interrupted => continue,
_ => return Err(e),
}
}
Ok(cur_read) => return Ok(cur_read),
}
}
}
fn write_no_interrupt<W:Write>(w: &mut W, mut buf: &[u8]) -> Result<usize, io::Error> {
let mut total_read = 0usize;
loop {
match w.write(buf) {
Err(e) => {
match e.kind() {
io::ErrorKind::Interrupted => continue,
_ => return Err(e),
}
},
Ok(cur_read) => {
buf = &buf[cur_read..];
total_read += cur_read;
if buf.len() == 0 {
return Ok(total_read);
}
},
}
}
}
fn main() {
let mut window_size: Option<u8> = None;
let mut double_dash = false;
let mut buffer_size = 4096usize;
let mut filenames = Vec::<String>::new();
let mut ostream = io::stdout();
if env::args_os().len() > 1 {
for argument in env::args().skip(1) {
if argument.starts_with("-w") && !double_dash {
window_size = Some(argument.trim_matches('-').trim_matches('w').parse::<i32>().unwrap() as u8);
continue;
}
if argument.starts_with("-bs") && !double_dash {
buffer_size = argument.trim_matches('-').trim_matches('b').trim_matches('s').parse::<usize>().unwrap();
continue;
}
if argument == "--" {
double_dash = true;
continue;
}
filenames.push(argument);
}
} else {
usage();
return;
}
let mut ibuffer = vec![0u8; buffer_size];
let mut obuffer = vec![0u8; buffer_size];
let mut ooffset = 0;
let mut ioffset;
let mut bro_cat_li = match window_size {
Some(ws) => BroCatli::new_with_window_size(ws),
None => BroCatli::new(),
};
for filename in filenames {
bro_cat_li.new_brotli_file();
let mut input_file = match File::open(&Path::new(&filename)) {
Err(why) => panic!("couldn't open {:}\n{:}", filename, why),
Ok(file) => file,
};
loop {
ioffset = 0;
match read_no_interrupt(&mut input_file, &mut ibuffer[..]) {
Err(e) => panic!("{}", e),
Ok(cur_read) => {
if cur_read == 0 {
break;
}
loop {
match bro_cat_li.stream(&ibuffer[..cur_read], &mut ioffset,
&mut obuffer[..], &mut ooffset) {
BroCatliResult::NeedsMoreOutput => {
match write_no_interrupt(&mut ostream, &obuffer[..ooffset]) {
Err(why) => panic!("couldn't write: {:}", why),
Ok(count) => {assert_eq!(count, ooffset);},
}
ooffset = 0;
},
BroCatliResult::NeedsMoreInput => {
break;
},
BroCatliResult::Success => {
panic!("Unexpected state: Success when streaming before finish");
}
failure => {
panic!("Failed to concatenate files on {:} {:?}", filename, failure);
},
}
}
}
}
}
}
loop {
match bro_cat_li.finish(&mut obuffer[..], &mut ooffset) {
BroCatliResult::NeedsMoreOutput => {
match write_no_interrupt(&mut ostream, &obuffer[..ooffset]) {
Err(why) => panic!("couldn't write: {:}", why),
Ok(count) => {assert_eq!(count, ooffset);},
}
ooffset = 0;
},
BroCatliResult::NeedsMoreInput => {
panic!("Unexpected EOF");
},
BroCatliResult::Success => {
if ooffset != 0 {
match write_no_interrupt(&mut ostream, &obuffer[..ooffset]) {
Err(why) => panic!("couldn't write: {:}", why),
Ok(count) => {assert_eq!(count, ooffset);},
}
}
break;
}
failure => {
panic!("{:?}", failure)
}
}
}
}
|