source: trunk/tools/common/kFile.cpp

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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