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