source: branches/gcc-kmk/tools/common/kFile.cpp@ 21759

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

Make tools/common library build.

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