]> git.cworth.org Git - apitrace/blob - trace_file.cpp
Merge branch 'master' into compression
[apitrace] / trace_file.cpp
1 #include "trace_file.hpp"
2
3 #include <assert.h>
4 #include <string.h>
5
6 #include <zlib.h>
7 #include <snappy.h>
8
9 #include "os.hpp"
10
11 #include <iostream>
12
13 using namespace Trace;
14
15 #define SNAPPY_BYTE1 'a'
16 #define SNAPPY_BYTE2 't'
17
18 File::File(const std::string &filename,
19            File::Mode mode)
20     : m_filename(filename),
21       m_mode(mode),
22       m_isOpened(false)
23 {
24     if (!m_filename.empty()) {
25         open(m_filename, m_mode);
26     }
27 }
28
29
30 File::~File()
31 {
32     close();
33 }
34
35 bool File::isOpened() const
36 {
37     return m_isOpened;
38 }
39
40 File::Mode File::mode() const
41 {
42     return m_mode;
43 }
44
45 std::string File::filename() const
46 {
47     return m_filename;
48 }
49
50 bool File::open(const std::string &filename, File::Mode mode)
51 {
52     if (m_isOpened) {
53         close();
54     }
55     m_isOpened = rawOpen(filename, mode);
56     m_mode = mode;
57
58     return m_isOpened;
59 }
60
61 bool File::write(const void *buffer, int length)
62 {
63     if (!m_isOpened || m_mode != File::Write) {
64         return false;
65     }
66     return rawWrite(buffer, length);
67 }
68
69 bool File::read(void *buffer, int length)
70 {
71     if (!m_isOpened || m_mode != File::Read) {
72         return false;
73     }
74     return rawRead(buffer, length);
75 }
76
77 void File::close()
78 {
79     if (m_isOpened) {
80         rawClose();
81         m_isOpened = false;
82     }
83 }
84
85 void File::flush(FlushType type)
86 {
87     rawFlush(type);
88 }
89
90 int File::getc()
91 {
92     if (!m_isOpened || m_mode != File::Read) {
93         return 0;
94     }
95     return rawGetc();
96 }
97
98 bool File::isZLibCompressed(const std::string &filename)
99 {
100     std::fstream stream(filename.c_str(),
101                         std::fstream::binary | std::fstream::in);
102     if (!stream.is_open())
103         return false;
104
105     unsigned char byte1, byte2;
106     stream >> byte1;
107     stream >> byte2;
108     stream.close();
109
110     return (byte1 == 0x1f && byte2 == 0x8b);
111 }
112
113
114 bool File::isSnappyCompressed(const std::string &filename)
115 {
116     std::fstream stream(filename.c_str(),
117                         std::fstream::binary | std::fstream::in);
118     if (!stream.is_open())
119         return false;
120
121     unsigned char byte1, byte2;
122     stream >> byte1;
123     stream >> byte2;
124     stream.close();
125
126     return (byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
127 }
128
129
130 ZLibFile::ZLibFile(const std::string &filename,
131                    File::Mode mode)
132     : File(filename, mode),
133       m_gzFile(NULL)
134 {
135 }
136
137 ZLibFile::~ZLibFile()
138 {
139 }
140
141 bool ZLibFile::rawOpen(const std::string &filename, File::Mode mode)
142 {
143     m_gzFile = gzopen(filename.c_str(),
144                       (mode == File::Write) ? "wb" : "rb");
145     return m_gzFile != NULL;
146 }
147
148 bool ZLibFile::rawWrite(const void *buffer, int length)
149 {
150     return gzwrite(m_gzFile, buffer, length) != -1;
151 }
152
153 bool ZLibFile::rawRead(void *buffer, int length)
154 {
155     return gzread(m_gzFile, buffer, length) != -1;
156 }
157
158 int ZLibFile::rawGetc()
159 {
160     return gzgetc(m_gzFile);
161 }
162
163 void ZLibFile::rawClose()
164 {
165     if (m_gzFile) {
166         gzclose(m_gzFile);
167         m_gzFile = NULL;
168     }
169 }
170
171 void ZLibFile::rawFlush(FlushType type)
172 {
173     gzflush(m_gzFile, Z_SYNC_FLUSH);
174 }
175
176 SnappyFile::SnappyFile(const std::string &filename,
177                               File::Mode mode)
178     : File(),
179       m_cache(0),
180       m_cachePtr(0),
181       m_cacheSize(0)
182 {
183     m_compressedCache = new char[SNAPPY_CHUNK_SIZE];
184 }
185
186 SnappyFile::~SnappyFile()
187 {
188     delete [] m_compressedCache;
189 }
190
191 bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode)
192 {
193     std::ios_base::openmode fmode = std::fstream::binary;
194     if (mode == File::Write) {
195         fmode |= (std::fstream::out | std::fstream::trunc);
196         createCache(SNAPPY_CHUNK_SIZE);
197     } else if (mode == File::Read) {
198         fmode |= std::fstream::in;
199     }
200
201     m_stream.open(filename.c_str(), fmode);
202
203     //read in the initial buffer if we're reading
204     if (m_stream.is_open() && mode == File::Read) {
205         // read the snappy file identifier
206         unsigned char byte1, byte2;
207         m_stream >> byte1;
208         m_stream >> byte2;
209         assert(byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
210
211         flushCache();
212     } else if (m_stream.is_open() && mode == File::Write) {
213         // write the snappy file identifier
214         m_stream << SNAPPY_BYTE1;
215         m_stream << SNAPPY_BYTE2;
216     }
217     return m_stream.is_open();
218 }
219
220 bool SnappyFile::rawWrite(const void *buffer, int length)
221 {
222     if (freeCacheSize() > length) {
223         memcpy(m_cachePtr, buffer, length);
224         m_cachePtr += length;
225     } else if (freeCacheSize() == length) {
226         memcpy(m_cachePtr, buffer, length);
227         m_cachePtr += length;
228         flushCache();
229     } else {
230         int sizeToWrite = length;
231
232         while (sizeToWrite >= freeCacheSize()) {
233             int endSize = freeCacheSize();
234             int offset = length - sizeToWrite;
235             memcpy(m_cachePtr, (char*)buffer + offset, endSize);
236             sizeToWrite -= endSize;
237             m_cachePtr += endSize;
238             flushCache();
239         }
240         if (sizeToWrite) {
241             int offset = length - sizeToWrite;
242             memcpy(m_cachePtr, (char*)buffer + offset, sizeToWrite);
243             m_cachePtr += sizeToWrite;
244         }
245     }
246
247     return true;
248 }
249
250 bool SnappyFile::rawRead(void *buffer, int length)
251 {
252     if (m_stream.eof()) {
253         return false;
254     }
255     if (freeCacheSize() > length) {
256         memcpy(buffer, m_cachePtr, length);
257         m_cachePtr += length;
258     } else if (freeCacheSize() == length) {
259         memcpy(buffer, m_cachePtr, length);
260         m_cachePtr += length;
261         flushCache();
262     } else {
263         int sizeToRead = length;
264         int offset = 0;
265         while (sizeToRead) {
266             int chunkSize = std::min(freeCacheSize(), sizeToRead);
267             offset = length - sizeToRead;
268             memcpy((char*)buffer + offset, m_cachePtr, chunkSize);
269             m_cachePtr += chunkSize;
270             sizeToRead -= chunkSize;
271             if (sizeToRead > 0)
272                 flushCache();
273             if (!m_cacheSize)
274                 break;
275         }
276     }
277
278     return true;
279 }
280
281 int SnappyFile::rawGetc()
282 {
283     int c = 0;
284     if (!rawRead(&c, 1))
285         return -1;
286     return c;
287 }
288
289 void SnappyFile::rawClose()
290 {
291     flushCache();
292     m_stream.close();
293     delete [] m_cache;
294     m_cache = NULL;
295     m_cachePtr = NULL;
296 }
297
298 void SnappyFile::rawFlush(FlushType type)
299 {
300     if (type == FlushDeep) {
301         flushCache();
302     }
303     m_stream.flush();
304 }
305
306 void SnappyFile::flushCache()
307 {
308     if (m_mode == File::Write) {
309         size_t compressedLength;
310
311         ::snappy::RawCompress(m_cache, SNAPPY_CHUNK_SIZE - freeCacheSize(),
312                               m_compressedCache, &compressedLength);
313
314         m_stream << compressedLength;
315         m_stream.write(m_compressedCache, compressedLength);
316         m_cachePtr = m_cache;
317     } else if (m_mode == File::Read) {
318         if (m_stream.eof())
319             return;
320         //assert(m_cachePtr == m_cache + m_cacheSize);
321         size_t compressedLength;
322         m_stream >> compressedLength;
323         m_stream.read((char*)m_compressedCache, compressedLength);
324         ::snappy::GetUncompressedLength(m_compressedCache, compressedLength,
325                                         &m_cacheSize);
326         if (m_cache)
327             delete [] m_cache;
328         createCache(m_cacheSize);
329         ::snappy::RawUncompress(m_compressedCache, compressedLength,
330                                 m_cache);
331     }
332 }
333
334 void SnappyFile::createCache(size_t size)
335 {
336     m_cache = new char[size];
337     m_cachePtr = m_cache;
338     m_cacheSize = size;
339 }