~josejuan-sanchez/esajpip/continue

« back to all changes in this revision

Viewing changes to src/data/file.h

  • Committer: José Juan Sánchez Hernández
  • Date: 2013-10-01 10:01:21 UTC
  • Revision ID: josejuan.sanchez@gmail.com-20131001100121-xfobvkenqie7y0te
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifndef _DATA_FILE_H_
 
2
#define _DATA_FILE_H_
 
3
 
 
4
 
 
5
#include <stdio.h>
 
6
#include <stdio_ext.h>
 
7
#include <assert.h>
 
8
#include <stdint.h>
 
9
#include <sys/types.h>
 
10
#include <sys/stat.h>
 
11
#include <unistd.h>
 
12
#include <string>
 
13
 
 
14
#ifndef _USE_BOOST
 
15
        #include <tr1/memory>
 
16
#else
 
17
        #include <boost/tr1/memory.hpp>
 
18
#endif
 
19
 
 
20
 
 
21
namespace data
 
22
{
 
23
 
 
24
  using namespace std;
 
25
 
 
26
 
 
27
  /**
 
28
   * Struct for wrapping the basic <code>FILE</code> locked functions for
 
29
   * reading and writing defined in <code>stdio.h</code>.
 
30
   *
 
31
   * @see File
 
32
   */
 
33
  struct LockedAccess
 
34
  {
 
35
    static inline void configure(FILE *file_ptr)
 
36
    {
 
37
    }
 
38
 
 
39
    static inline size_t fwrite(const void *ptr, size_t size, size_t count, FILE *file_ptr)
 
40
    {
 
41
      return ::fwrite(ptr, size, count, file_ptr);
 
42
    }
 
43
 
 
44
    static inline size_t fread(void * ptr, size_t size, size_t count, FILE *file_ptr)
 
45
    {
 
46
      return ::fread(ptr, size, count, file_ptr);
 
47
    }
 
48
 
 
49
    static inline int fgetc(FILE *file_ptr)
 
50
    {
 
51
      return ::fgetc(file_ptr);
 
52
    }
 
53
 
 
54
    static inline int fputc(int c, FILE *file_ptr)
 
55
    {
 
56
      return ::fputc(c, file_ptr);
 
57
    }
 
58
  };
 
59
 
 
60
 
 
61
  /**
 
62
   * Struct for wrapping the basic <code>FILE</code> unlocked functions for
 
63
   * reading and writing defined in <code>stdio_exts.h</code>.
 
64
   *
 
65
   * @see File
 
66
   */
 
67
  #ifndef _NO_FAST_FILE
 
68
  struct UnlockedAccess
 
69
  {
 
70
    static inline void configure(FILE *file_ptr)
 
71
    {
 
72
      __fsetlocking(file_ptr, FSETLOCKING_BYCALLER);
 
73
    }
 
74
 
 
75
    static inline size_t fwrite(const void *ptr, size_t size, size_t count, FILE *file_ptr)
 
76
    {
 
77
      return ::fwrite_unlocked(ptr, size, count, file_ptr);
 
78
    }
 
79
 
 
80
    static inline size_t fread(void * ptr, size_t size, size_t count, FILE *file_ptr)
 
81
    {
 
82
      return ::fread_unlocked(ptr, size, count, file_ptr);
 
83
    }
 
84
 
 
85
    static inline int fgetc(FILE *file_ptr)
 
86
    {
 
87
      return ::fgetc_unlocked(file_ptr);
 
88
    }
 
89
 
 
90
    static inline int fputc(int c, FILE *file_ptr)
 
91
    {
 
92
      return ::fputc_unlocked(c, file_ptr);
 
93
    }
 
94
  };
 
95
  #endif
 
96
 
 
97
 
 
98
  /**
 
99
   * This is a wrapper class for the <code>FILE</code> functions that
 
100
   * provides all the functionality to handle files safely. It is defined
 
101
   * as a template in order to allow to use either the locked or the
 
102
   * unlocked API, by means of the structs <code>LockedAccess</code> and
 
103
   * <code>UnlockedAccess</code>. The unlocked API is not thread-safe,
 
104
   * but it provides faster file operations.
 
105
   *
 
106
   * @see LockedAccess
 
107
   * @see UnlockedAccess
 
108
   */
 
109
  template<class IO> class BaseFile
 
110
  {
 
111
  public:
 
112
        /**
 
113
         * Safe pointer to this class.
 
114
         */
 
115
    typedef tr1::shared_ptr< BaseFile<IO> > Ptr;
 
116
 
 
117
 
 
118
    /**
 
119
     * Initialized the internal file pointer to <code>NULL</code>.
 
120
     */
 
121
    BaseFile()
 
122
    {
 
123
      file_ptr = NULL;
 
124
    }
 
125
 
 
126
    /**
 
127
     * Returns <code>true</code> if the given file exists. This
 
128
     * is a wrapper of the system funcion <code>stat</code>.
 
129
     */
 
130
    static bool Exists(const char *file_name)
 
131
    {
 
132
      struct stat file_stat;
 
133
      return (stat(file_name, &file_stat) == 0);
 
134
    }
 
135
 
 
136
    /**
 
137
     * Opens a file with a specific access mode.
 
138
     * @param file_name Path name of the file to open.
 
139
     * @param access Access mode as a <code>fopen</code>
 
140
     * compatible format string.
 
141
     * @return <code>true</code> if successful.
 
142
     */
 
143
    bool Open(const char *file_name, const char *access)
 
144
    {
 
145
      assert(file_ptr == NULL);
 
146
 
 
147
      if((file_ptr = fopen(file_name, access)) == NULL) return false;
 
148
      else {
 
149
        IO::configure(file_ptr);
 
150
        return true;
 
151
      }
 
152
    }
 
153
 
 
154
    /**
 
155
     * Opens a file with a specific access mode.
 
156
     * @param file_name Path name of the file to open.
 
157
     * @param access Access mode as a <code>fopen</code>
 
158
     * compatible format string.
 
159
     * @return <code>true</code> if successful.
 
160
     */
 
161
    bool Open(const string& file_name, const char *access)
 
162
    {
 
163
      return Open(file_name.c_str(), access);
 
164
    }
 
165
 
 
166
    /**
 
167
     * Opens a file with a specific access mode given an already
 
168
     * opened <code>File</code> object. The descriptor of the opened
 
169
     * file is duplicated and re-opened with the access mode given.
 
170
     * @param file Opened file.
 
171
     * @param access Access mode as a <code>fopen</code>
 
172
     * compatible format string.
 
173
     * @return <code>true</code> if successful.
 
174
     */
 
175
    template<class IO2> bool Open(const BaseFile<IO2>& file, const char *access)
 
176
    {
 
177
      assert((file_ptr == NULL) && file.IsValid());
 
178
 
 
179
      int new_fd = -1;
 
180
 
 
181
      if((new_fd = dup(file.GetDescriptor())) < 0) return false;
 
182
      else {
 
183
        if((file_ptr = fdopen(new_fd, access)) == NULL) {
 
184
          close(new_fd);
 
185
          return false;
 
186
 
 
187
        } else {
 
188
          IO::configure(file_ptr);
 
189
          return true;
 
190
        }
 
191
      }
 
192
    }
 
193
 
 
194
    /*
 
195
     * Calls the function <code>Open</code> with the <code>"rb"
 
196
     * </code> access mode (reading).
 
197
     */
 
198
    bool OpenForReading(const char *file_name)
 
199
    {
 
200
      return Open(file_name, "rb");
 
201
    }
 
202
 
 
203
    /*
 
204
     * Calls the function <code>Open</code> with the <code>"rb"
 
205
     * </code> access mode (reading).
 
206
     */
 
207
    bool OpenForReading(const string& file_name)
 
208
    {
 
209
      return Open(file_name.c_str(), "rb");
 
210
    }
 
211
 
 
212
    /*
 
213
     * Calls the function <code>Open</code> with the <code>"rb"
 
214
     * </code> access mode (reading).
 
215
     */
 
216
    template<class IO2> bool OpenForReading(const BaseFile<IO2>& file)
 
217
    {
 
218
      return Open(file, "rb");
 
219
    }
 
220
 
 
221
    /*
 
222
     * Calls the function <code>Open</code> with the <code>"wb"
 
223
     * </code> access mode (writing).
 
224
     */
 
225
    bool OpenForWriting(const char *file_name)
 
226
    {
 
227
      return Open(file_name, "wb");
 
228
    }
 
229
 
 
230
    /*
 
231
     * Calls the function <code>Open</code> with the <code>"wb"
 
232
     * </code> access mode (writing).
 
233
     */
 
234
    bool OpenForWriting(const string& file_name)
 
235
    {
 
236
      return Open(file_name.c_str(), "wb");
 
237
    }
 
238
 
 
239
    /*
 
240
     * Calls the function <code>Open</code> with the <code>"wb"
 
241
     * </code> access mode (writing).
 
242
     */
 
243
    template<class IO2> bool OpenForWriting(const BaseFile<IO2>& file)
 
244
    {
 
245
      return Open(file, "wb");
 
246
    }
 
247
 
 
248
    /**
 
249
     * Changes the current position of the file.
 
250
     * @param offset Offset to add to the current position.
 
251
     * @param origin Origin to use for the change (<code>
 
252
     * SEEK_SET</code> by default).
 
253
     * @return <code>true</code> if successful.
 
254
     */
 
255
    bool Seek(int offset, int origin = SEEK_SET) const
 
256
    {
 
257
      assert(file_ptr != NULL);
 
258
 
 
259
      return !fseek(file_ptr, offset, origin);
 
260
    }
 
261
 
 
262
    /**
 
263
     * Closes the file.
 
264
     */
 
265
    void Close()
 
266
    {
 
267
      if(file_ptr != NULL) {
 
268
        fclose(file_ptr);
 
269
        file_ptr = NULL;
 
270
      }
 
271
    }
 
272
 
 
273
    /**
 
274
     * Returns the current file position.
 
275
     */
 
276
    uint64_t GetOffset() const
 
277
    {
 
278
      assert(file_ptr != NULL);
 
279
 
 
280
      return ftell(file_ptr);
 
281
    }
 
282
 
 
283
    /**
 
284
     * Returns the EOF status (<code>feof</code>) of the file.
 
285
     */
 
286
    int IsEOF() const
 
287
    {
 
288
      assert(file_ptr != NULL);
 
289
 
 
290
      return feof(file_ptr);
 
291
    }
 
292
 
 
293
    /**
 
294
     * Returns the file descriptor.
 
295
     */
 
296
    int GetDescriptor() const
 
297
    {
 
298
      assert(file_ptr != NULL);
 
299
 
 
300
      return fileno(file_ptr);
 
301
    }
 
302
 
 
303
    /**
 
304
     * Return the current size of the file, without modifying
 
305
     * the file position.
 
306
     */
 
307
    uint64_t GetSize() const
 
308
    {
 
309
      assert(file_ptr != NULL);
 
310
 
 
311
      uint64_t offset = GetOffset();
 
312
      Seek(0, SEEK_END);
 
313
      uint64_t final_offset = GetOffset();
 
314
      Seek(offset, SEEK_SET);
 
315
 
 
316
      return final_offset;
 
317
    }
 
318
 
 
319
    /**
 
320
     * Reads a byte from the file.
 
321
     */
 
322
    int ReadByte() const
 
323
    {
 
324
      assert(file_ptr != NULL);
 
325
 
 
326
      return IO::fgetc(file_ptr);
 
327
    }
 
328
 
 
329
    /**
 
330
     * Reads a value from the file.
 
331
     * @param value Pointer to the value where to store.
 
332
     * @param num_bytes Number of bytes to read (by default,
 
333
     * the size of the value).
 
334
     * @return <code>true</code> if successful.
 
335
     */
 
336
    template<typename T> bool Read(T *value, int num_bytes = sizeof(T)) const
 
337
    {
 
338
      assert(file_ptr != NULL);
 
339
 
 
340
      return (IO::fread((void *) value, num_bytes, 1, file_ptr) == 1);
 
341
    }
 
342
 
 
343
    /**
 
344
     * Reads a value from the file in reverse order.
 
345
     * @param value Pointer to the value where to store.
 
346
     * @param num_bytes Number of bytes to read (by default,
 
347
     * the size of the value).
 
348
     * @return <code>true</code> if successful.
 
349
     */
 
350
    template<typename T> bool ReadReverse(T *value, int num_bytes = sizeof(T)) const
 
351
    {
 
352
      assert(file_ptr != NULL);
 
353
 
 
354
      for (char *ptr = ((char *) value) + (num_bytes - 1); num_bytes-- > 0; ptr--)
 
355
        if (IO::fread((void *) ptr, 1, 1, file_ptr) != 1) return false;
 
356
 
 
357
      return true;
 
358
    }
 
359
 
 
360
    /**
 
361
     * Writes a byte to the file.
 
362
     */
 
363
    int WriteByte(int c) const
 
364
    {
 
365
      assert(file_ptr != NULL);
 
366
 
 
367
      return IO::fputc(c, file_ptr);
 
368
    }
 
369
 
 
370
    /**
 
371
     * Writes a value to the file.
 
372
     * @param value Pointer to the value.
 
373
     * @param num_bytes Number of bytes to write (by default,
 
374
     * the size of the value).
 
375
     * @return <code>true</code> if successful.
 
376
     */
 
377
    template<typename T> bool Write(T *value, int num_bytes = sizeof(T)) const
 
378
    {
 
379
      assert(file_ptr != NULL);
 
380
 
 
381
      return (IO::fwrite((void *) value, num_bytes, 1, file_ptr) == 1);
 
382
    }
 
383
 
 
384
    /**
 
385
     * Writes a value to the file in reverse order.
 
386
     * @param value Pointer to the value.
 
387
     * @param num_bytes Number of bytes to write (by default,
 
388
     * the size of the value).
 
389
     * @return <code>true</code> if successful.
 
390
     */
 
391
    template<typename T> bool WriteReverse(T *value, int num_bytes = sizeof(T)) const
 
392
    {
 
393
      assert(file_ptr != NULL);
 
394
 
 
395
      for (char *ptr = ((char *) value) + (num_bytes - 1); num_bytes-- > 0; ptr--)
 
396
        if (IO::fwrite((void *) ptr, 1, 1, file_ptr) != 1) return false;
 
397
 
 
398
      return true;
 
399
    }
 
400
 
 
401
    /**
 
402
     * Returns <code>true</code> if the file pointer is not
 
403
     * <code>NULL</code>.
 
404
     */
 
405
    bool IsValid() const
 
406
    {
 
407
      return (file_ptr != NULL);
 
408
    }
 
409
 
 
410
    /**
 
411
     * Returns <code>true</code> if the file pointer is not
 
412
     * <code>NULL</code>.
 
413
     */
 
414
    operator bool() const
 
415
    {
 
416
      return (file_ptr != NULL);
 
417
    }
 
418
 
 
419
    /**
 
420
     * The destructor closes the file.
 
421
     */
 
422
    virtual ~BaseFile()
 
423
    {
 
424
      Close();
 
425
    }
 
426
 
 
427
  private:
 
428
    /**
 
429
     * File pointer.
 
430
     */
 
431
    FILE *file_ptr;
 
432
  };
 
433
 
 
434
 
 
435
  /**
 
436
   * Specialization of the class <code>BaseFile</code> with
 
437
   * locked access.
 
438
   *
 
439
   * @see BaseFile
 
440
   * @see LockedAccess
 
441
   */
 
442
  typedef BaseFile<LockedAccess> File;
 
443
 
 
444
 
 
445
  /**
 
446
   * Specialization of the class <code>BaseFile</code> with
 
447
   * unlocked access.
 
448
   *
 
449
   * @see BaseFile
 
450
   * @see UnlockedAccess
 
451
   */
 
452
        #ifndef _NO_FAST_FILE
 
453
  typedef BaseFile<UnlockedAccess> FastFile;
 
454
        #endif
 
455
 
 
456
}
 
457
 
 
458
#endif /* _DATA_FILE_H_ */