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

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

Implemented buffering of read and write in class kFile.

File size: 25.1 KB
Line 
1/* $Id: kFile.cpp,v 1.7 2000-10-05 07:27:56 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(void *pvBuffer, long cbBuffer)
559{
560 if (fReadOnly)
561 rc = ERROR_ACCESS_DENIED;
562 else
563 {
564 ULONG cbWrite;
565 ULONG cbAddPost = 0;
566
567 /* buffered writes? */
568 if (pachBuffer != NULL)
569 { /* Buffered write!
570 * Init buffer if necessary.
571 * Check if all fits into current buffer.
572 * Update buffer and return.
573 * Check if some fits into the current buffer
574 * Start - update valid part of the buffer. Commit buffer.
575 * End - update buffer. no write
576 * Not - commit buffer.
577 */
578 if (offBuffer == ~0UL)
579 { /* Empty buffer at current virtual offset */
580 cbBufferValid = offVirtual;
581 offBuffer = 0;
582 }
583
584 if ( offBuffer <= offVirtual
585 && offBuffer + this->cbBuffer > offVirtual + cbBuffer
586 )
587 { /* all fits into the buffer */
588 memcpy(&pachBuffer[offVirtual - offBuffer], pvBuffer, (size_t)cbBuffer);
589 fBufferDirty = TRUE;
590 if (cbBufferValid < offVirtual - offBuffer + cbBuffer)
591 cbBufferValid = offVirtual - offBuffer + cbBuffer;
592 offVirtual += cbBuffer;
593 return TRUE;
594 }
595 else if ( offBuffer <= offVirtual
596 && offBuffer + this->cbBufferValid > offVirtual
597 )
598 { /* start fits into the valid part of the buffer */
599 cbWrite = this->cbBuffer - (offVirtual - offBuffer);
600 memcpy(&pachBuffer[offVirtual - offBuffer], pvBuffer, (size_t)cbWrite);
601 fBufferDirty = TRUE;
602 if (cbBufferValid < offVirtual - offBuffer + cbWrite)
603 cbBufferValid = offVirtual - offBuffer + cbWrite;
604 pvBuffer = (char*)pvBuffer + cbWrite;
605 cbBuffer -= cbWrite;
606 offVirtual += cbWrite;
607 if (!bufferCommit())
608 return FALSE;
609 }
610 else if ( offBuffer < offVirtual + cbBuffer
611 && offBuffer + this->cbBuffer >= offVirtual + cbBuffer
612 )
613 { /* end fits into the buffer */
614 cbWrite = offVirtual + cbBuffer - offBuffer;
615 memcpy(pachBuffer, &((char*)pvBuffer)[offBuffer - offVirtual], (size_t)cbWrite);
616 fBufferDirty = TRUE;
617 if (cbBufferValid < cbWrite)
618 cbBufferValid = cbWrite;
619 cbBuffer -= cbWrite;
620 cbAddPost = cbWrite;
621 }
622 else if ( offVirtual + cbBuffer <= offBuffer
623 || offVirtual >= offBuffer + this->cbBufferValid
624 )
625 { /* don't fit into the buffer at all */
626 if (!bufferCommit())
627 return FALSE;
628 }
629
630 /* Set filepointer. */
631 if (!position())
632 return FALSE;
633
634 /* Write. */
635 rc = DosWrite(hFile, pvBuffer, cbBuffer, &cbWrite);
636 if (rc == NO_ERROR)
637 {
638 offVirtual = offReal += cbWrite;
639 if (cbAddPost == 0)
640 { /* no post add; start empty buffer at current virtual offset .*/
641 offBuffer = offVirtual;
642 cbBufferValid = 0;
643 fBufferDirty = FALSE;
644 }
645 else
646 offVirtual += cbAddPost;
647 return TRUE;
648 }
649 }
650 else if (position())
651 { /* non-buffered write! */
652 ULONG cbWrote;
653
654 rc = DosWrite(hFile, pvBuffer, cbBuffer, &cbWrote);
655 if (rc == NO_ERROR)
656 {
657 offVirtual = offReal += cbWrote;
658 return TRUE;
659 }
660 }
661 }
662
663 if (fThrowErrors)
664 throw ((int)rc);
665 return FALSE;
666}
667
668
669/**
670 * Write <cbBuffer> bytes at file offset <off> from <pvBuffer>.
671 * @returns success indicator. (TRUE/FALSE)
672 * @param pvBuffer Output buffer.
673 * @param cbBuffer Amount of bytes to write.
674 * @param off Absolute file offset.
675 */
676BOOL kFile::writeAt(void *pvBuffer, long cbBuffer, long off)
677{
678 return set(off) && write(pvBuffer, cbBuffer);
679}
680
681
682/**
683 * printf - formatted write.
684 *
685 * Lonely '\n's are prefixed with a '\r' to make output conform with
686 * PC line ending.
687 *
688 * @returns Number of bytes written.
689 * @param pszFormat Format string.
690 * @param ... Ellipcis.
691 * @remark Currently limited to 64KB of result data.
692 */
693int kFile::printf(const char *pszFormat, ...) throw (int)
694{
695 long offStart = getPos();
696 va_list arg;
697
698 /* !QUICK AND DIRTY! */
699 char * psz, * pszEnd;
700 static char szBuffer[1024*64]; //64KB should normally be enough for anyone...
701
702 va_start(arg, pszFormat);
703 pszEnd = vsprintf(szBuffer, pszFormat, arg) + szBuffer;
704 va_end(arg);
705
706 psz = pszEnd;
707 while (psz > szBuffer)
708 {
709 if (*psz-- == '\n' && *psz != '\r')
710 {
711 memmove(psz+2, psz+1, pszEnd - psz + 1);
712 psz[1] = '\r';
713 pszEnd++;
714 }
715 }
716
717 write(szBuffer, pszEnd - szBuffer);
718
719 return (int)(getPos() - offStart);
720}
721
722
723/**
724 * Sets the filesize.
725 * @returns Success indicator.
726 * @param cbFile New filesize.
727 * Defaults to 0xffffffff, which results in
728 * cutting the file at the current position.
729 */
730BOOL kFile::setSize(unsigned long cbFile/*= ~0UL*/)
731{
732 if (cbFile == ~0UL)
733 cbFile = offVirtual;
734 rc = DosSetFileSize(hFile, cbFile);
735 if (rc != NO_ERROR && fThrowErrors)
736 throw ((int)rc);
737
738 return rc == NO_ERROR;
739}
740
741
742/**
743 * Appends the AppendFile to this file.
744 * @returns Reference to this file.
745 * @param AppendFile Reference to the file we're to append.
746 */
747kFile & kFile::operator+=(kFile &AppendFile)
748{
749 long cb;
750 char * pachBuffer = new char[1024*256];
751 long pos = AppendFile.getPos();
752 BOOL fAppend = AppendFile.fThrowErrors;
753 BOOL fThis = fThrowErrors;
754
755 setThrowOnErrors();
756 AppendFile.setThrowOnErrors();
757
758 end();
759 AppendFile.start();
760 AppendFile.refreshFileStatus();
761
762 cb = min(1024*256, AppendFile.filestatus.cbFile);
763 while (cb > 0)
764 {
765 AppendFile.read(pachBuffer, cb);
766 write(pachBuffer, cb);
767 cb = min(1024*256, (long)AppendFile.filestatus.cbFile - (long)AppendFile.offVirtual);
768 }
769
770 delete pachBuffer;
771 AppendFile.set(pos);
772 AppendFile.fThrowErrors = fAppend;
773 fThrowErrors = fThis;
774
775 return *this;
776}
777
778
779/**
780 * Seek relative to the current position.
781 * @returns Success indicator.
782 * @param off Relative reposition.
783 */
784BOOL kFile::move(long off)
785{
786 if ((off + offVirtual) & 0x80000000UL) /* above 2GB or negative */
787 rc = ERROR_NEGATIVE_SEEK;
788 else
789 {
790 if (off + offVirtual > filestatus.cbFile && fReadOnly) /* can't expand readonly file. */
791 rc = ERROR_HANDLE_EOF;
792 else
793 {
794 offVirtual += off;
795 return TRUE;
796 }
797 }
798
799 if (fThrowErrors)
800 throw ((int)rc);
801 return FALSE;
802}
803
804
805/**
806 * Seek to an absolute position in the file (off).
807 * @returns Success indicator.
808 * @param off New file position.
809 */
810BOOL kFile::set(long off)
811{
812 if (off < 0)
813 rc = ERROR_NEGATIVE_SEEK;
814 else
815 {
816 if ((unsigned long)off > filestatus.cbFile && fReadOnly)
817 rc = ERROR_HANDLE_EOF;
818 else
819 {
820 offVirtual = off;
821 rc = NO_ERROR;
822 return TRUE;
823 }
824 }
825 if (fThrowErrors)
826 throw ((int)rc);
827 return FALSE;
828}
829
830
831/**
832 * Seek to the end of the file.
833 * @returns Success indicator. TRUE / FALSE.
834 * @remark Will only throw error if refreshFileStatus failes.
835 */
836BOOL kFile::end()
837{
838 if (!refreshFileStatus())
839 return FALSE;
840
841 if (!fReadOnly && pachBuffer && offBuffer != ~0UL && offBuffer + cbBufferValid > filestatus.cbFile)
842 /* a writable file with buffer might have uncommited data in the buffer. */
843 offVirtual = offBuffer + cbBufferValid;
844 else
845 offVirtual = filestatus.cbFile;
846
847 rc = NO_ERROR;
848 return TRUE;
849}
850
851
852/**
853 * Seek to the start of the file.
854 * @returns TRUE.
855 * @remark Will never throw errors.
856 */
857BOOL kFile::start()
858{
859 offVirtual = 0;
860 rc = NO_ERROR;
861 return TRUE;
862}
863
864
865/**
866 * Get the size of the file.
867 * @returns Returns file size on success.
868 * -1 on error.
869 * @remark Will only throw error if refreshFileStatus failes.
870 */
871long kFile::getSize()
872{
873 if (!refreshFileStatus())
874 return -1;
875
876 return filestatus.cbFile;
877}
878
879
880/**
881 * Get current position.
882 * @returns The current file position.
883 * @remark Will only throw error if refreshFileStatus failes.
884 */
885long kFile::getPos() const
886{
887 return offVirtual;
888}
889
890
891/**
892 * Checks if we have reached the file end.
893 * @returns TRUE if end-of-file is reached.
894 * FALSE is not end-of-file.
895 * @remark Will only throw error if refreshFileStatus failes.
896 */
897BOOL kFile::isEOF()
898{
899 #if 0
900 throw(ERROR_NOT_SUPPORTED); //this method don't currently work! Need to use flag!
901 #else
902 if (!fReadOnly && !refreshFileStatus())
903 return (BOOL)-1;
904
905 return filestatus.cbFile <= offVirtual; //??? - !!!
906 #endif
907}
908
909
910/**
911 * Set error behaviour to fail by throwing the OS/2 return code when an
912 * error occures.
913 * @returns TRUE;
914 * @remark Will never throw errors.
915 */
916BOOL kFile::setThrowOnErrors()
917{
918 fThrowErrors = TRUE;
919 rc = NO_ERROR;
920 return TRUE;
921}
922
923
924/**
925 * Set error behaviour to fail by return FALSE when an error has occures.
926 * @returns TRUE;
927 * @remark Will never throw errors.
928 */
929BOOL kFile::setFailOnErrors()
930{
931 fThrowErrors = FALSE;
932 rc = NO_ERROR;
933 return TRUE;
934}
935
936
937/**
938 * Gets the last error code.
939 * @returns OS/2 error code for the last operation.
940 * @remark Will never throw errors.
941 */
942int kFile::getLastError() const
943{
944 return rc;
945}
946
Note: See TracBrowser for help on using the repository browser.