Add command-line tool and tests.

This commit is contained in:
Zoltan Szabadka 2014-10-30 13:59:37 +01:00
parent 6b9ce4dfab
commit e1739826c0
16 changed files with 26285 additions and 0 deletions

10
dec/Makefile Normal file
View File

@ -0,0 +1,10 @@
#brotli/dec
include ../shared.mk
OBJS = bit_reader.o decode.o huffman.o safe_malloc.o streams.o
all : $(OBJS)
clean :
rm -f $(OBJS)

11
enc/Makefile Normal file
View File

@ -0,0 +1,11 @@
#brotli/enc
include ../shared.mk
OBJS = backward_references.o block_splitter.o brotli_bit_stream.o encode.o entropy_encode.o histogram.o literal_cost.o
all : $(OBJS)
clean :
rm -f $(OBJS) $(SO)

16
shared.mk Normal file
View File

@ -0,0 +1,16 @@
OS := $(shell uname)
GFLAGS=-no-canonical-prefixes -fno-omit-frame-pointer -m64
CPP = g++
LFLAGS =
CPPFLAGS = -c -std=c++0x $(GFLAGS)
ifeq ($(OS), Darwin)
CPPFLAGS += -DOS_MACOSX
else
CPPFLAGS += -fno-tree-vrp
endif
%.o : %.c
$(CPP) $(CPPFLAGS) $< -o $@

19
tests/Makefile Normal file
View File

