xref: /aosp_15_r20/external/brotli/python/bro.py (revision f4ee7fba7774faf2a30f13154332c0a06550dbc4)
1*f4ee7fbaSAndroid Build Coastguard Worker#! /usr/bin/env python
2*f4ee7fbaSAndroid Build Coastguard Worker"""Compression/decompression utility using the Brotli algorithm."""
3*f4ee7fbaSAndroid Build Coastguard Worker
4*f4ee7fbaSAndroid Build Coastguard Workerfrom __future__ import print_function
5*f4ee7fbaSAndroid Build Coastguard Workerimport argparse
6*f4ee7fbaSAndroid Build Coastguard Workerimport sys
7*f4ee7fbaSAndroid Build Coastguard Workerimport os
8*f4ee7fbaSAndroid Build Coastguard Workerimport platform
9*f4ee7fbaSAndroid Build Coastguard Worker
10*f4ee7fbaSAndroid Build Coastguard Workerimport brotli
11*f4ee7fbaSAndroid Build Coastguard Worker
12*f4ee7fbaSAndroid Build Coastguard Worker# default values of encoder parameters
13*f4ee7fbaSAndroid Build Coastguard WorkerDEFAULT_PARAMS = {
14*f4ee7fbaSAndroid Build Coastguard Worker    'mode': brotli.MODE_GENERIC,
15*f4ee7fbaSAndroid Build Coastguard Worker    'quality': 11,
16*f4ee7fbaSAndroid Build Coastguard Worker    'lgwin': 22,
17*f4ee7fbaSAndroid Build Coastguard Worker    'lgblock': 0,
18*f4ee7fbaSAndroid Build Coastguard Worker}
19*f4ee7fbaSAndroid Build Coastguard Worker
20*f4ee7fbaSAndroid Build Coastguard Worker
21*f4ee7fbaSAndroid Build Coastguard Workerdef get_binary_stdio(stream):
22*f4ee7fbaSAndroid Build Coastguard Worker    """ Return the specified standard input, output or errors stream as a
23*f4ee7fbaSAndroid Build Coastguard Worker    'raw' buffer object suitable for reading/writing binary data from/to it.
24*f4ee7fbaSAndroid Build Coastguard Worker    """
25*f4ee7fbaSAndroid Build Coastguard Worker    assert stream in ['stdin', 'stdout', 'stderr'], 'invalid stream name'
26*f4ee7fbaSAndroid Build Coastguard Worker    stdio = getattr(sys, stream)
27*f4ee7fbaSAndroid Build Coastguard Worker    if sys.version_info[0] < 3:
28*f4ee7fbaSAndroid Build Coastguard Worker        if sys.platform == 'win32':
29*f4ee7fbaSAndroid Build Coastguard Worker            # set I/O stream binary flag on python2.x (Windows)
30*f4ee7fbaSAndroid Build Coastguard Worker            runtime = platform.python_implementation()
31*f4ee7fbaSAndroid Build Coastguard Worker            if runtime == 'PyPy':
32*f4ee7fbaSAndroid Build Coastguard Worker                # the msvcrt trick doesn't work in pypy, so I use fdopen
33*f4ee7fbaSAndroid Build Coastguard Worker                mode = 'rb' if stream == 'stdin' else 'wb'
34*f4ee7fbaSAndroid Build Coastguard Worker                stdio = os.fdopen(stdio.fileno(), mode, 0)
35*f4ee7fbaSAndroid Build Coastguard Worker            else:
36*f4ee7fbaSAndroid Build Coastguard Worker                # this works with CPython -- untested on other implementations
37*f4ee7fbaSAndroid Build Coastguard Worker                import msvcrt
38*f4ee7fbaSAndroid Build Coastguard Worker                msvcrt.setmode(stdio.fileno(), os.O_BINARY)
39*f4ee7fbaSAndroid Build Coastguard Worker        return stdio
40*f4ee7fbaSAndroid Build Coastguard Worker    else:
41*f4ee7fbaSAndroid Build Coastguard Worker        # get 'buffer' attribute to read/write binary data on python3.x
42*f4ee7fbaSAndroid Build Coastguard Worker        if hasattr(stdio, 'buffer'):
43*f4ee7fbaSAndroid Build Coastguard Worker            return stdio.buffer
44*f4ee7fbaSAndroid Build Coastguard Worker        else:
45*f4ee7fbaSAndroid Build Coastguard Worker            orig_stdio = getattr(sys, '__%s__' % stream)
46*f4ee7fbaSAndroid Build Coastguard Worker            return orig_stdio.buffer
47*f4ee7fbaSAndroid Build Coastguard Worker
48*f4ee7fbaSAndroid Build Coastguard Worker
49*f4ee7fbaSAndroid Build Coastguard Workerdef main(args=None):
50*f4ee7fbaSAndroid Build Coastguard Worker
51*f4ee7fbaSAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(
52*f4ee7fbaSAndroid Build Coastguard Worker        prog=os.path.basename(__file__), description=__doc__)
53*f4ee7fbaSAndroid Build Coastguard Worker    parser.add_argument(
54*f4ee7fbaSAndroid Build Coastguard Worker        '--version', action='version', version=brotli.__version__)
55*f4ee7fbaSAndroid Build Coastguard Worker    parser.add_argument(
56*f4ee7fbaSAndroid Build Coastguard Worker        '-i',
57*f4ee7fbaSAndroid Build Coastguard Worker        '--input',
58*f4ee7fbaSAndroid Build Coastguard Worker        metavar='FILE',
59*f4ee7fbaSAndroid Build Coastguard Worker        type=str,
60*f4ee7fbaSAndroid Build Coastguard Worker        dest='infile',
61*f4ee7fbaSAndroid Build Coastguard Worker        help='Input file',
62*f4ee7fbaSAndroid Build Coastguard Worker        default=None)
63*f4ee7fbaSAndroid Build Coastguard Worker    parser.add_argument(
64*f4ee7fbaSAndroid Build Coastguard Worker        '-o',
65*f4ee7fbaSAndroid Build Coastguard Worker        '--output',
66*f4ee7fbaSAndroid Build Coastguard Worker        metavar='FILE',
67*f4ee7fbaSAndroid Build Coastguard Worker        type=str,
68*f4ee7fbaSAndroid Build Coastguard Worker        dest='outfile',
69*f4ee7fbaSAndroid Build Coastguard Worker        help='Output file',
70*f4ee7fbaSAndroid Build Coastguard Worker        default=None)
71*f4ee7fbaSAndroid Build Coastguard Worker    parser.add_argument(
72*f4ee7fbaSAndroid Build Coastguard Worker        '-f',
73*f4ee7fbaSAndroid Build Coastguard Worker        '--force',
74*f4ee7fbaSAndroid Build Coastguard Worker        action='store_true',
75*f4ee7fbaSAndroid Build Coastguard Worker        help='Overwrite existing output file',
76*f4ee7fbaSAndroid Build Coastguard Worker        default=False)
77*f4ee7fbaSAndroid Build Coastguard Worker    parser.add_argument(
78*f4ee7fbaSAndroid Build Coastguard Worker        '-d',
79*f4ee7fbaSAndroid Build Coastguard Worker        '--decompress',
80*f4ee7fbaSAndroid Build Coastguard Worker        action='store_true',
81*f4ee7fbaSAndroid Build Coastguard Worker        help='Decompress input file',
82*f4ee7fbaSAndroid Build Coastguard Worker        default=False)
83*f4ee7fbaSAndroid Build Coastguard Worker    params = parser.add_argument_group('optional encoder parameters')
84*f4ee7fbaSAndroid Build Coastguard Worker    params.add_argument(
85*f4ee7fbaSAndroid Build Coastguard Worker        '-m',
86*f4ee7fbaSAndroid Build Coastguard Worker        '--mode',
87*f4ee7fbaSAndroid Build Coastguard Worker        metavar='MODE',
88*f4ee7fbaSAndroid Build Coastguard Worker        type=int,
89*f4ee7fbaSAndroid Build Coastguard Worker        choices=[0, 1, 2],
90*f4ee7fbaSAndroid Build Coastguard Worker        help='The compression mode can be 0 for generic input, '
91*f4ee7fbaSAndroid Build Coastguard Worker        '1 for UTF-8 encoded text, or 2 for WOFF 2.0 font data. '
92*f4ee7fbaSAndroid Build Coastguard Worker        'Defaults to 0.')
93*f4ee7fbaSAndroid Build Coastguard Worker    params.add_argument(
94*f4ee7fbaSAndroid Build Coastguard Worker        '-q',
95*f4ee7fbaSAndroid Build Coastguard Worker        '--quality',
96*f4ee7fbaSAndroid Build Coastguard Worker        metavar='QUALITY',
97*f4ee7fbaSAndroid Build Coastguard Worker        type=int,
98*f4ee7fbaSAndroid Build Coastguard Worker        choices=list(range(0, 12)),
99*f4ee7fbaSAndroid Build Coastguard Worker        help='Controls the compression-speed vs compression-density '
100*f4ee7fbaSAndroid Build Coastguard Worker        'tradeoff. The higher the quality, the slower the '
101*f4ee7fbaSAndroid Build Coastguard Worker        'compression. Range is 0 to 11. Defaults to 11.')
102*f4ee7fbaSAndroid Build Coastguard Worker    params.add_argument(
103*f4ee7fbaSAndroid Build Coastguard Worker        '--lgwin',
104*f4ee7fbaSAndroid Build Coastguard Worker        metavar='LGWIN',
105*f4ee7fbaSAndroid Build Coastguard Worker        type=int,
106*f4ee7fbaSAndroid Build Coastguard Worker        choices=list(range(10, 25)),
107*f4ee7fbaSAndroid Build Coastguard Worker        help='Base 2 logarithm of the sliding window size. Range is '
108*f4ee7fbaSAndroid Build Coastguard Worker        '10 to 24. Defaults to 22.')
109*f4ee7fbaSAndroid Build Coastguard Worker    params.add_argument(
110*f4ee7fbaSAndroid Build Coastguard Worker        '--lgblock',
111*f4ee7fbaSAndroid Build Coastguard Worker        metavar='LGBLOCK',
112*f4ee7fbaSAndroid Build Coastguard Worker        type=int,
113*f4ee7fbaSAndroid Build Coastguard Worker        choices=[0] + list(range(16, 25)),
114*f4ee7fbaSAndroid Build Coastguard Worker        help='Base 2 logarithm of the maximum input block size. '
115*f4ee7fbaSAndroid Build Coastguard Worker        'Range is 16 to 24. If set to 0, the value will be set based '
116*f4ee7fbaSAndroid Build Coastguard Worker        'on the quality. Defaults to 0.')
117*f4ee7fbaSAndroid Build Coastguard Worker    # set default values using global DEFAULT_PARAMS dictionary
118*f4ee7fbaSAndroid Build Coastguard Worker    parser.set_defaults(**DEFAULT_PARAMS)
119*f4ee7fbaSAndroid Build Coastguard Worker
120*f4ee7fbaSAndroid Build Coastguard Worker    options = parser.parse_args(args=args)
121*f4ee7fbaSAndroid Build Coastguard Worker
122*f4ee7fbaSAndroid Build Coastguard Worker    if options.infile:
123*f4ee7fbaSAndroid Build Coastguard Worker        if not os.path.isfile(options.infile):
124*f4ee7fbaSAndroid Build Coastguard Worker            parser.error('file "%s" not found' % options.infile)
125*f4ee7fbaSAndroid Build Coastguard Worker        with open(options.infile, 'rb') as infile:
126*f4ee7fbaSAndroid Build Coastguard Worker            data = infile.read()
127*f4ee7fbaSAndroid Build Coastguard Worker    else:
128*f4ee7fbaSAndroid Build Coastguard Worker        if sys.stdin.isatty():
129*f4ee7fbaSAndroid Build Coastguard Worker            # interactive console, just quit
130*f4ee7fbaSAndroid Build Coastguard Worker            parser.error('no input')
131*f4ee7fbaSAndroid Build Coastguard Worker        infile = get_binary_stdio('stdin')
132*f4ee7fbaSAndroid Build Coastguard Worker        data = infile.read()
133*f4ee7fbaSAndroid Build Coastguard Worker
134*f4ee7fbaSAndroid Build Coastguard Worker    if options.outfile:
135*f4ee7fbaSAndroid Build Coastguard Worker        if os.path.isfile(options.outfile) and not options.force:
136*f4ee7fbaSAndroid Build Coastguard Worker            parser.error('output file exists')
137*f4ee7fbaSAndroid Build Coastguard Worker        outfile = open(options.outfile, 'wb')
138*f4ee7fbaSAndroid Build Coastguard Worker    else:
139*f4ee7fbaSAndroid Build Coastguard Worker        outfile = get_binary_stdio('stdout')
140*f4ee7fbaSAndroid Build Coastguard Worker
141*f4ee7fbaSAndroid Build Coastguard Worker    try:
142*f4ee7fbaSAndroid Build Coastguard Worker        if options.decompress:
143*f4ee7fbaSAndroid Build Coastguard Worker            data = brotli.decompress(data)
144*f4ee7fbaSAndroid Build Coastguard Worker        else:
145*f4ee7fbaSAndroid Build Coastguard Worker            data = brotli.compress(
146*f4ee7fbaSAndroid Build Coastguard Worker                data,
147*f4ee7fbaSAndroid Build Coastguard Worker                mode=options.mode,
148*f4ee7fbaSAndroid Build Coastguard Worker                quality=options.quality,
149*f4ee7fbaSAndroid Build Coastguard Worker                lgwin=options.lgwin,
150*f4ee7fbaSAndroid Build Coastguard Worker                lgblock=options.lgblock)
151*f4ee7fbaSAndroid Build Coastguard Worker    except brotli.error as e:
152*f4ee7fbaSAndroid Build Coastguard Worker        parser.exit(1,
153*f4ee7fbaSAndroid Build Coastguard Worker                    'bro: error: %s: %s' % (e, options.infile or 'sys.stdin'))
154*f4ee7fbaSAndroid Build Coastguard Worker
155*f4ee7fbaSAndroid Build Coastguard Worker    outfile.write(data)
156*f4ee7fbaSAndroid Build Coastguard Worker    outfile.close()
157*f4ee7fbaSAndroid Build Coastguard Worker
158*f4ee7fbaSAndroid Build Coastguard Worker
159*f4ee7fbaSAndroid Build Coastguard Workerif __name__ == '__main__':
160*f4ee7fbaSAndroid Build Coastguard Worker    main()
161