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

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

Fixes and enhancements.

File size: 11.1 KB
Line 
1/* $Id: kFile.cpp,v 1.4 2000-08-31 03:00:12 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 = DosQueryFileInfo(hFile, FIL_QUERYEASIZE, &filestatus, sizeof(filestatus));
42 fStatusClean = (rc == NO_ERROR);
43 if (!fStatusClean && fThrowErrors)
44 throw ((int)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 = DosSetFilePtr(hFile, offVirtual, FILE_BEGIN, &off);
67 if (rc != NO_ERROR || off != offVirtual)
68 {
69 if (fThrowErrors)
70 throw ((int)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 pszFilename(NULL)
97{
98 ULONG fulOpenFlags;
99 ULONG fulOpenMode;
100 ULONG ulAction;
101
102 /*
103 * Determin open flags according to fReadOnly.
104 */
105 if (fReadOnly)
106 {
107 fulOpenFlags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
108 fulOpenMode = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY;
109 }
110 else
111 {
112 fulOpenFlags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
113 fulOpenMode = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READWRITE;
114 }
115
116 rc = DosOpen((PCSZ)pszFilename, &hFile, &ulAction, 0, FILE_NORMAL,
117 fulOpenFlags, fulOpenMode, NULL);
118 if (rc != NO_ERROR)
119 throw ((int)rc);
120
121 if (!refreshFileStatus())
122 throw ((int)rc);
123
124 char szFullName[CCHMAXPATH];
125 if (DosQueryPathInfo(pszFilename, FIL_QUERYFULLNAME, szFullName, sizeof(szFullName)))
126 strcpy(szFullName, pszFilename);
127 this->pszFilename = strdup(szFullName);
128 if (this->pszFilename == NULL)
129 throw (ERROR_NOT_ENOUGH_MEMORY);
130}
131
132
133/**
134 * Closes the file.
135 */
136kFile::~kFile()
137{
138 DosClose(hFile);
139}
140
141
142/**
143 * Reads <cbBuffer> bytes from the current file posistion into the buffer.
144 * @returns success indicator. (TRUE/FALSE)
145 * @param pvBuffer Output buffer.
146 * @param cbBuffer Amount of bytes to read.
147 */
148BOOL kFile::read(void *pvBuffer, long cbBuffer)
149{
150 if (position())
151 {
152 ULONG cbRead;
153 rc = DosRead(hFile, pvBuffer, cbBuffer, &cbRead);
154 if (rc == NO_ERROR)
155 {
156 offVirtual = offReal += cbRead;
157 return TRUE;
158 }
159 }
160
161 if (fThrowErrors)
162 throw ((int)rc);
163 return FALSE;
164}
165
166
167/**
168 * Reads <cbBuffer> bytes at file offset <off>.
169 * @returns success indicator. (TRUE/FALSE)
170 * @param pvBuffer Output buffer.
171 * @param cbBuffer Amount of bytes to read.
172 * @param off Absolute file offset.
173 */
174BOOL kFile::readAt(void *pvBuffer, long cbBuffer, long off)
175{
176 return set(off) && read(pvBuffer, cbBuffer);
177}
178
179
180/**
181 * Reads the entire file into a single memory block.
182 * (The memory block has a '\0' at the end just in case you
183 * are using it as a long string.)
184 * @returns Pointer to file in memory.
185 */
186void * kFile::readFile() throw(int)
187{
188 void *pv;
189
190 /* allocate memory for the file */
191 pv = calloc((size_t)this->getSize() + 1, 1);
192 if (pv == NULL)
193 {
194 if (fThrowErrors)
195 throw(ERROR_NOT_ENOUGH_MEMORY);
196 return NULL;
197 }
198
199 /* go the start of the file and read it. */
200 if (start() && read(pv, this->getSize()))
201 return pv; // successfull exit!
202
203 /* we failed, cleanup and return NULL */
204 free(pv);
205 return NULL;
206}
207
208
209/**
210 * Writes <cbBuffer> bytes to the file at the current file position.
211 * @returns success indicator. (TRUE/FALSE)
212 * @param pvBuffer Output buffer.
213 * @param cbBuffer Amount of bytes to write.
214 */
215BOOL kFile::write(void *pvBuffer, long cbBuffer)
216{
217 if (fReadOnly)
218 rc = ERROR_ACCESS_DENIED;
219 else
220 {
221 if (position())
222 {
223 ULONG cbWrote;
224
225 rc = DosWrite(hFile, pvBuffer, cbBuffer, &cbWrote);
226 if (rc == NO_ERROR)
227 {
228 fStatusClean = FALSE;
229 offVirtual = offReal += cbWrote;
230 return TRUE;
231 }
232 }
233 }
234
235 if (fThrowErrors)
236 throw ((int)rc);
237 return FALSE;
238}
239
240
241/**
242 * Write <cbBuffer> bytes at file offset <off> from <pvBuffer>.
243 * @returns success indicator. (TRUE/FALSE)
244 * @param pvBuffer Output buffer.
245 * @param cbBuffer Amount of bytes to write.
246 * @param off Absolute file offset.
247 */
248BOOL kFile::writeAt(void *pvBuffer, long cbBuffer, long off)
249{
250 return set(off) && write(pvBuffer, cbBuffer);
251}
252
253
254/**
255 * printf - formatted write.
256 *
257 * Lonely '\n's are prefixed with a '\r' to make output conform with
258 * PC line ending.
259 *
260 * @returns Number of bytes written.
261 * @param pszFormat Format string.
262 * @param ... Ellipcis.
263 * @remark Currently limited to 64KB of result data.
264 */
265int kFile::printf(const char *pszFormat, ...) throw (int)
266{
267 long offStart = getPos();
268 va_list arg;
269
270 /* !QUICK AND DIRTY! */
271 char * psz, * pszEnd;
272 char * pszBuffer = (char*)malloc(1024*64); //64KB should normally be enough...
273
274 va_start(arg, pszFormat);
275 pszEnd = vsprintf(pszBuffer, pszFormat, arg) + pszBuffer;
276 va_end(arg);
277
278 psz = pszEnd;
279 while (psz > pszBuffer)
280 {
281 if (*psz-- == '\n' && *psz != '\r')
282 {
283 memmove(psz+2, psz+1, pszEnd - psz + 1);
284 psz[1] = '\r';
285 pszEnd++;
286 }
287 }
288
289 write(pszBuffer, pszEnd - pszBuffer);
290 free(pszBuffer);
291
292 return (int)(getPos() - offStart);
293}
294
295
296/**
297 * Sets the filesize.
298 * @returns Success indicator.
299 * @param cbFile New filesize.
300 * Defaults to 0xffffffff, which results in
301 * cutting the file at the current position.
302 */
303BOOL kFile::setSize(unsigned long cbFile/*= ~0UL*/)
304{
305 if (cbFile == ~0UL)
306 cbFile = offVirtual;
307 rc = DosSetFileSize(hFile, cbFile);
308 if (rc != NO_ERROR && fThrowErrors)
309 throw ((int)rc);
310
311 return rc == NO_ERROR;
312}
313
314
315
316/**
317 * Seek relative to the current position.
318 * @returns Success indicator.
319 * @param off Relative reposition.
320 */
321BOOL kFile::move(long off)
322{
323 if ((off + offVirtual) & 0x80000000UL) /* above 2GB or negative */
324 rc = ERROR_NEGATIVE_SEEK;
325 else
326 {
327 if (off + offVirtual > filestatus.cbFile && fReadOnly) /* can't expand readonly file. */
328 rc = ERROR_HANDLE_EOF;
329 else
330 {
331 offVirtual += off;
332 return TRUE;
333 }
334 }
335
336 if (fThrowErrors)
337 throw ((int)rc);
338 return FALSE;
339}
340
341
342/**
343 * Seek to an absolute position in the file (off).
344 * @returns Success indicator.
345 * @param off New file position.
346 */
347BOOL kFile::set(long off)
348{
349 if (off < 0)
350 rc = ERROR_NEGATIVE_SEEK;
351 else
352 {
353 if ((unsigned long)off > filestatus.cbFile && fReadOnly)
354 rc = ERROR_HANDLE_EOF;
355 else
356 {
357 offVirtual = off;
358 rc = NO_ERROR;
359 return TRUE;
360 }
361 }
362 if (fThrowErrors)
363 throw ((int)rc);
364 return FALSE;
365}
366
367
368/**
369 * Seek to the end of the file.
370 * @returns Success indicator. TRUE / FALSE.
371 * @remark Will only throw error if refreshFileStatus failes.
372 */
373BOOL kFile::end()
374{
375 if (!refreshFileStatus())
376 return FALSE;
377 offVirtual = filestatus.cbFile; //?? or +1
378 rc = NO_ERROR;
379 return TRUE;
380}
381
382
383/**
384 * Seek to the start of the file.
385 * @returns TRUE.
386 * @remark Will never throw errors.
387 */
388BOOL kFile::start()
389{
390 offVirtual = 0;
391 rc = NO_ERROR;
392 return TRUE;
393}
394
395
396/**
397 * Get the size of the file.
398 * @returns Returns file size on success.
399 * -1 on error.
400 * @remark Will only throw error if refreshFileStatus failes.
401 */
402long kFile::getSize()
403{
404 if (!refreshFileStatus())
405 return -1;
406
407 return filestatus.cbFile;
408}
409
410
411/**
412 * Get current position.
413 * @returns The current file position.
414 * @remark Will only throw error if refreshFileStatus failes.
415 */
416long kFile::getPos() const
417{
418 return offVirtual;
419}
420
421
422/**
423 * Checks if we have reached the file end.
424 * @returns TRUE if end-of-file is reached.
425 * FALSE is not end-of-file.
426 * @remark Will only throw error if refreshFileStatus failes.
427 */
428BOOL kFile::isEOF()
429{
430 #if 0
431 throw(ERROR_NOT_SUPPORTED); //this method don't currently work! Need to use flag!
432 #else
433 if (!refreshFileStatus())
434 return (BOOL)-1;
435
436 return filestatus.cbFile >= offReal; //???
437 #endif
438}
439
440
441/**
442 * Set error behaviour to fail by throwing the OS/2 return code when an
443 * error occures.
444 * @returns TRUE;
445 * @remark Will never throw errors.
446 */
447BOOL kFile::setThrowOnErrors()
448{
449 fThrowErrors = TRUE;
450 rc = NO_ERROR;
451 return TRUE;
452}
453
454
455/**
456 * Set error behaviour to fail by return FALSE when an error has occures.
457 * @returns TRUE;
458 * @remark Will never throw errors.
459 */
460BOOL kFile::setFailOnErrors()
461{
462 fThrowErrors = FALSE;
463 rc = NO_ERROR;
464 return TRUE;
465}
466
467
468/**
469 * Gets the last error code.
470 * @returns OS/2 error code for the last operation.
471 * @remark Will never throw errors.
472 */
473int kFile::getLastError() const
474{
475 return rc;
476}
477
Note: See TracBrowser for help on using the repository browser.