1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
/** \file
* \brief Binary File Access.
*
* See Copyright Notice in im_lib.h
*/
#include "im_util.h"
#ifndef __IM_BINFILE_H
#define __IM_BINFILE_H
#if defined(__cplusplus)
extern "C" {
#endif
/** \defgroup binfile Binary File Access
*
* \par
* These functions are very usefull for reading/writing binary files
* that have headers or data that have to be converted depending on
* the current CPU byte order. It can invert 2, 4 or 8 bytes numbers to/from little/big-endian orders.
* \par
* It will process the data only if the file format is diferent from the current CPU.
* \par
* Can read from disk or memory. In case of a memory buffer, the file name must be the \ref imBinMemoryFileName structure.
* \par
* See \ref im_binfile.h
* \ingroup util */
typedef struct _imBinFile imBinFile;
/** Opens an existant binary file for reading.
* The default file byte order is the CPU byte order.
* Returns NULL if failed.
* \ingroup binfile */
imBinFile* imBinFileOpen(const char* pFileName);
/** Creates a new binary file for writing.
* The default file byte order is the CPU byte order.
* Returns NULL if failed.
* \ingroup binfile */
imBinFile* imBinFileNew(const char* pFileName);
/** Closes the file.
* \ingroup binfile */
void imBinFileClose(imBinFile* bfile);
/** Indicates that was an error on the last operation.
* \ingroup binfile */
int imBinFileError(imBinFile* bfile);
/** Returns the file size in bytes.
* \ingroup binfile */
unsigned long imBinFileSize(imBinFile* bfile);
/** Changes the file byte order. Returns the old one.
* \ingroup binfile */
int imBinFileByteOrder(imBinFile* bfile, int pByteOrder);
/** Reads an array of count values with byte sizes: 1, 2, 4, or 8. And invert the byte order if necessary after read.
* \ingroup binfile */
unsigned long imBinFileRead(imBinFile* bfile, void* pValues, unsigned long pCount, int pSizeOf);
/** Writes an array of values with sizes: 1, 2, 4, or 8. And invert the byte order if necessary before write.\n
* <b>ATENTION</b>: The function will not make a temporary copy of the values to invert the byte order.\n
* So after the call the values will be invalid, if the file byte order is diferent from the CPU byte order.
* \ingroup binfile */
unsigned long imBinFileWrite(imBinFile* bfile, void* pValues, unsigned long pCount, int pSizeOf);
/** Writes a string without the NULL terminator. The function uses sprintf to compose the string. \n
* The internal buffer is fixed at 4096 bytes.
* \ingroup binfile */
unsigned long imBinFilePrintf(imBinFile* bfile, char *format, ...);
/** Reads an integer number from the current position until found a non integer character.
* Returns a non zero value if sucessfull.
* \ingroup binfile */
int imBinFileReadInteger(imBinFile* handle, int *value);
/** Reads an floating point number from the current position until found a non number character.
* Returns a non zero value if sucessfull.
* \ingroup binfile */
int imBinFileReadFloat(imBinFile* handle, float *value);
/** Moves the file pointer from the begining of the file.\n
* When writing to a file seeking can go beyond the end of the file.
* \ingroup binfile */
void imBinFileSeekTo(imBinFile* bfile, unsigned long pOffset);
/** Moves the file pointer from current position.\n
* If the offset is a negative value the pointer moves backwards.
* \ingroup binfile */
void imBinFileSeekOffset(imBinFile* bfile, long pOffset);
/** Moves the file pointer from the end of the file.\n
* The offset is usually a negative value.
* \ingroup binfile */
void imBinFileSeekFrom(imBinFile* bfile, long pOffset);
/** Returns the current offset position.
* \ingroup binfile */
unsigned long imBinFileTell(imBinFile* bfile);
/** Indicates that the file pointer is at the end of the file.
* \ingroup binfile */
int imBinFileEndOfFile(imBinFile* bfile);
/** Predefined I/O Modules.
* \ingroup binfile */
enum imBinFileModule
{
IM_RAWFILE, /**< System dependent file I/O Rotines. */
IM_STREAM, /**< Standard Ansi C Stream I/O Rotines. */
IM_MEMFILE, /**< Uses a memory buffer (see \ref imBinMemoryFileName). */
IM_SUBFILE, /**< It is a sub file. FileName is a imBinFile* pointer from any other module. */
IM_FILEHANDLE,/**< System dependent file I/O Rotines, but FileName is a system file handle ("int" in UNIX and "HANDLE" in Windows). */
IM_IOCUSTOM0 /**< Other registered modules starts from here. */
};
/** Sets the current I/O module.
* \returns the previous function set, or -1 if failed.
* See also \ref imBinFileModule.
* \ingroup binfile */
int imBinFileSetCurrentModule(int pModule);
/** \brief Memory File I/O Filename
*
* \par
* Fake file name for the memory I/O module.
* \ingroup binfile */
typedef struct _imBinMemoryFileName
{
unsigned char *buffer; /**< The memory buffer. If you are reading the buffer must exists.
* If you are writing the buffer can be internally allocated to the given size. The buffer is never free.
* The buffer is allocated using "malloc", and reallocated using "realloc". Use "free" to release it.
* To avoid RTL conflicts use the function imBinMemoryRelease. */
int size; /**< Size of the buffer. */
float reallocate; /**< Reallocate factor for the memory buffer when writing (size += reallocate*size).
* Set reallocate to 0 to disable reallocation, in this case buffer must not be NULL. */
}imBinMemoryFileName;
/** Release the internal memory allocated when writing a Memory File (see \ref imBinMemoryFileName).
* \ingroup binfile */
void imBinMemoryRelease(unsigned char *buffer);
#if defined(__cplusplus)
}
#endif
#if defined(__cplusplus)
/** Base class to help the creation of new modules.\n
* It handles the read/write operations with byte order correction if necessary.
* \ingroup binfile */
class imBinFileBase
{
friend class imBinSubFile;
protected:
int IsNew,
FileByteOrder,
DoByteOrder; // to speed up byte order checking
// These will actually read/write the data
virtual unsigned long ReadBuf(void* pValues, unsigned long pSize) = 0;
virtual unsigned long WriteBuf(void* pValues, unsigned long pSize) = 0;
public:
int InitByteOrder(int ByteOrder)
{
int old_byte_order = this->FileByteOrder;
this->FileByteOrder = ByteOrder;
if (ByteOrder != imBinCPUByteOrder())
this->DoByteOrder = 1;
else
this->DoByteOrder = 0;
return old_byte_order;
}
// These will take care of byte swap if needed.
unsigned long Read(void* pValues, unsigned long pCount, int pSizeOf)
{
unsigned long rSize = ReadBuf(pValues, pCount * pSizeOf);
if (pSizeOf != 1 && DoByteOrder) imBinSwapBytes(pValues, pCount, pSizeOf);
return rSize/pSizeOf;
}
unsigned long Write(void* pValues, unsigned long pCount, int pSizeOf)
{
if (pSizeOf != 1 && DoByteOrder) imBinSwapBytes(pValues, pCount, pSizeOf);
return WriteBuf(pValues, pCount * pSizeOf)/pSizeOf;
}
virtual void Open(const char* pFileName) = 0;
virtual void New(const char* pFileName) = 0;
virtual void Close() = 0;
virtual unsigned long FileSize() = 0;
virtual int HasError() const = 0;
virtual void SeekTo(unsigned long pOffset) = 0;
virtual void SeekOffset(long pOffset) = 0;
virtual void SeekFrom(long pOffset) = 0;
virtual unsigned long Tell() const = 0;
virtual int EndOfFile() const = 0;
};
/** File I/O module creation callback.
* \ingroup binfile */
typedef imBinFileBase* (*imBinFileNewFunc)();
/** Register a user I/O module.\n
* Returns the new function set id.\n
* Accepts up to 10 modules.
* \ingroup binfile */
int imBinFileRegisterModule(imBinFileNewFunc pNewFunc);
#endif
#endif
|