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

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

New kFile* classes; now in sync with os2tools.

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