source: trunk/tools/common/kFile.cpp@ 3629

Last change on this file since 3629 was 3629, checked in by bird, 25 years ago

Added printf method (works for upto 64KB of data).

File size: 9.6 KB
Line 
1/* $Id: kFile.cpp,v 1.3 2000-05-29 19:45:57 bird Exp $
2 *
3 * kFile - Simple (for the time being) file class.
4 *
5 * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
6 *
7 * Project Odin Software License can be found in LICENSE.TXT
8 *
9 */
10
11/*******************************************************************************
12* Defined Constants And Macros *
13*******************************************************************************/
14#define INCL_DOSFILEMGR
15#define INCL_DOSERRORS
16
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#include <os2.h>
22
23#include <malloc.h>
24#include <string.h>
25#include <stdarg.h>
26#include <stdio.h>
27
28#include <kFile.h>
29
30
31/**
32 * Updates the internal filestatus struct.
33 * @returns Success indicator.
34 * On success filestatus is refreshed.
35 * @remark
36 */
37BOOL kFile::refreshFileStatus()
38{
39 if (!fStatusClean)
40 {
41 rc = (int)DosQueryFileInfo(hFile, FIL_QUERYEASIZE, &filestatus, sizeof(filestatus));
42 fStatusClean = (rc == NO_ERROR);
43 if (!fStatusClean && fThrowErrors)
44 throw (rc);
45 }
46 else
47 rc = NO_ERROR;
48
49 return fStatusClean;
50}
51
52
53/**
54 * Changes the real file position to match the virtual file position.
55 * @returns Success indicator.
56 */
57BOOL kFile::position()
58{
59 /*
60 * If virtual file offset is different from the real,
61 * issue a set file pointer call.
62 */
63 if (offVirtual != offReal)
64 {
65 ULONG off;
66 rc = (int)DosSetFilePtr(hFile, offVirtual, FILE_BEGIN, &off);
67 if (rc != NO_ERROR || off != offVirtual)
68 {
69 if (fThrowErrors)
70 throw (rc);
71 return FALSE;
72 }
73 offReal = offVirtual;
74 }
75
76 return TRUE;
77}
78
79
80/**
81 * Opens a file for binary reading or readwrite.
82 * @returns <object> with state updated.
83 * Throws OS/2 error on error.
84 * @param pszFilename Filename.
85 * @param fReadOnly TRUE: Open the file readonly. (default)
86 * FALSE: Open the file readwrite appending
87 * existing files.
88 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
89 */
90kFile::kFile(const char *pszFilename, BOOL fReadOnly/*=TRUE*/)
91: fReadOnly(fReadOnly),
92 fStatusClean(FALSE),
93 fThrowErrors(FALSE),
94 offVirtual(0),
95 offReal(0)
96{
97 ULONG fulOpenFlags;
98 ULONG fulOpenMode;
99 ULONG ulAction;
100
101 /*
102 * Determin open flags according to fReadOnly.
103 */
104 if (fReadOnly)
105 {
106 fulOpenFlags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
107 fulOpenMode = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY;
108 }
109 else
110 {
111 fulOpenFlags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
112 fulOpenMode = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READWRITE;
113 }
114
115 rc = (int)DosOpen((PCSZ)pszFilename, &hFile, &ulAction, 0, FILE_NORMAL,
116 fulOpenFlags, fulOpenMode, NULL);
117 if (rc != NO_ERROR)
118 throw (rc);
119
120 if (!refreshFileStatus())
121 throw (rc);
122}
123
124
125/**
126 * Closes the file.
127 */
128kFile::~kFile()
129{
130 DosClose(hFile);
131}
132
133
134/**
135 * Reads <cbBuffer> bytes from the current file posistion into the buffer.
136 * @returns success indicator. (TRUE/FALSE)
137 * @param pvBuffer Output buffer.
138 * @param cbBuffer Amount of bytes to read.
139 */
140BOOL kFile::read(void *pvBuffer, long cbBuffer)
141{
142 if (position())
143 {
144 ULONG cbRead;
145 rc = (int)DosRead(hFile, pvBuffer, cbBuffer, &cbRead);
146 if (rc == NO_ERROR)
147 {
148 offVirtual = offReal += cbRead;
149 return TRUE;
150 }
151 }
152
153 if (fThrowErrors)
154 throw (rc);
155 return FALSE;
156}
157
158
159/**
160 * Reads <cbBuffer> bytes at file offset <off>.
161 * @returns success indicator. (TRUE/FALSE)
162 * @param pvBuffer Output buffer.
163 * @param cbBuffer Amount of bytes to read.
164 * @param off Absolute file offset.
165 */
166BOOL kFile::readAt(void *pvBuffer, long cbBuffer, long off)
167{
168 return set(off) && read(pvBuffer, cbBuffer);
169}
170
171
172/**
173 * Writes <cbBuffer> bytes to the file at the current file position.
174 * @returns success indicator. (TRUE/FALSE)
175 * @param pvBuffer Output buffer.
176 * @param cbBuffer Amount of bytes to write.
177 */
178BOOL kFile::write(void *pvBuffer, long cbBuffer)
179{
180 if (fReadOnly)
181 rc = ERROR_ACCESS_DENIED;
182 else
183 {
184 if (position())
185 {
186 ULONG cbWrote;
187
188 rc = (int)DosWrite(hFile, pvBuffer, cbBuffer, &cbWrote);
189 if (rc == NO_ERROR)
190 {
191 fStatusClean = FALSE;
192 offVirtual = offReal += cbWrote;
193 return TRUE;
194 }
195 }
196 }
197
198 if (fThrowErrors)
199 throw(rc);
200 return FALSE;
201}
202
203
204/**
205 * Write <cbBuffer> bytes at file offset <off> from <pvBuffer>.
206 * @returns success indicator. (TRUE/FALSE)
207 * @param pvBuffer Output buffer.
208 * @param cbBuffer Amount of bytes to write.
209 * @param off Absolute file offset.
210 */
211BOOL kFile::writeAt(void *pvBuffer, long cbBuffer, long off)
212{
213 return set(off) && write(pvBuffer, cbBuffer);
214}
215
216
217/**
218 * printf - formatted write.
219 *
220 * Lonely '\n's are prefixed with a '\r' to make output conform with
221 * PC line ending.
222 *
223 * @returns Number of bytes written.
224 * @param pszFormat Format string.
225 * @param ... Ellipcis.
226 * @remark Currently limited to 64KB of result data.
227 */
228int kFile::printf(const char *pszFormat, ...) throw (int)
229{
230 long offStart = getPos();
231 va_list arg;
232
233 /* !QUICK AND DIRTY! */
234 char * psz, * pszEnd;
235 char * pszBuffer = (char*)malloc(1024*64); //64KB should normally be enough...
236
237 va_start(arg, pszFormat);
238 pszEnd = vsprintf(pszBuffer, pszFormat, arg) + pszBuffer;
239 va_end(arg);
240
241 psz = pszEnd;
242 while (psz > pszBuffer)
243 {
244 if (*psz-- == '\n' && *psz != '\r')
245 {
246 memmove(psz+2, psz+1, pszEnd - psz + 1);
247 psz[1] = '\r';
248 pszEnd++;
249 }
250 }
251
252 write(pszBuffer, pszEnd - pszBuffer);
253 free(pszBuffer);
254
255 return getPos() - offStart;
256}
257
258
259
260
261/**
262 * Seek relative to the current position.
263 * @returns Success indicator.
264 * @param off Relative reposition.
265 */
266BOOL kFile::move(long off)
267{
268 if ((off + offVirtual) & 0x80000000UL) /* above 2GB or negative */
269 rc = ERROR_NEGATIVE_SEEK;
270 else
271 {
272 if (off + offVirtual > filestatus.cbFile && fReadOnly) /* can't expand readonly file. */
273 rc = ERROR_HANDLE_EOF;
274 else
275 {
276 offVirtual += off;
277 return TRUE;
278 }
279 }
280
281 if (fThrowErrors)
282 throw(rc);
283 return FALSE;
284}
285
286
287/**
288 * Seek to an absolute position in the file (off).
289 * @returns Success indicator.
290 * @param off New file position.
291 */
292BOOL kFile::set(long off)
293{
294 if (off < 0)
295 rc = ERROR_NEGATIVE_SEEK;
296 else
297 {
298 if ((unsigned long)off > filestatus.cbFile && fReadOnly)
299 rc = ERROR_HANDLE_EOF;
300 else
301 {
302 offVirtual = off;
303 rc = NO_ERROR;
304 return TRUE;
305 }
306 }
307 if (fThrowErrors)
308 throw(rc);
309 return FALSE;
310}
311
312
313/**
314 * Seek to the end of the file.
315 * @returns Success indicator. TRUE / FALSE.
316 * @remark Will only throw error if refreshFileStatus failes.
317 */
318BOOL kFile::end()
319{
320 if (!refreshFileStatus())
321 return FALSE;
322 offVirtual = filestatus.cbFile; //?? or +1
323 rc = NO_ERROR;
324 return TRUE;
325}
326
327
328/**
329 * Seek to the start of the file.
330 * @returns TRUE.
331 * @remark Will never throw errors.
332 */
333BOOL kFile::start()
334{
335 offVirtual = 0;
336 rc = NO_ERROR;
337 return TRUE;
338}
339
340
341/**
342 * Get the size of the file.
343 * @returns Returns file size on success.
344 * -1 on error.
345 * @remark Will only throw error if refreshFileStatus failes.
346 */
347long kFile::getSize()
348{
349 if (!refreshFileStatus())
350 return -1;
351
352 return filestatus.cbFile;
353}
354
355
356/**
357 * Get current position.
358 * @returns The current file position.
359 * @remark Will only throw error if refreshFileStatus failes.
360 */
361long kFile::getPos() const
362{
363 return offVirtual;
364}
365
366
367/**
368 * Checks if we have reached the file end.
369 * @returns TRUE if end-of-file is reached.
370 * FALSE is not end-of-file.
371 * @remark Will only throw error if refreshFileStatus failes.
372 */
373BOOL kFile::isEOF()
374{
375 #if 0
376 throw(ERROR_NOT_SUPPORTED); //this method don't currently work! Need to use flag!
377 #else
378 if (!refreshFileStatus())
379 return (BOOL)-1;
380
381 return filestatus.cbFile >= offReal; //???
382 #endif
383}
384
385
386/**
387 * Set error behaviour to fail by throwing the OS/2 return code when an
388 * error occures.
389 * @returns TRUE;
390 * @remark Will never throw errors.
391 */
392BOOL kFile::setThrowOnErrors()
393{
394 fThrowErrors = TRUE;
395 rc = NO_ERROR;
396 return TRUE;
397}
398
399
400/**
401 * Set error behaviour to fail by return FALSE when an error has occures.
402 * @returns TRUE;
403 * @remark Will never throw errors.
404 */
405BOOL kFile::setFailOnErrors()
406{
407 fThrowErrors = FALSE;
408 rc = NO_ERROR;
409 return TRUE;
410}
411
412
413/**
414 * Gets the last error code.
415 * @returns OS/2 error code for the last operation.
416 * @remark Will never throw errors.
417 */
418int kFile::getLastError() const
419{
420 return rc;
421}
422
Note: See TracBrowser for help on using the repository browser.