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