1 /**************************************************************************
2 *
3 * Copyright 2016 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 **************************************************************************/
25
26
27 #include "trace_file.hpp"
28
29
30 #include <assert.h>
31 #include <string.h>
32
33 #include <iostream>
34
35 #include <brotli/decode.h>
36
37 #include "os.hpp"
38
39
40 using namespace trace;
41
42
43 class BrotliFile : public File {
44 public:
45 BrotliFile(void);
46 virtual ~BrotliFile();
47
48 protected:
49 virtual bool rawOpen(const char *filename) override;
50 virtual size_t rawRead(void *buffer, size_t length) override;
51 virtual int rawGetc(void) override;
52 virtual void rawClose(void) override;
53 virtual bool rawSkip(size_t length) override;
54 virtual int rawPercentRead(void) override;
55 private:
56 BrotliDecoderState *state;
57 std::ifstream m_stream;
58 static const size_t kFileBufferSize = 65536;
59 uint8_t input[kFileBufferSize];
60 const uint8_t* next_in;
61 size_t available_in;
62 };
63
BrotliFile(void)64 BrotliFile::BrotliFile(void)
65 {
66 state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
67 available_in = 0;
68 next_in = input;
69 }
70
~BrotliFile()71 BrotliFile::~BrotliFile()
72 {
73 close();
74 BrotliDecoderDestroyInstance(state);
75 }
76
rawOpen(const char * filename)77 bool BrotliFile::rawOpen(const char *filename)
78 {
79 std::ios_base::openmode fmode = std::fstream::binary
80 | std::fstream::in;
81
82 m_stream.open(filename, fmode);
83 return m_stream.is_open();
84 }
85
rawRead(void * buffer,size_t length)86 size_t BrotliFile::rawRead(void *buffer, size_t length)
87 {
88 uint8_t* output = (uint8_t *)buffer;
89 size_t total_out;
90 size_t available_out = length;
91 uint8_t* next_out = output;
92
93 while (true) {
94 BrotliDecoderResult result;
95 result = BrotliDecoderDecompressStream(state,
96 &available_in, &next_in,
97 &available_out, &next_out, &total_out);
98 if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
99 if (m_stream.fail()) {
100 break;
101 }
102 m_stream.read((char *)input, kFileBufferSize);
103 available_in = kFileBufferSize;
104 if (m_stream.fail()) {
105 available_in = m_stream.gcount();
106 if (!available_in) {
107 break;
108 }
109 }
110 next_in = input;
111 } else {
112 assert(result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT ||
113 result == BROTLI_DECODER_RESULT_SUCCESS);
114 break;
115 }
116 }
117
118 assert(next_out - output <= length);
119
120 return next_out - output;
121 }
122
rawGetc()123 int BrotliFile::rawGetc()
124 {
125 unsigned char c;
126 if (rawRead(&c, 1) != 1) {
127 return -1;
128 }
129 return c;
130 }
131
rawClose()132 void BrotliFile::rawClose()
133 {
134 m_stream.close();
135 }
136
rawSkip(size_t)137 bool BrotliFile::rawSkip(size_t)
138 {
139 return false;
140 }
141
rawPercentRead(void)142 int BrotliFile::rawPercentRead(void)
143 {
144 return 0;
145 }
146
147
createBrotli(void)148 File * File::createBrotli(void) {
149 return new BrotliFile;
150 }
151