@ -0,0 +1,19 @@
#brotli/tests
include ../shared.mk
BROTLI = ..
all: test
test: deps
./compatibility_test.sh
./roundtrip_test.sh
deps :
make -C $(BROTLI)/tools
clean :
rm -f testdata/*.{bro,unbro,uncompressed}
rm -f $(BROTLI)/{enc,dec,tools}/*.{un,}bro
make -C $(BROTLI)/tools clean

23
tests/compatibility_test.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash
#
# Test that the brotli command-line tool can decompress old brotli-compressed
# files.
set -o errexit
BRO=../tools/bro
INPUTS="""
testdata/alice29.txt.compressed
testdata/asyoulik.txt.compressed
testdata/lcet10.txt.compressed
testdata/plrabn12.txt.compressed
"""
for file in $INPUTS; do
echo "Testing decompression of file $file"
uncompressed=${file%.compressed}.uncompressed
expected=${file%.compressed}
$BRO -f -d -i $file -o $uncompressed
diff -q $uncompressed $expected
done

26
tests/roundtrip_test.sh Executable file
View File

@ -0,0 +1,26 @@
#!/bin/bash
#
# Roundtrip test for the brotli command-line tool.
set -o errexit
BRO=../tools/bro
INPUTS="""
testdata/alice29.txt
testdata/asyoulik.txt
testdata/lcet10.txt
testdata/plrabn12.txt
../enc/encode.cc
../enc/dictionary.h
../dec/decode.c
$BRO
"""
for file in $INPUTS; do
echo "Roundtrip testing $file"
compressed=${file}.bro
uncompressed=${file}.unbro
$BRO -f -i $file -o $compressed
$BRO -f -d -i $compressed -o $uncompressed
diff -q $file $uncompressed
done

3609
tests/testdata/alice29.txt vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
tests/testdata/alice29.txt.compressed vendored Normal file

Binary file not shown.

4122
tests/testdata/asyoulik.txt vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
tests/testdata/asyoulik.txt.compressed vendored Normal file

Binary file not shown.

7519
tests/testdata/lcet10.txt vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
tests/testdata/lcet10.txt.compressed vendored Normal file

Binary file not shown.

10699
tests/testdata/plrabn12.txt vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
tests/testdata/plrabn12.txt.compressed vendored Normal file

Binary file not shown.

25
tools/Makefile Normal file
View File

@ -0,0 +1,25 @@
#brotli/tools
include ../shared.mk
BROTLI = ..
ENCOBJ = $(BROTLI)/enc/*.o
DECOBJ = $(BROTLI)/dec/*.o
EXECUTABLES=bro
EXE_OBJS=$(patsubst %, %.o, $(EXECUTABLES))
all : $(EXECUTABLES)
$(EXECUTABLES) : $(EXE_OBJS) deps
$(CPP) $(LFLAGS) $(ENCOBJ) $(DECOBJ) $@.o -o $@
deps :
make -C $(BROTLI)/dec
make -C $(BROTLI)/enc
clean :
rm -f $(OBJS) $(EXE_OBJS) $(EXECUTABLES)
make -C $(BROTLI)/dec clean
make -C $(BROTLI)/enc clean

206
tools/bro.cc Normal file
View File

@ -0,0 +1,206 @@
/* Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Example main() function for Brotli library.
*/
#include <fcntl.h>
#include <malloc.h>
#include <stdio.h>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "../dec/decode.h"
#include "../enc/encode.h"
/* The returned pointer must be freed by the caller. */
char *ReadFile(const char *path, size_t *file_size) {
FILE *fp = fopen(path, "rb");
if (!fp) {
perror("fopen");
exit(1);
}
if (fseek(fp, 0, SEEK_END) != 0) {
perror("fseek");
exit(1);
}
*file_size = ftell(fp);
if (*file_size == (size_t) -1) {
perror("ftell");
exit(1);
}
if (fseek(fp, 0, SEEK_SET) != 0) {
perror("fseek");
exit(1);
}
char *retval = (char *)malloc(*file_size + 1);
if (!retval) {
perror("malloc");
exit(1);
}
if (fread(retval, *file_size, 1, fp) != 1) {
perror("fread");
exit(1);
}
if (fclose(fp) != 0) {
perror("fclose");
exit(1);
}
retval[*file_size] = 0;
return retval;
}
static void ParseArgv(int argc, char **argv,
char **input_path,
char **output_path,
int *force,
int *decompress) {
*force = 0;
*input_path = 0;
*output_path = 0;
{
size_t argv0_len = strlen(argv[0]);
*decompress =
argv0_len >= 5 && strcmp(&argv[0][argv0_len - 5], "unbro") == 0;
}
for (int k = 1; k < argc; ++k) {
if (!strcmp("--force", argv[k]) ||
!strcmp("-f", argv[k])) {
if (*force != 0) {
goto error;
}
*force = 1;
continue;
} else if (!strcmp("--decompress", argv[k]) ||
!strcmp("--uncompress", argv[k]) ||
!strcmp("-d", argv[k])) {
*decompress = 1;
continue;
}
if (k < argc - 1) {
if (!strcmp("--input", argv[k]) ||
!strcmp("-i", argv[k])) {
if (*input_path != 0) {
goto error;
}
*input_path = argv[k + 1];
++k;
continue;
} else if (!strcmp("--output", argv[k]) ||
!strcmp("-o", argv[k])) {
if (*output_path != 0) {
goto error;
}
*output_path = argv[k + 1];
++k;
continue;
}
}
goto error;
}
if (!*input_path) {
fprintf(stderr, "missing --input argument");
goto error;
}
if (!*output_path) {
fprintf(stderr, "missing --output argument");
goto error;
}
return;
error:
fprintf(stderr,
"Usage: %s [--force] [--decompress]"
" --input filename --output filename\n",
argv[0]);
exit(1);
}
static FILE *OpenOutputFile(const char *output_path, const int force) {
if (!force) {
struct stat statbuf;
if (stat(output_path, &statbuf) == 0) {
fprintf(stderr, "output file exists\n");
exit(1);
}
}
int fd = open(output_path, O_CREAT | O_WRONLY | O_TRUNC,
S_IRUSR | S_IWUSR);
if (fd < 0) {
perror("open");
exit(1);
}
return fdopen(fd, "wb");
}
int main(int argc, char** argv) {
char *input_path = 0;
char *output_path = 0;
int force = 0;
int decompress = 0;
ParseArgv(argc, argv, &input_path, &output_path, &force, &decompress);
FILE* fout = OpenOutputFile(output_path, force);
size_t input_size = 0;
char *input = ReadFile(input_path, &input_size);
if (decompress) {
BrotliOutput out;
BrotliMemInput memin;
BrotliInput in =
BrotliInitMemInput(reinterpret_cast<const uint8_t*>(input),
input_size, &memin);
out = BrotliFileOutput(fout);
if (!BrotliDecompress(in, out)) {
fprintf(stderr, "corrupt input\n");
exit(1);
}
} else {
const int max_block_size = 1 << 21;
const size_t max_output_size = 1 << 22;
uint8_t* output_buffer = new uint8_t[max_output_size];
const uint8_t* input_buffer = NULL;
size_t input_pos = 0;
bool input_end = false;
int block_size;
input_buffer = reinterpret_cast<const uint8_t*>(input);
brotli::BrotliParams params;
brotli::BrotliCompressor compressor(params);
compressor.WriteStreamHeader();
while (!input_end) {
block_size = max_block_size;
if (block_size >= input_size - input_pos) {
block_size = input_size - input_pos;
input_end = true;
}
size_t output_size = max_output_size;
compressor.WriteMetaBlock(block_size, input_buffer + input_pos,
input_end,
&output_size, output_buffer);
if (fwrite(output_buffer, output_size, 1, fout) != 1) {
perror("fwrite");
unlink(output_path);
exit(1);
}
input_pos += block_size;
}
delete[] output_buffer;
}
if (fclose(fout) != 0) {
perror("fclose");
exit(1);
}
free(input);
return 0;
}