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

Last change on this file since 7093 was 7093, checked in by bird, 24 years ago

Corrected buffering algorithm.

File size: 25.4 KB
Line 
1/* $Id: kFile.cpp,v 1.9 2001-10-17 14:21:10 bird Exp $
2 *
3 * kFile - Simple (for the time being) file class.
4 *
5 * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@mynd.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#include <stdlib.h>
28
29#include "kFile.h"
30
31/*******************************************************************************
32* Global Variables *
33*******************************************************************************/
34kFile kFile::StdIn((HFILE)0, TRUE);
35kFile kFile::StdOut((HFILE)1, FALSE);
36kFile kFile::StdErr((HFILE)2, FALSE);
37
38
39/**
40 * Updates the internal filestatus struct.
41 * @returns Success indicator.
42 * On success filestatus is refreshed.
43 * @remark
44 */
45BOOL kFile::refreshFileStatus()
46{
47 if (fStdDev)
48 return fStatusClean = TRUE;
49
50 if (!fStatusClean)
51 {
52 rc = DosQueryFileInfo(hFile, FIL_QUERYEASIZE, &filestatus, sizeof(filestatus));
53 fStatusClean = (rc == NO_ERROR);
54 if (!fStatusClean && fThrowErrors)
55 throw ((int)rc);
56 }
57 else
58 rc = NO_ERROR;
59
60 return fStatusClean;
61}
62
63
64/**
65 * Changes the real file position to match the virtual file position.
66 * @returns Success indicator.
67 */
68BOOL kFile::position()
69{
70 /*
71 * If virtual file offset is different from the real,
72 * issue a set file pointer call.
73 */
74 if (offVirtual != offReal)
75 {
76 ULONG off;
77 rc = DosSetFilePtr(hFile, offVirtual, FILE_BEGIN, &off);
78 if (rc != NO_ERROR || off != offVirtual)
79 {
80 if (fThrowErrors)
81 throw ((int)rc);
82 return FALSE;
83 }
84 offReal = offVirtual;
85 }
86 else
87 rc = NO_ERROR;
88
89 return TRUE;
90}
91
92
93/**
94 * Reads data from the file into the buffer from the given file offset.
95 * @returns Success indicator.
96 * @param offFile File offset to read from.
97 * (If readonly and beyond end of file the offset used
98 * may be addjusted.)
99 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
100 */
101BOOL kFile::bufferRead(ULONG offFile) throw (int)
102{
103 ULONG cbRead;
104
105 /* refresh file status (cbFile) */
106 if (!refreshFileStatus())
107 return FALSE;
108
109 /* check that the request is valid */
110 if (offFile > filestatus.cbFile)
111 return FALSE;
112
113 /* commit dirty buffer */
114 if (fBufferDirty)
115 {
116 if (!bufferCommit())
117 return TRUE;
118
119 /* refresh file status (cbFile) */
120 if (!refreshFileStatus())
121 return FALSE;
122 }
123
124 /* If readonly file optimize end of file */
125 if (fReadOnly && cbBuffer + offFile > filestatus.cbFile)
126 offFile = filestatus.cbFile > cbBuffer ? filestatus.cbFile - cbBuffer : 0UL;
127
128 /* need to change file ptr? */
129 if (offFile != offReal)
130 {
131 ULONG ul;
132 rc = DosSetFilePtr(hFile, offFile, FILE_BEGIN, &ul);
133 if (rc != NO_ERROR)
134 {
135 if (fThrowErrors)
136 throw ((int)rc);
137 return FALSE;
138 }
139 offReal = offFile;
140 }
141
142 /* read from the file */
143 cbRead = min(filestatus.cbFile - offFile, cbBuffer);
144 rc = DosRead(hFile, pachBuffer, cbRead, &cbRead);
145 if (rc == NO_ERROR)
146 {
147 cbBufferValid = cbRead;
148 offBuffer = offFile;
149 offReal = offFile + cbRead;
150 fBufferDirty = FALSE;
151 }
152 else
153 {
154 cbBufferValid = 0;
155 offBuffer = ~0UL;
156 fBufferDirty = FALSE;
157 if (fThrowErrors)
158 throw ((int)rc);
159 return FALSE;
160 }
161
162 return TRUE;
163}
164
165
166/**
167 * Commits the data in the buffer.
168 * @returns Success indicator.
169 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
170 */
171BOOL kFile::bufferCommit(void) throw (int)
172{
173 ULONG cbWrote;
174 ULONG ul;
175
176 /* don't commit clean buffers! */
177 if (!fBufferDirty)
178 return TRUE;
179
180 /* need to change file ptr? */
181 if (offBuffer != offReal)
182 {
183 rc = DosSetFilePtr(hFile, offBuffer, FILE_BEGIN, &ul);
184 if (rc != NO_ERROR)
185 {
186 if (fThrowErrors)
187 throw ((int)rc);
188 return FALSE;
189 }
190 offReal = offBuffer;
191 }
192
193 /* write to the file */
194 rc = DosWrite(hFile, pachBuffer, cbBufferValid, &cbWrote);
195 fStatusClean = FALSE;
196 if (rc == NO_ERROR)
197 {
198 fBufferDirty = FALSE;
199 offReal += cbWrote;
200 }
201 else
202 {
203 DosSetFilePtr(hFile, offReal, FILE_BEGIN, &ul);
204 if (fThrowErrors)
205 throw ((int)rc);
206 return FALSE;
207 }
208
209 return TRUE;
210}
211
212
213/**
214 * Creates a kFile object for a file that is opened allready.
215 * Intended use for the three standard handles only.
216 *
217 * @returns <object> with state updated.
218 * @param pszFilename Filename.
219 * @param fReadOnly TRUE: Open the file readonly.
220 * FALSE: Open the file readwrite appending
221 * existing files.
222 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
223 */
224kFile::kFile(HFILE hFile, BOOL fReadOnly)
225: fReadOnly(fReadOnly),
226 fStatusClean(FALSE),
227 fThrowErrors(FALSE),
228 offVirtual(0),
229 offReal(0),
230 pszFilename(NULL),
231 hFile(hFile),
232 fStdDev(TRUE),
233 pachBuffer(NULL),
234 cbBufferValid(0UL),
235 offBuffer(~0UL),
236 fBufferDirty(FALSE)
237{
238 if (!refreshFileStatus())
239 throw ((int)rc);
240 this->pszFilename = strdup("");
241}
242
243
244/**
245 * Opens a file for binary reading or readwrite.
246 * @returns <object> with state updated.
247 * Throws OS/2 error on error.
248 * @param pszFilename Filename.
249 * @param fReadOnly TRUE: Open the file readonly. (default)
250 * FALSE: Open the file readwrite appending
251 * existing files.
252 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
253 */
254kFile::kFile(const char *pszFilename, BOOL fReadOnly/*=TRUE*/)
255: fReadOnly(fReadOnly),
256 fStatusClean(FALSE),
257 fThrowErrors(FALSE),
258 offVirtual(0),
259 offReal(0),
260 pszFilename(NULL),
261 fStdDev(FALSE),
262 pachBuffer(NULL),
263 cbBufferValid(0UL),
264 offBuffer(~0UL),
265 fBufferDirty(FALSE)
266{
267 ULONG fulOpenFlags;
268 ULONG fulOpenMode;
269 ULONG ulAction;
270
271 /*
272 * Determin open flags according to fReadOnly.
273 */
274 if (fReadOnly)
275 {
276 fulOpenFlags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
277 fulOpenMode = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY;
278 }
279 else
280 {
281 fulOpenFlags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
282 fulOpenMode = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READWRITE;
283 }
284
285 rc = DosOpen((PCSZ)pszFilename, &hFile, &ulAction, 0, FILE_NORMAL,
286 fulOpenFlags, fulOpenMode, NULL);
287 if (rc != NO_ERROR)
288 throw ((int)rc);
289
290 if (!refreshFileStatus())
291 throw ((int)rc);
292
293 char szFullName[CCHMAXPATH];
294 if (DosQueryPathInfo(pszFilename, FIL_QUERYFULLNAME, szFullName, sizeof(szFullName)))
295 strcpy(szFullName, pszFilename);
296 this->pszFilename = strdup(szFullName);
297 if (this->pszFilename == NULL)
298 throw (ERROR_NOT_ENOUGH_MEMORY);
299
300 /* Buffering */
301 cbBuffer = (fReadOnly && filestatus.cbFile < 32768) ? filestatus.cbFile : 8192;
302 pachBuffer = new char[cbBuffer];
303 if (pachBuffer == NULL)
304 throw (ERROR_NOT_ENOUGH_MEMORY);
305 if (fReadOnly && filestatus.cbFile < 32768)
306 {
307 if (!bufferRead(0))
308 throw ((int)rc);
309 }
310}
311
312
313/**
314 * Closes the file.
315 */
316kFile::~kFile()
317{
318 if (fBufferDirty)
319 bufferCommit();
320 if (pachBuffer)
321 delete pachBuffer;
322 DosClose(hFile);
323}
324
325
326/**
327 * Reads <cbBuffer> bytes from the current file posistion into the buffer.
328 * @returns success indicator. (TRUE/FALSE)
329 * @param pvBuffer Output buffer.
330 * @param cbBuffer Amount of bytes to read.
331 */
332BOOL kFile::read(void *pvBuffer, long cbBuffer)
333{
334 ULONG cbRead;
335
336 /* Validate parameters */
337 if (cbBuffer == 0)
338 return TRUE;
339 if (cbBuffer < 0)
340 {
341 rc = ERROR_INVALID_PARAMETER;
342 if (fThrowErrors)
343 throw ((int)rc);
344 return FALSE;
345 }
346
347 /* refresh file status (cbFile) */
348 if (!refreshFileStatus())
349 return FALSE;
350
351 /* check if valid request */
352 if ( offVirtual > filestatus.cbFile
353 || offVirtual + cbBuffer > filestatus.cbFile
354 )
355 { /* invalid request */
356 rc = ERROR_NO_DATA;
357 }
358 else if (this->cbBufferValid == filestatus.cbFile && offBuffer == 0)
359 {
360 /*
361 * The entire file is buffered
362 * Complete the request.
363 */
364 memcpy(pvBuffer, &pachBuffer[offVirtual], (size_t)cbBuffer);
365 offVirtual += cbBuffer;
366 rc = NO_ERROR;
367 }
368 else if (pachBuffer && cbBuffer <= this->cbBuffer)
369 { /*
370 * Buffered read. (request not bigger than the buffer!)
371 * Update status (filesize).
372 * Check if the request is with the bounds of the file.
373 * Not in buffer?
374 * Then read more data into buffer.
375 * In buffer?
376 * Then complete the request.
377 *
378 */
379 while (cbBuffer > 0)
380 {
381 /* Part or all in buffer? */
382 if (pachBuffer != NULL &&
383 offVirtual >= offBuffer &&
384 offVirtual < offBuffer + cbBufferValid
385 )
386 { /* copy data from buffer */
387 cbRead = cbBufferValid - offVirtual + offBuffer;
388 cbRead = min(cbRead, cbBuffer);
389 memcpy(pvBuffer, &pachBuffer[offVirtual - offBuffer], (size_t)cbRead);
390 offVirtual += cbRead;
391 pvBuffer = (char*)pvBuffer + cbRead;
392 cbBuffer -= cbRead;
393 }
394 else
395 {
396 /* read into buffer */
397 if (!bufferRead(offVirtual))
398 return FALSE;
399 }
400 }
401
402 rc = NO_ERROR;
403 }
404 else if (position())
405 { /*
406 * unbuffered read.
407 */
408 rc = DosRead(hFile, pvBuffer, cbBuffer, &cbRead);
409 if (rc == NO_ERROR)
410 offVirtual = offReal += cbRead;
411 }
412
413 /* check for error and return accordingly */
414 if (rc)
415 {
416 if (fThrowErrors)
417 throw ((int)rc);
418 return FALSE;
419 }
420 return TRUE;
421}
422
423
424/**
425 * Reads <cbBuffer> bytes at file offset <off>.
426 * @returns success indicator. (TRUE/FALSE)
427 * @param pvBuffer Output buffer.
428 * @param cbBuffer Amount of bytes to read.
429 * @param off Absolute file offset.
430 */
431BOOL kFile::readAt(void *pvBuffer, long cbBuffer, long off)
432{
433 return set(off) && read(pvBuffer, cbBuffer);
434}
435
436
437/**
438 * Reads the entire file into a single memory block.
439 * (The memory block has a '\0' at the end just in case you
440 * are using it as a long string.)
441 * @returns Pointer to file in memory.
442 */
443void * kFile::readFile() throw(int)
444{
445 void *pv;
446
447 /* allocate memory for the file */
448 pv = calloc((size_t)this->getSize() + 1, 1);
449 if (pv == NULL)
450 {
451 if (fThrowErrors)
452 throw(ERROR_NOT_ENOUGH_MEMORY);
453 return NULL;
454 }
455
456 /* go the start of the file and read it. */
457 if (start() && read(pv, this->getSize()))
458 return pv; // successfull exit!
459
460 /* we failed, cleanup and return NULL */
461 free(pv);
462 return NULL;
463}
464
465
466/**
467 * Reads a single line from the file into the given buffer.
468 * Newline is stripped!
469 * @returns Success indicator.
470 * @param pszBuffer Pointer to string buffer.
471 * Will hold a zero-string upon successful return.
472 * @param cchBuffer Buffer size.
473 * @sketch
474 * @status partially implemented.
475 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
476 */
477BOOL kFile::readln(char *pszBuffer, long cchBuffer) throw (int)
478{
479 long cbRead;
480
481 /* refresh file status (cbFile) */
482 if (!refreshFileStatus())
483 return FALSE;
484
485 /*
486 * Buffered read.
487 * Calc max read size.
488 * Loop buffer by buffer looking for a newline.
489 */
490 cbRead = min(max((long)filestatus.cbFile - (long)offVirtual, 0), cchBuffer-1);
491 if (cbRead == 0)
492 return FALSE;
493
494 while (cbRead > 0)
495 {
496 char *pszNewLine;
497 char *pszReturn;
498 char *pszEnd;
499 unsigned long cch;
500
501 /* read more buffer ? */
502 if (offVirtual >= offBuffer + cbBufferValid || offVirtual < offBuffer)
503 if (!bufferRead(offVirtual))
504 return FALSE;
505
506 /* Scan buffer for new line */
507 pszNewLine = (char*)memchr(&pachBuffer[offVirtual - offBuffer], '\r', (size_t)(cbBufferValid - offVirtual + offBuffer));
508 pszReturn = (char*)memchr(&pachBuffer[offVirtual - offBuffer], '\n', (size_t)(cbBufferValid - offVirtual + offBuffer));
509 if (pszNewLine != NULL || pszReturn != NULL)
510 {
511 pszEnd = pszReturn != NULL && (pszNewLine == NULL || pszReturn < pszNewLine) ?
512 pszReturn : pszNewLine;
513 cch = pszEnd - &pachBuffer[offVirtual - offBuffer];
514 }
515 else
516 {
517 pszEnd = NULL;
518 cch = cbBufferValid - offVirtual + offBuffer;
519 }
520
521 /* copy into result buffer */
522 memcpy(pszBuffer, &pachBuffer[offVirtual - offBuffer], (size_t)cch);
523 cbRead -= cch;
524 offVirtual += cch;
525 pszBuffer += cch;
526 *pszBuffer = '\0';
527
528 /* check for completion */
529 if (pszEnd != NULL)
530 { /* skip newline */
531 if (pszEnd[0] == '\r')
532 {
533 if (cch + 1 > cbBufferValid)
534 {
535 if (bufferRead(offBuffer + cbBufferValid))
536 pszEnd = pachBuffer;
537 }
538 else
539 pszEnd++;
540 offVirtual += pszEnd != NULL && *pszEnd == '\n' ? 2 : 1;
541 }
542 else
543 offVirtual++;
544 return TRUE;
545 }
546 }
547
548 return TRUE;
549}
550
551
552/**
553 * Writes <cbBuffer> bytes to the file at the current file position.
554 * @returns success indicator. (TRUE/FALSE)
555 * @param pvBuffer Output buffer.
556 * @param cbBuffer Amount of bytes to write.
557 */
558BOOL kFile::write(const void *pv, long cb)
559{
560 if (fReadOnly)
561 rc = ERROR_ACCESS_DENIED;
562 else
563 {
564 /* buffered writes? */
565 if (pachBuffer != NULL)
566 {
567 ULONG cbWrite;
568 ULONG cbAddPost = 0;
569
570 /*
571 * New buffer algorithm.
572 * Init buffer if it's invalid.
573 * Loop until no more to write
574 * If All fits into current buffer Then
575 * Insert it. COMPLETED.
576 * If Start fits into the current buffer Then
577 * Insert it.
578 * Else If End fits into the current buffer Then
579 * Insert it.
580 * Else //nothing fit's into the buffer
581 * Commit the buffer.
582 * Initiate the buffer to the current offset.
583 * Insert as much as possible.
584 * Endif
585 * EndLoop
586 */
587 if (offBuffer == ~0UL)
588 { /* Empty buffer at current virtual offset */
589 fBufferDirty = 0;
590 cbBufferValid = 0;
591 offBuffer = offVirtual;
592 }
593
594 while (cb > 0)
595 {
596 if ( offBuffer <= offVirtual
597 && offBuffer + cbBufferValid >= offVirtual
598 && offBuffer + cbBuffer >= offVirtual + cb
599 )
600 { /* everything fits into the buffer */
601 memcpy(&pachBuffer[offVirtual - offBuffer], pv, cb);
602 if (cbBufferValid < cb + offVirtual - offBuffer)
603 cbBufferValid = cb + offVirtual - offBuffer;
604 offVirtual += cb + cbAddPost;
605 fBufferDirty = TRUE;
606 return TRUE;
607 }
608
609 if ( offBuffer <= offVirtual
610 && offBuffer + cbBufferValid >= offVirtual
611 && offBuffer + cbBuffer < offVirtual
612 )
613 { /* start fits into the buffer */
614 cbWrite = cbBuffer - (offVirtual - offBuffer);
615 memcpy(&pachBuffer[offVirtual - offBuffer], pv, cbWrite);
616 cbBufferValid = cbBuffer;
617 offVirtual += cbWrite;
618 cb -= cbWrite;
619 pv = (char*)pv + cbWrite;
620 }
621 else if ( offBuffer > offVirtual
622 && offBuffer <= offVirtual + cb
623 && offBuffer + cbBuffer >= offVirtual + cb
624 )
625 { /* end fits into the buffer */
626 cbWrite = offVirtual + cb - offBuffer;
627 memcpy(pachBuffer, pv, cbWrite);
628 if (cbBufferValid < cbWrite)
629 cbBufferValid = cbWrite;
630 cbAddPost += cbWrite;
631 cb -= cbWrite;
632 }
633 else
634 { /* don't fit anywhere... */
635 if (!bufferCommit())
636 return FALSE;
637 offBuffer = offVirtual;
638 cbWrite = cbBufferValid = cb > cbBuffer ? cbBuffer : cb;
639 memcpy(pachBuffer, pv, cbWrite);
640 cb -= cbWrite;
641 pv = (char*)pv + cbWrite;
642 offVirtual += cbWrite;
643 }
644 fBufferDirty = TRUE;
645
646
647 } /* loop */
648 offVirtual += cbAddPost;
649
650 return TRUE;
651 }
652 else if (position())
653 { /* non-buffered write! */
654 ULONG cbWrote;
655
656 rc = DosWrite(hFile, (PVOID)pv, cb, &cbWrote);
657 if (rc == NO_ERROR)
658 {
659 offVirtual = offReal += cbWrote;
660 return TRUE;
661 }
662 }
663 }
664
665 if (fThrowErrors)
666 throw ((int)rc);
667 return FALSE;
668}
669
670
671/**
672 * Write <cbBuffer> bytes at file offset <off> from <pvBuffer>.
673 * @returns success indicator. (TRUE/FALSE)
674 * @param pvBuffer Output buffer.
675 * @param cbBuffer Amount of bytes to write.
676 * @param off Absolute file offset.
677 */
678BOOL kFile::writeAt(void *pvBuffer, long cbBuffer, long off)
679{
680 return set(off) && write(pvBuffer, cbBuffer);
681}
682
683
684/**
685 * printf - formatted write.
686 *
687 * Lonely '\n's are prefixed with a '\r' to make output conform with
688 * PC line ending.
689 *
690 * @returns Number of bytes written.
691 * @param pszFormat Format string.
692 * @param ... Ellipcis.
693 * @remark Currently limited to 64KB of result data.
694 */
695int kFile::printf(const char *pszFormat, ...) throw (int)
696{
697 long offStart = getPos();
698 va_list arg;
699
700 /* !QUICK AND DIRTY! */
701 char * psz, * pszEnd;
702 static char szBuffer[1024*64]; //64KB should normally be enough for anyone...
703
704 va_start(arg, pszFormat);
705 pszEnd = vsprintf(szBuffer, pszFormat, arg) + szBuffer;
706 va_end(arg);
707
708 psz = pszEnd;
709 while (psz > szBuffer)
710 {
711 if (*psz-- == '\n' && *psz != '\r')
712 {
713 memmove(psz+2, psz+1, pszEnd - psz + 1);
714 psz[1] = '\r';
715 pszEnd++;
716 }
717 }
718
719 write(szBuffer, pszEnd - szBuffer);
720
721 return (int)(getPos() - offStart);
722}
723
724
725/**
726 * Sets the filesize.
727 * @returns Success indicator.
728 * @param cbFile New filesize.
729 * Defaults to 0xffffffff, which results in
730 * cutting the file at the current position.
731 */
732BOOL kFile::setSize(unsigned long cbFile/*= ~0UL*/)
733{
734 if (cbFile == ~0UL)
735 cbFile = offVirtual;
736 rc = DosSetFileSize(hFile, cbFile);
737 if (rc != NO_ERROR && fThrowErrors)
738 throw ((int)rc);
739
740 return rc == NO_ERROR;
741}
742
743
744/**
745 * Appends the AppendFile to this file.
746 * @returns Reference to this file.
747 * @param AppendFile Reference to the file we're to append.
748 */
749kFile & kFile::operator+=(kFile &AppendFile)
750{
751 long cb;
752 char * pachBuffer = new char[1024*256];
753 long pos = AppendFile.getPos();
754 BOOL fAppend = AppendFile.fThrowErrors;
755 BOOL fThis = fThrowErrors;
756
757 setThrowOnErrors();
758 AppendFile.setThrowOnErrors();
759
760 end();
761 AppendFile.start();
762 AppendFile.refreshFileStatus();
763
764 cb = min(1024*256, AppendFile.filestatus.cbFile);
765 while (cb > 0)
766 {
767 AppendFile.read(pachBuffer, cb);
768 write(pachBuffer, cb);
769 cb = min(1024*256, (long)AppendFile.filestatus.cbFile - (long)AppendFile.offVirtual);
770 }
771
772 delete pachBuffer;
773 AppendFile.set(pos);
774 AppendFile.fThrowErrors = fAppend;
775 fThrowErrors = fThis;
776
777 return *this;
778}
779
780
781/**
782 * Seek relative to the current position.
783 * @returns Success indicator.
784 * @param off Relative reposition.
785 */
786BOOL kFile::move(long off)
787{
788 if ((off + offVirtual) & 0x80000000UL) /* above 2GB or negative */
789 rc = ERROR_NEGATIVE_SEEK;
790 else
791 {
792 if (off + offVirtual > filestatus.cbFile && fReadOnly) /* can't expand readonly file. */
793 rc = ERROR_HANDLE_EOF;
794 else
795 {
796 offVirtual += off;
797 return TRUE;
798 }
799 }
800
801 if (fThrowErrors)
802 throw ((int)rc);
803 return FALSE;
804}
805
806
807/**
808 * Seek to an absolute position in the file (off).
809 * @returns Success indicator.
810 * @param off New file position.
811 */
812BOOL kFile::set(long off)
813{
814 if (off < 0)
815 rc = ERROR_NEGATIVE_SEEK;
816 else
817 {
818 if ((unsigned long)off > filestatus.cbFile && fReadOnly)
819 rc = ERROR_HANDLE_EOF;
820 else
821 {
822 offVirtual = off;
823 rc = NO_ERROR;
824 return TRUE;
825 }
826 }
827 if (fThrowErrors)
828 throw ((int)rc);
829 return FALSE;
830}
831
832
833/**
834 * Seek to the end of the file.
835 * @returns Success indicator. TRUE / FALSE.
836 * @remark Will only throw error if refreshFileStatus failes.
837 */
838BOOL kFile::end()
839{
840 if (!refreshFileStatus())
841 return FALSE;
842
843 if (!fReadOnly && pachBuffer && offBuffer != ~0UL && offBuffer + cbBufferValid > filestatus.cbFile)
844 /* a writable file with buffer might have uncommited data in the buffer. */
845 offVirtual = offBuffer + cbBufferValid;
846 else
847 offVirtual = filestatus.cbFile;
848
849 rc = NO_ERROR;
850 return TRUE;
851}
852
853
854/**
855 * Seek to the start of the file.
856 * @returns TRUE.
857 * @remark Will never throw errors.
858 */
859BOOL kFile::start()
860{
861 offVirtual = 0;
862 rc = NO_ERROR;
863 return TRUE;
864}
865
866
867/**
868 * Get the size of the file.
869 * @returns Returns file size on success.
870 * -1 on error.
871 * @remark Will only throw error if refreshFileStatus failes.
872 */
873long kFile::getSize()
874{
875 if (!refreshFileStatus())
876 return -1;
877
878 return filestatus.cbFile;
879}
880
881
882/**
883 * Get current position.
884 * @returns The current file position.
885 * @remark Will only throw error if refreshFileStatus failes.
886 */
887long kFile::getPos() const
888{
889 return offVirtual;
890}
891
892
893/**
894 * Checks if we have reached the file end.
895 * @returns TRUE if end-of-file is reached.
896 * FALSE is not end-of-file.
897 * @remark Will only throw error if refreshFileStatus failes.
898 */
899BOOL kFile::isEOF()
900{
901 #if 0
902 throw(ERROR_NOT_SUPPORTED); //this method don't currently work! Need to use flag!
903 #else
904 if (!fReadOnly && !refreshFileStatus())
905 return (BOOL)-1;
906
907 return filestatus.cbFile <= offVirtual; //??? - !!!
908 #endif
909}
910
911
912/**
913 * Set error behaviour to fail by throwing the OS/2 return code when an
914 * error occures.
915 * @returns TRUE;
916 * @remark Will never throw errors.
917 */
918BOOL kFile::setThrowOnErrors()
919{
920 fThrowErrors = TRUE;
921 rc = NO_ERROR;
922 return TRUE;
923}
924
925
926/**
927 * Set error behaviour to fail by return FALSE when an error has occures.
928 * @returns TRUE;
929 * @remark Will never throw errors.
930 */
931BOOL kFile::setFailOnErrors()
932{
933 fThrowErrors = FALSE;
934 rc = NO_ERROR;
935 return TRUE;
936}
937
938
939/**
940 * Gets the last error code.
941 * @returns OS/2 error code for the last operation.
942 * @remark Will never throw errors.
943 */
944int kFile::getLastError() const
945{
946 return rc;
947}
948
949
950
951/**
952 * Reads the specified file in to a memory block and returns it.
953 * @returns Pointer to memory mapping on success.
954 * NULL on error.
955 * @param pszFilename Name of the file.
956 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
957 * @remark May throw errors.
958 */
959void *kFile::readFile(const char *pszFilename)
960{
961 kFile file(pszFilename);
962 return file.readFile();
963}
964
Note: See TracBrowser for help on using the repository browser.