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

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

Added some limited dump capabilities for PE executables.

File size: 12.3 KB
Line 
1/* $Id: kFile.cpp,v 1.5 2000-10-02 04:01:39 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
28#include "kFile.h"
29
30/*******************************************************************************
31* Global Variables *
32*******************************************************************************/
33kFile kFile::StdIn((HFILE)0, TRUE);
34kFile kFile::StdOut((HFILE)1, FALSE);
35kFile kFile::StdErr((HFILE)2, FALSE);
36
37
38/**
39 * Updates the internal filestatus struct.
40 * @returns Success indicator.
41 * On success filestatus is refreshed.
42 * @remark
43 */
44BOOL kFile::refreshFileStatus()
45{
46 if (fStdDev)
47 return fStatusClean = TRUE;
48
49 if (!fStatusClean)
50 {
51 rc = DosQueryFileInfo(hFile, FIL_QUERYEASIZE, &filestatus, sizeof(filestatus));
52 fStatusClean = (rc == NO_ERROR);
53 if (!fStatusClean && fThrowErrors)
54 throw ((int)rc);
55 }
56 else
57 rc = NO_ERROR;
58
59 return fStatusClean;
60}
61
62
63/**
64 * Changes the real file position to match the virtual file position.
65 * @returns Success indicator.
66 */
67BOOL kFile::position()
68{
69 /*
70 * If virtual file offset is different from the real,
71 * issue a set file pointer call.
72 */
73 if (offVirtual != offReal)
74 {
75 ULONG off;
76 rc = DosSetFilePtr(hFile, offVirtual, FILE_BEGIN, &off);
77 if (rc != NO_ERROR || off != offVirtual)
78 {
79 if (fThrowErrors)
80 throw ((int)rc);
81 return FALSE;
82 }
83 offReal = offVirtual;
84 }
85
86 return TRUE;
87}
88
89/**
90 * Creates a kFile object for a file that is opened allready.
91 * Intended use for the three standard handles only.
92 *
93 * @returns <object> with state updated.
94 * @param pszFilename Filename.
95 * @param fReadOnly TRUE: Open the file readonly.
96 * FALSE: Open the file readwrite appending
97 * existing files.
98 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
99 */
100kFile::kFile(HFILE hFile, BOOL fReadOnly)
101: fReadOnly(fReadOnly),
102 fStatusClean(FALSE),
103 fThrowErrors(FALSE),
104 offVirtual(0),
105 offReal(0),
106 pszFilename(NULL),
107 hFile(hFile),
108 fStdDev(TRUE)
109{
110 if (!refreshFileStatus())
111 throw ((int)rc);
112 this->pszFilename = strdup("");
113}
114
115
116/**
117 * Opens a file for binary reading or readwrite.
118 * @returns <object> with state updated.
119 * Throws OS/2 error on error.
120 * @param pszFilename Filename.
121 * @param fReadOnly TRUE: Open the file readonly. (default)
122 * FALSE: Open the file readwrite appending
123 * existing files.
124 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
125 */
126kFile::kFile(const char *pszFilename, BOOL fReadOnly/*=TRUE*/)
127: fReadOnly(fReadOnly),
128 fStatusClean(FALSE),
129 fThrowErrors(FALSE),
130 offVirtual(0),
131 offReal(0),
132 pszFilename(NULL),
133 fStdDev(FALSE)
134{
135 ULONG fulOpenFlags;
136 ULONG fulOpenMode;
137 ULONG ulAction;
138
139 /*
140 * Determin open flags according to fReadOnly.
141 */
142 if (fReadOnly)
143 {
144 fulOpenFlags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
145 fulOpenMode = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY;
146 }
147 else
148 {
149 fulOpenFlags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
150 fulOpenMode = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READWRITE;
151 }
152
153 rc = DosOpen((PCSZ)pszFilename, &hFile, &ulAction, 0, FILE_NORMAL,
154 fulOpenFlags, fulOpenMode, NULL);
155 if (rc != NO_ERROR)
156 throw ((int)rc);
157
158 if (!refreshFileStatus())
159 throw ((int)rc);
160
161 char szFullName[CCHMAXPATH];
162 if (DosQueryPathInfo(pszFilename, FIL_QUERYFULLNAME, szFullName, sizeof(szFullName)))
163 strcpy(szFullName, pszFilename);
164 this->pszFilename = strdup(szFullName);
165 if (this->pszFilename == NULL)
166 throw (ERROR_NOT_ENOUGH_MEMORY);
167}
168
169
170/**
171 * Closes the file.
172 */
173kFile::~kFile()
174{
175 DosClose(hFile);
176}
177
178
179/**
180 * Reads <cbBuffer> bytes from the current file posistion into the buffer.
181 * @returns success indicator. (TRUE/FALSE)
182 * @param pvBuffer Output buffer.
183 * @param cbBuffer Amount of bytes to read.
184 */
185BOOL kFile::read(void *pvBuffer, long cbBuffer)
186{
187 if (position())
188 {
189 ULONG cbRead;
190 rc = DosRead(hFile, pvBuffer, cbBuffer, &cbRead);
191 if (rc == NO_ERROR)
192 {
193 offVirtual = offReal += cbRead;
194 return TRUE;
195 }
196 }
197
198 if (fThrowErrors)
199 throw ((int)rc);
200 return FALSE;
201}
202
203
204/**
205 * Reads <cbBuffer> bytes at file offset <off>.
206 * @returns success indicator. (TRUE/FALSE)
207 * @param pvBuffer Output buffer.
208 * @param cbBuffer Amount of bytes to read.
209 * @param off Absolute file offset.
210 */
211BOOL kFile::readAt(void *pvBuffer, long cbBuffer, long off)
212{
213 return set(off) && read(pvBuffer, cbBuffer);
214}
215
216
217/**
218 * Reads the entire file into a single memory block.
219 * (The memory block has a '\0' at the end just in case you
220 * are using it as a long string.)
221 * @returns Pointer to file in memory.
222 */
223void * kFile::readFile() throw(int)
224{
225 void *pv;
226
227 /* allocate memory for the file */
228 pv = calloc((size_t)this->getSize() + 1, 1);
229 if (pv == NULL)
230 {
231 if (fThrowErrors)
232 throw(ERROR_NOT_ENOUGH_MEMORY);
233 return NULL;
234 }
235
236 /* go the start of the file and read it. */
237 if (start() && read(pv, this->getSize()))
238 return pv; // successfull exit!
239
240 /* we failed, cleanup and return NULL */
241 free(pv);
242 return NULL;
243}
244
245
246/**
247 * Writes <cbBuffer> bytes to the file at the current file position.
248 * @returns success indicator. (TRUE/FALSE)
249 * @param pvBuffer Output buffer.
250 * @param cbBuffer Amount of bytes to write.
251 */
252BOOL kFile::write(void *pvBuffer, long cbBuffer)
253{
254 if (fReadOnly)
255 rc = ERROR_ACCESS_DENIED;
256 else
257 {
258 if (position())
259 {
260 ULONG cbWrote;
261
262 rc = DosWrite(hFile, pvBuffer, cbBuffer, &cbWrote);
263 if (rc == NO_ERROR)
264 {
265 fStatusClean = FALSE;
266 offVirtual = offReal += cbWrote;
267 return TRUE;
268 }
269 }
270 }
271
272 if (fThrowErrors)
273 throw ((int)rc);
274 return FALSE;
275}
276
277
278/**
279 * Write <cbBuffer> bytes at file offset <off> from <pvBuffer>.
280 * @returns success indicator. (TRUE/FALSE)
281 * @param pvBuffer Output buffer.
282 * @param cbBuffer Amount of bytes to write.
283 * @param off Absolute file offset.
284 */
285BOOL kFile::writeAt(void *pvBuffer, long cbBuffer, long off)
286{
287 return set(off) && write(pvBuffer, cbBuffer);
288}
289
290
291/**
292 * printf - formatted write.
293 *
294 * Lonely '\n's are prefixed with a '\r' to make output conform with
295 * PC line ending.
296 *
297 * @returns Number of bytes written.
298 * @param pszFormat Format string.
299 * @param ... Ellipcis.
300 * @remark Currently limited to 64KB of result data.
301 */
302int kFile::printf(const char *pszFormat, ...) throw (int)
303{
304 long offStart = getPos();
305 va_list arg;
306
307 /* !QUICK AND DIRTY! */
308 char * psz, * pszEnd;
309 char * pszBuffer = (char*)malloc(1024*64); //64KB should normally be enough...
310
311 va_start(arg, pszFormat);
312 pszEnd = vsprintf(pszBuffer, pszFormat, arg) + pszBuffer;
313 va_end(arg);
314
315 psz = pszEnd;
316 while (psz > pszBuffer)
317 {
318 if (*psz-- == '\n' && *psz != '\r')
319 {
320 memmove(psz+2, psz+1, pszEnd - psz + 1);
321 psz[1] = '\r';
322 pszEnd++;
323 }
324 }
325
326 write(pszBuffer, pszEnd - pszBuffer);
327 free(pszBuffer);
328
329 return (int)(getPos() - offStart);
330}
331
332
333/**
334 * Sets the filesize.
335 * @returns Success indicator.
336 * @param cbFile New filesize.
337 * Defaults to 0xffffffff, which results in
338 * cutting the file at the current position.
339 */
340BOOL kFile::setSize(unsigned long cbFile/*= ~0UL*/)
341{
342 if (cbFile == ~0UL)
343 cbFile = offVirtual;
344 rc = DosSetFileSize(hFile, cbFile);
345 if (rc != NO_ERROR && fThrowErrors)
346 throw ((int)rc);
347
348 return rc == NO_ERROR;
349}
350
351
352
353/**
354 * Seek relative to the current position.
355 * @returns Success indicator.
356 * @param off Relative reposition.
357 */
358BOOL kFile::move(long off)
359{
360 if ((off + offVirtual) & 0x80000000UL) /* above 2GB or negative */
361 rc = ERROR_NEGATIVE_SEEK;
362 else
363 {
364 if (off + offVirtual > filestatus.cbFile && fReadOnly) /* can't expand readonly file. */
365 rc = ERROR_HANDLE_EOF;
366 else
367 {
368 offVirtual += off;
369 return TRUE;
370 }
371 }
372
373 if (fThrowErrors)
374 throw ((int)rc);
375 return FALSE;
376}
377
378
379/**
380 * Seek to an absolute position in the file (off).
381 * @returns Success indicator.
382 * @param off New file position.
383 */
384BOOL kFile::set(long off)
385{
386 if (off < 0)
387 rc = ERROR_NEGATIVE_SEEK;
388 else
389 {
390 if ((unsigned long)off > filestatus.cbFile && fReadOnly)
391 rc = ERROR_HANDLE_EOF;
392 else
393 {
394 offVirtual = off;
395 rc = NO_ERROR;
396 return TRUE;
397 }
398 }
399 if (fThrowErrors)
400 throw ((int)rc);
401 return FALSE;
402}
403
404
405/**
406 * Seek to the end of the file.
407 * @returns Success indicator. TRUE / FALSE.
408 * @remark Will only throw error if refreshFileStatus failes.
409 */
410BOOL kFile::end()
411{
412 if (!refreshFileStatus())
413 return FALSE;
414 offVirtual = filestatus.cbFile; //?? or +1
415 rc = NO_ERROR;
416 return TRUE;
417}
418
419
420/**
421 * Seek to the start of the file.
422 * @returns TRUE.
423 * @remark Will never throw errors.
424 */
425BOOL kFile::start()
426{
427 offVirtual = 0;
428 rc = NO_ERROR;
429 return TRUE;
430}
431
432
433/**
434 * Get the size of the file.
435 * @returns Returns file size on success.
436 * -1 on error.
437 * @remark Will only throw error if refreshFileStatus failes.
438 */
439long kFile::getSize()
440{
441 if (!refreshFileStatus())
442 return -1;
443
444 return filestatus.cbFile;
445}
446
447
448/**
449 * Get current position.
450 * @returns The current file position.
451 * @remark Will only throw error if refreshFileStatus failes.
452 */
453long kFile::getPos() const
454{
455 return offVirtual;
456}
457
458
459/**
460 * Checks if we have reached the file end.
461 * @returns TRUE if end-of-file is reached.
462 * FALSE is not end-of-file.
463 * @remark Will only throw error if refreshFileStatus failes.
464 */
465BOOL kFile::isEOF()
466{
467 #if 0
468 throw(ERROR_NOT_SUPPORTED); //this method don't currently work! Need to use flag!
469 #else
470 if (!refreshFileStatus())
471 return (BOOL)-1;
472
473 return filestatus.cbFile >= offReal; //???
474 #endif
475}
476
477
478/**
479 * Set error behaviour to fail by throwing the OS/2 return code when an
480 * error occures.
481 * @returns TRUE;
482 * @remark Will never throw errors.
483 */
484BOOL kFile::setThrowOnErrors()
485{
486 fThrowErrors = TRUE;
487 rc = NO_ERROR;
488 return TRUE;
489}
490
491
492/**
493 * Set error behaviour to fail by return FALSE when an error has occures.
494 * @returns TRUE;
495 * @remark Will never throw errors.
496 */
497BOOL kFile::setFailOnErrors()
498{
499 fThrowErrors = FALSE;
500 rc = NO_ERROR;
501 return TRUE;
502}
503
504
505/**
506 * Gets the last error code.
507 * @returns OS/2 error code for the last operation.
508 * @remark Will never throw errors.
509 */
510int kFile::getLastError() const
511{
512 return rc;
513}
514
Note: See TracBrowser for help on using the repository browser.