1 /**
2 * @namespace biewlib
3 * @file biewlib/bbio.c
4 * @brief This file contains implementation of Buffering binary input/ouput routines.
5 * @version -
6 * @remark this source file is part of Binary vIEW project (BIEW).
7 * The Binary vIEW (BIEW) is copyright (C) 1995 Nickols_K.
8 * All rights reserved. This software is redistributable under the
9 * licence given in the file "Licence.en" ("Licence.ru" in russian
10 * translation) distributed in the BIEW archive.
11 * @note Requires POSIX compatible development system
12 *
13 * @author Nickols_K
14 * @since 1995
15 * @note Development, fixes and improvements
16 * @todo Support for preemptive memory allocation and multiple buffers for
17 * one opened stream
18 **/
19 #include <sys/stat.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <limits.h>
25
26 #include "biewlib/bbio.h"
27 #include "biewlib/pmalloc.h"
28
29 #define MK_FPTR(x) (x)
30
31 #define IS_CACHE_VALID(obj) ((obj)->b.vfb.MBuffer && !((obj)->optimize & BIO_OPT_NOCACHE))
32 #define IS_WRITEABLE(openmode) (((openmode) & FO_READWRITE) || ((openmode) & FO_WRITEONLY))
33
34 struct tagBFILE bNull =
35 {
36 0L,
37 0L,
38 NULL,
39 0,
40 0,
41 False,
42 False,
43 {
44 {
45 NULL_HANDLE,
46 0L,
47 NULL,
48 0,
49 0,
50 True
51 }
52 },
53 False
54 };
55
56 /* notes: all function with prefix=>__ assume, that buffer present */
57
58 #define __isOutOfBuffer(obj,pos)\
59 (int)(((__filesize_t)pos < ((BFILE *)obj)->b.vfb.FBufStart ||\
60 (__filesize_t)pos >= ((BFILE *)obj)->b.vfb.FBufStart +\
61 ((BFILE *)obj)->b.vfb.MBufSize) && !((BFILE *)obj)->is_mmf)
62
63 #define __isOutOfContents(obj,pos)\
64 (int)(((__filesize_t)pos < ((BFILE *)obj)->b.vfb.FBufStart ||\
65 (__filesize_t)pos >= ((BFILE *)obj)->b.vfb.FBufStart +\
66 ((BFILE *)obj)->b.vfb.MBufLen) && !((BFILE *)obj)->is_mmf)
67
__fill(BFILE * obj,__fileoff_t pos)68 static tBool __NEAR__ __FASTCALL__ __fill(BFILE *obj,__fileoff_t pos)
69 {
70 void * mbuff;
71 __filesize_t remaind;
72 tBool ret;
73 if(pos < 0) pos = 0;
74 if((__filesize_t)pos > obj->FLength)
75 {
76 pos = obj->FLength;
77 obj->b.vfb.MBufLen = 0;
78 ret = False;
79 }
80 else
81 {
82 obj->b.vfb.FBufStart = pos;
83 remaind = obj->FLength - pos;
84 obj->b.vfb.MBufLen = (__filesize_t)obj->b.vfb.MBufSize < remaind ?
85 obj->b.vfb.MBufSize : (unsigned)remaind;
86 mbuff = MK_FPTR(obj->b.vfb.MBuffer);
87 __OsSeek(obj->b.vfb.handle,pos,SEEKF_START);
88 ret = (unsigned)__OsRead(obj->b.vfb.handle,mbuff,obj->b.vfb.MBufLen) == obj->b.vfb.MBufLen;
89 }
90 return ret;
91 }
92
__flush(BFILE * obj)93 static tBool __NEAR__ __FASTCALL__ __flush(BFILE *obj)
94 {
95 void * mbuff;
96 tBool ret;
97 ret = True;
98 if(!obj->b.vfb.updated)
99 {
100 mbuff = MK_FPTR(obj->b.vfb.MBuffer);
101 __OsSeek(obj->b.vfb.handle,obj->b.vfb.FBufStart,SEEKF_START);
102 if(obj->b.vfb.MBufLen) ret = (unsigned)__OsWrite(obj->b.vfb.handle,mbuff,obj->b.vfb.MBufLen) == obj->b.vfb.MBufLen;
103 if(ret) obj->b.vfb.updated = True;
104 }
105 return ret;
106 }
107
108 #define CHK_EOF(obj,pos)\
109 {\
110 ((BFILE *)obj)->is_eof = False;\
111 /* Accessing memory after mmf[FLength-1] causes GPF in MMF mode */\
112 /* so we must add special checks for it but no for read-write mode */\
113 /* Special case: FLength == 0. When file is being created pos == FLength.*/\
114 if(obj->FLength && !IS_WRITEABLE(obj->openmode)\
115 && (__filesize_t)pos >= (__filesize_t)obj->FLength)\
116 {\
117 pos = ((BFILE *)obj)->FLength-1;\
118 ret = False;\
119 ((BFILE *)obj)->is_eof = True;\
120 }\
121 }
122
123 #define SEEK_FPTR(ret,obj,pos,origin)\
124 {\
125 ret = True;\
126 switch((int)origin)\
127 {\
128 case BIO_SEEK_SET: break;\
129 case BIO_SEEK_CUR: pos += ((BFILE *)obj)->FilePos; break;\
130 default: pos += ((BFILE *)obj)->FLength;\
131 }\
132 CHK_EOF(obj,pos)\
133 }
134
__seek(BFILE * obj,__fileoff_t pos,int origin)135 static tBool __NEAR__ __FASTCALL__ __seek(BFILE *obj,__fileoff_t pos,int origin)
136 {
137 tBool ret,rret;
138 SEEK_FPTR(ret,obj,pos,origin);
139 obj->FilePos = pos;
140 if(__isOutOfBuffer(obj,pos))
141 {
142 __flush(obj);
143 switch(obj->optimize & BIO_OPT_DIRMASK)
144 {
145 default:
146 case BIO_OPT_DB: break;
147 case BIO_OPT_RANDOM: pos -= obj->b.vfb.MBufSize / 2;
148 break;
149 case BIO_OPT_BACKSCAN: pos -= (obj->b.vfb.MBufSize - 1);
150 break;
151 case BIO_OPT_RFORWARD: pos -= obj->b.vfb.MBufSize / 10;
152 break;
153 case BIO_OPT_RBACKSCAN: pos -= (obj->b.vfb.MBufSize/10)*9;
154 break;
155 }
156 if(obj->FilePos < obj->FLength)
157 {
158 rret = __fill(obj,pos);
159 if(ret) ret = rret;
160 }
161 else
162 {
163 obj->b.vfb.FBufStart = obj->FilePos;
164 obj->b.vfb.MBufLen = 0;
165 }
166 }
167 return ret;
168 }
169
170 static tBool founderr;
171
__getc(BFILE * obj)172 static unsigned char __NEAR__ __FASTCALL__ __getc(BFILE *obj)
173 {
174 char * buff = MK_FPTR(obj->b.vfb.MBuffer);
175 unsigned buffpos;
176 tBool ret;
177 unsigned char ch;
178 ret = True;
179 founderr = False;
180 if(__isOutOfContents(obj,obj->FilePos)) ret = __seek(obj,obj->FilePos,SEEKF_START);
181 ch = -1;
182 if(obj->b.vfb.MBufLen && ret && obj->FilePos <= obj->FLength)
183 {
184 buffpos = (unsigned)(obj->FilePos - obj->b.vfb.FBufStart);
185 if(buffpos < obj->b.vfb.MBufLen) ch = buff[buffpos];
186 if(obj->FilePos < obj->FLength) obj->FilePos++;
187 CHK_EOF(obj,obj->FilePos);
188 }
189 else
190 {
191 errno = EACCES;
192 ret = False;
193 }
194 if(ret == False) founderr = True;
195 return ch;
196 }
197
__putc(BFILE * obj,unsigned char ch)198 static tBool __NEAR__ __FASTCALL__ __putc(BFILE *obj,unsigned char ch)
199 {
200 char * buff;
201 unsigned buffpos;
202 tBool ret;
203 if(IS_WRITEABLE(obj->openmode))
204 {
205 ret = True;
206 buff = MK_FPTR(obj->b.vfb.MBuffer);
207 if(__isOutOfBuffer(obj,obj->FilePos)) __seek(obj,obj->FilePos,SEEKF_START);
208 buffpos = (unsigned)(obj->FilePos - obj->b.vfb.FBufStart);
209 buff[buffpos++] = ch;
210 obj->b.vfb.updated = False;
211 if(obj->b.vfb.MBufLen < buffpos)
212 if(obj->b.vfb.MBufLen < obj->b.vfb.MBufSize) obj->b.vfb.MBufLen = buffpos;
213 if(obj->FLength <= obj->b.vfb.FBufStart + buffpos)
214 obj->FLength = obj->b.vfb.FBufStart + buffpos;
215 obj->FilePos++;
216 }
217 else { errno = EACCES; ret = False; }
218 return ret;
219 }
220
221 #if 0
222 static void __NEAR__ __FASTCALL__ dump_BFILE(BFILE*obj)
223 {
224 fprintf(stderr,
225 " %p\n"
226 " FilePos=%llu FLength=%llu\n"
227 " %s openmode=%u optimize=%i\n"
228 " is_mmf=%i primary_mmf=%i\n"
229 " VFB:\n"
230 " handle = %p FBufStart=%llu MBuffer=%p\n"
231 " MBufLen=%u MBufSize=%u updated=%u\n"
232 " MMB: mmf=%p mmf_addr=%p\n"
233 " handle = %p FBufStart=%llu MBuffer=%p\n"
234 " MBufLen=%u MBufSize=%u updated=%u\n"
235 " is_eof=%i\n"
236 ,obj
237 ,obj->FilePos,obj->FLength
238 ,obj->FileName,obj->openmode,obj->optimize
239 ,obj->is_mmf,obj->primary_mmf
240 ,obj->b.vfb.handle,obj->b.vfb.FBufStart,obj->b.vfb.MBuffer
241 ,obj->b.vfb.MBufLen,obj->b.vfb.MBufSize,obj->b.vfb.updated
242 ,obj->is_mmf?obj->b.mmb->mmf:0,obj->is_mmf?obj->b.mmb->mmf_addr:0
243 ,obj->is_eof);
244 }
245 #endif
246
__getbuff(BFILE * obj,char * buff,unsigned cbBuff)247 static tBool __NEAR__ __FASTCALL__ __getbuff(BFILE *obj,char * buff,unsigned cbBuff)
248 {
249 unsigned diffsize;
250 unsigned MBufStart,MBufRem;
251 int optimize = obj->optimize;
252 tBool ret = True;
253 if(obj->is_mmf)
254 {
255 tUInt32 size = min(cbBuff,obj->FLength - obj->FilePos);
256 CHK_EOF(obj,obj->FilePos);
257 if(size && ret)
258 {
259 memcpy(buff,((tUInt8 *)obj->b.mmb->mmf_addr) + obj->FilePos,size);
260 obj->FilePos += size;
261 }
262 }
263 else
264 {
265 obj->optimize = (optimize & ~BIO_OPT_DIRMASK) | BIO_OPT_DB;
266 while(cbBuff)
267 {
268 MBufStart = (unsigned)(obj->FilePos - obj->b.vfb.FBufStart);
269 MBufRem = obj->b.vfb.MBufLen - MBufStart;
270 if(!MBufRem || __isOutOfContents(obj,obj->FilePos))
271 {
272 ret = __seek(obj,obj->FilePos,SEEKF_START);
273 if(!ret) break;
274 if(obj->FilePos >= obj->FLength) break;
275 MBufStart = (unsigned)(obj->FilePos - obj->b.vfb.FBufStart);
276 MBufRem = obj->b.vfb.MBufLen - MBufStart;
277 }
278 if(!MBufRem)
279 {
280 errno = E2BIG; /* fault: internal error */
281 ret = False;
282 break;
283 }
284 diffsize = min(MBufRem,cbBuff);
285 memcpy(buff,&obj->b.vfb.MBuffer[MBufStart],diffsize);
286 obj->FilePos += diffsize;
287 if(obj->FilePos > obj->FLength) obj->FilePos = obj->FLength;
288 cbBuff -= diffsize;
289 buff += diffsize;
290 }
291 obj->optimize = optimize;
292 }
293 return ret;
294 }
295
__putbuff(BFILE * obj,const char * buff,unsigned cbBuff)296 static tBool __NEAR__ __FASTCALL__ __putbuff(BFILE *obj,const char * buff,unsigned cbBuff)
297 {
298 unsigned diffsize;
299 unsigned MBufStart,MBufRem;
300 int optimize = obj->optimize;
301 tBool ret = True;
302 if(IS_WRITEABLE(obj->openmode))
303 {
304 if(obj->is_mmf)
305 {
306 tUInt32 size = min(cbBuff,obj->FLength - obj->FilePos);
307 if(size)
308 {
309 memcpy(((tUInt8 *)obj->b.mmb->mmf_addr) + obj->FilePos,buff,size);
310 obj->FilePos += size;
311 }
312 }
313 else
314 {
315 obj->optimize = (optimize & ~BIO_OPT_DIRMASK) | BIO_OPT_DB;
316 ret = True;
317 while(cbBuff)
318 {
319 MBufStart = (unsigned)(obj->FilePos - obj->b.vfb.FBufStart);
320 MBufRem = obj->b.vfb.MBufSize - MBufStart;
321 if(!MBufRem || __isOutOfBuffer(obj,obj->FilePos))
322 {
323 ret = __seek(obj,obj->FilePos,SEEKF_START);
324 if(!ret) break;
325 MBufStart = (unsigned)(obj->FilePos - obj->b.vfb.FBufStart);
326 MBufRem = obj->b.vfb.MBufSize - MBufStart;
327 }
328 if(!MBufRem)
329 {
330 errno = E2BIG; /* fault: internal error */
331 ret = False;
332 break;
333 }
334 diffsize = min(MBufRem,cbBuff);
335 memcpy(&obj->b.vfb.MBuffer[MBufStart],buff,diffsize);
336 obj->b.vfb.updated = False;
337 if(obj->b.vfb.MBufLen < MBufStart + diffsize) obj->b.vfb.MBufLen = MBufStart + diffsize;
338 if(obj->FLength < obj->FilePos + diffsize) obj->FLength = obj->FilePos + diffsize;
339 obj->FilePos += diffsize;
340 cbBuff -= diffsize;
341 buff += diffsize;
342 }
343 obj->optimize = optimize;
344 }
345 }
346 else { errno = EACCES; ret = False; }
347 return ret;
348 }
349
bioOpen(const char * fname,unsigned openmode,unsigned bSize,unsigned optimization)350 BGLOBAL __FASTCALL__ bioOpen(const char * fname,unsigned openmode,unsigned bSize,unsigned optimization)
351 {
352 BFILE * bFile;
353 BGLOBAL ret = NULL;
354 unsigned len;
355 ret = PMalloc(sizeof(BFILE));
356 if(ret)
357 {
358 memset(ret,0,sizeof(BFILE));
359 bFile = MK_FPTR(ret);
360 bFile->openmode = openmode;
361 if(!(bFile->FileName = PMalloc(strlen(fname)+1)))
362 {
363 PFREE(bFile);
364 return &bNull;
365 }
366 strcpy(bFile->FileName,fname);
367 /* Attempt open as MMF */
368 if(!IS_WRITEABLE(openmode) && optimization == BIO_OPT_USEMMF)
369 {
370 if((bFile->b.mmb = PMalloc(sizeof(mmb))))
371 {
372 if((bFile->b.mmb->mmf = __mmfOpen(fname,openmode)) != NULL)
373 {
374 bFile->b.mmb->mmf_addr = __mmfAddress(bFile->b.mmb->mmf);
375 bFile->FLength = __mmfSize(bFile->b.mmb->mmf);
376 bFile->primary_mmf = True;
377 bFile->is_mmf = True;
378 bFile->b.vfb.MBuffer = NULL; /* [dBorca] be consistent with IS_CACHE_VALID */
379 }
380 else PFREE(bFile->b.mmb);
381 }
382 }
383 if(!bFile->is_mmf)
384 {
385 bhandle_t handle = __OsOpen(fname,openmode);
386 optimization = BIO_OPT_DB;
387 if(handle == NULL_HANDLE)
388 {
389 PFREE(bFile->FileName);
390 PFREE(ret);
391 return &bNull;
392 }
393 bFile->b.vfb.handle = handle;
394 bFile->optimize = optimization;
395 bFile->b.vfb.FBufStart = 0L;
396 bFile->b.vfb.updated = True;
397 bFile->is_mmf = False;
398 bFile->FLength = __FileLength(bFile->b.vfb.handle);
399 len = bSize;
400 if(bSize == UINT_MAX) len = (unsigned)bFile->FLength;
401 if(len)
402 {
403 if((bFile->b.vfb.MBuffer = PMalloc(len)) != NULL)
404 {
405 bFile->b.vfb.MBufLen = 0;
406 bFile->b.vfb.MBufSize = len;
407 }
408 else
409 {
410 PFREE(bFile->FileName);
411 __OsClose(bFile->b.vfb.handle);
412 PFREE(ret);
413 return &bNull;
414 }
415 __fill(bFile,0L);
416 }
417 else bFile->b.vfb.MBuffer = NULL;
418 }
419 }
420 else ret = &bNull;
421 return ret;
422 }
423
bioClose(BGLOBAL handle)424 tBool __FASTCALL__ bioClose(BGLOBAL handle)
425 {
426 BFILE * bFile = MK_FPTR(handle);
427 if(bFile->is_mmf)
428 {
429 if(bFile->primary_mmf)
430 {
431 __mmfClose(bFile->b.mmb->mmf);
432 PFREE(bFile->b.mmb);
433 }
434 }
435 else
436 {
437 if(bFile->b.vfb.handle != NULL_HANDLE)
438 {
439 if(IS_WRITEABLE(bFile->openmode)) __flush(bFile);
440 /* For compatibility with DOS-32: don't try to close stderr */
441 if(bFile->b.vfb.handle != (bhandle_t)2) __OsClose(bFile->b.vfb.handle);
442 }
443 if(bFile->b.vfb.MBuffer) PFREE(bFile->b.vfb.MBuffer);
444 }
445 PFREE(bFile->FileName);
446 PFREE(handle);
447 return True;
448 }
449
bioSeek(BGLOBAL bioFile,__fileoff_t pos,int orig)450 tBool __FASTCALL__ bioSeek(BGLOBAL bioFile,__fileoff_t pos,int orig)
451 {
452 BFILE *obj =MK_FPTR(bioFile);
453 tBool ret;
454 if(IS_CACHE_VALID(obj)) ret = __seek(obj,pos,orig);
455 else
456 {
457 if(obj->is_mmf)
458 {
459 SEEK_FPTR(ret,obj,pos,orig);
460 obj->FilePos = pos;
461 }
462 else
463 {
464 ret = __OsSeek(obj->b.vfb.handle,pos,orig) != 0;
465 if(pos == 0L && orig == SEEKF_START) ret = True;
466 }
467 }
468 return ret;
469 }
470
bioTell(BGLOBAL bioFile)471 __filesize_t __FASTCALL__ bioTell(BGLOBAL bioFile)
472 {
473 BFILE *obj = MK_FPTR(bioFile);
474 return (IS_CACHE_VALID(obj) || obj->is_mmf) ? obj->FilePos : (__filesize_t)__OsTell(obj->b.vfb.handle);
475 }
476
bioReadByte(BGLOBAL bioFile)477 tUInt8 __FASTCALL__ bioReadByte(BGLOBAL bioFile)
478 {
479 BFILE *obj = MK_FPTR(bioFile);
480 tUInt8 ret;
481 if(IS_CACHE_VALID(obj) && !obj->is_mmf) {
482 ret = __getc(obj);
483 }
484 else {
485 if(obj->is_mmf)
486 {
487 tUInt8 rval;
488 rval = ret = ((tUInt8 *)obj->b.mmb->mmf_addr)[obj->FilePos];
489 if(obj->FilePos < obj->FLength) obj->FilePos++;
490 CHK_EOF(obj,obj->FilePos);
491 ret = rval;
492 }
493 else {
494 if(__OsRead(obj->b.vfb.handle,&ret,sizeof(tUInt8)) != sizeof(tUInt8)) ret = -1;
495 }
496 }
497 return ret;
498 }
499
bioReadWord(BGLOBAL bioFile)500 tUInt16 __FASTCALL__ bioReadWord(BGLOBAL bioFile)
501 {
502 BFILE *obj = MK_FPTR(bioFile);
503 tUInt16 ret;
504 if(IS_CACHE_VALID(obj) || obj->is_mmf)
505 {
506 if(!__getbuff(obj,(void *)&ret,sizeof(tUInt16))) ret = -1;
507 }
508 else
509 if(__OsRead(obj->b.vfb.handle,&ret,sizeof(tUInt16)) != sizeof(tUInt16)) ret = -1;
510 return ret;
511 }
512
bioReadDWord(BGLOBAL bioFile)513 tUInt32 __FASTCALL__ bioReadDWord(BGLOBAL bioFile)
514 {
515 BFILE *obj = MK_FPTR(bioFile);
516 tUInt32 ret;
517 if(IS_CACHE_VALID(obj) || obj->is_mmf)
518 {
519 if(!__getbuff(obj,(void *)&ret,sizeof(tUInt32))) ret = -1;
520 }
521 else
522 if(__OsRead(obj->b.vfb.handle,&ret,sizeof(tUInt32)) != sizeof(tUInt32)) ret = -1;
523 return ret;
524 }
525
bioReadQWord(BGLOBAL bioFile)526 tUInt64 __FASTCALL__ bioReadQWord(BGLOBAL bioFile)
527 {
528 BFILE *obj = MK_FPTR(bioFile);
529 tUInt64 ret;
530 if(IS_CACHE_VALID(obj) || obj->is_mmf)
531 {
532 if(!__getbuff(obj,(void *)&ret,sizeof(tUInt64))) ret = -1;
533 }
534 else
535 if(__OsRead(obj->b.vfb.handle,&ret,sizeof(tUInt64)) != sizeof(tUInt64)) ret = -1;
536 return ret;
537 }
538
bioReadBuffer(BGLOBAL bioFile,void * buffer,unsigned cbBuffer)539 tBool __FASTCALL__ bioReadBuffer(BGLOBAL bioFile,void * buffer,unsigned cbBuffer)
540 {
541 BFILE *obj = MK_FPTR(bioFile);
542 return IS_CACHE_VALID(obj) || obj->is_mmf ?
543 __getbuff(obj,buffer,cbBuffer) :
544 ((unsigned)__OsRead(obj->b.vfb.handle,buffer,cbBuffer)) == cbBuffer;
545 }
546
bioWriteByte(BGLOBAL bioFile,tUInt8 bVal)547 tBool __FASTCALL__ bioWriteByte(BGLOBAL bioFile,tUInt8 bVal)
548 {
549 BFILE *obj = MK_FPTR(bioFile);
550 tBool ret = True;
551 if(IS_CACHE_VALID(obj)) ret = __putc(obj,bVal);
552 else
553 ret = __OsWrite(obj->b.vfb.handle,&bVal,sizeof(tUInt8)) == sizeof(tUInt8);
554 return ret;
555 }
556
bioWriteWord(BGLOBAL bioFile,tUInt16 wVal)557 tBool __FASTCALL__ bioWriteWord(BGLOBAL bioFile,tUInt16 wVal)
558 {
559 BFILE *obj = MK_FPTR(bioFile);
560 return IS_CACHE_VALID(obj) ?
561 __putbuff(obj,(void *)&wVal,sizeof(tUInt16)) :
562 __OsWrite(obj->b.vfb.handle,&wVal,sizeof(tUInt16)) == sizeof(tUInt16);
563 }
564
bioWriteDWord(BGLOBAL bioFile,tUInt32 dwVal)565 tBool __FASTCALL__ bioWriteDWord(BGLOBAL bioFile,tUInt32 dwVal)
566 {
567 BFILE *obj = MK_FPTR(bioFile);
568 return IS_CACHE_VALID(obj) ?
569 __putbuff(obj,(void *)&dwVal,sizeof(tUInt32)) :
570 __OsWrite(obj->b.vfb.handle,&dwVal,sizeof(tUInt32)) == sizeof(tUInt32);
571 }
572
bioWriteQWord(BGLOBAL bioFile,tUInt64 dwVal)573 tBool __FASTCALL__ bioWriteQWord(BGLOBAL bioFile,tUInt64 dwVal)
574 {
575 BFILE *obj = MK_FPTR(bioFile);
576 return IS_CACHE_VALID(obj) ?
577 __putbuff(obj,(void *)&dwVal,sizeof(tUInt64)) :
578 __OsWrite(obj->b.vfb.handle,&dwVal,sizeof(tUInt64)) == sizeof(tUInt64);
579 }
580
bioWriteBuffer(BGLOBAL bioFile,const void * buffer,unsigned cbBuffer)581 tBool __FASTCALL__ bioWriteBuffer(BGLOBAL bioFile,const void * buffer,unsigned cbBuffer)
582 {
583 BFILE *obj = MK_FPTR(bioFile);
584 return IS_CACHE_VALID(obj) ?
585 __putbuff(obj,buffer,cbBuffer) :
586 ((unsigned)__OsWrite(obj->b.vfb.handle,buffer,cbBuffer)) == cbBuffer;
587 }
588
bioFlush(BGLOBAL bioFile)589 tBool __FASTCALL__ bioFlush(BGLOBAL bioFile)
590 {
591 BFILE * obj = MK_FPTR(bioFile);
592 return IS_CACHE_VALID(obj) ? __flush(obj) : obj->is_mmf ? __mmfFlush(obj->b.mmb->mmf) : True;
593 }
594
bioReRead(BGLOBAL bioFile)595 tBool __FASTCALL__ bioReRead(BGLOBAL bioFile)
596 {
597 __filesize_t fpos;
598 BFILE * obj = MK_FPTR(bioFile);
599 tBool ret = True;
600 if(obj->is_mmf)
601 {
602 obj->b.mmb->mmf = __mmfSync(obj->b.mmb->mmf);
603 if(obj->b.mmb->mmf)
604 {
605 obj->b.mmb->mmf_addr = __mmfAddress(obj->b.mmb->mmf);
606 obj->FLength = __mmfSize(obj->b.mmb->mmf);
607 }
608 /** @todo Most reliable code */
609 else { printm("Internal error occured in __mmfSync\n"); exit(EXIT_FAILURE); }
610 }
611 else
612 {
613 fpos = __OsTell(obj->b.vfb.handle);
614 __OsSeek(obj->b.vfb.handle,0L,SEEKF_END);
615 obj->FLength = __OsTell(obj->b.vfb.handle);
616 __OsSeek(obj->b.vfb.handle,fpos,SEEKF_START);
617 ret = __fill(obj,obj->b.vfb.FBufStart);
618 }
619 return ret;
620 }
621
bioFLength(BGLOBAL bioFile)622 __filesize_t __FASTCALL__ bioFLength(BGLOBAL bioFile)
623 {
624 BFILE * bFile = MK_FPTR(bioFile);
625 return bFile->FLength;
626 }
627
bioChSize(BGLOBAL bioFile,__filesize_t newsize)628 tBool __FASTCALL__ bioChSize(BGLOBAL bioFile,__filesize_t newsize)
629 {
630 __filesize_t length, fillsize;
631 char * buf;
632 BFILE *obj = MK_FPTR(bioFile);
633 unsigned bufsize, numtowrite;
634 tBool ret;
635 if(obj->is_mmf)
636 {
637 if((ret=__mmfResize(obj->b.mmb->mmf,newsize)))
638 {
639 obj->b.mmb->mmf_addr = __mmfAddress(obj->b.mmb->mmf);
640 obj->FLength = __mmfSize(obj->b.mmb->mmf);
641 }
642 }
643 else
644 {
645 length = obj->FLength;
646 if(length >= newsize) /* truncate size */
647 {
648 __seek(obj, newsize, SEEKF_START);
649 length = newsize;
650 ret = __OsTruncFile(obj->b.vfb.handle, length) != 0;
651 obj->FLength = newsize;
652 if(obj->b.vfb.FBufStart > obj->FLength) { obj->b.vfb.FBufStart = obj->FLength; obj->b.vfb.MBufLen = 0; }
653 if(obj->b.vfb.FBufStart + obj->b.vfb.MBufLen > obj->FLength) obj->b.vfb.MBufLen = (unsigned)(obj->FLength - obj->b.vfb.FBufStart);
654 ret = ret ? False : True;
655 }
656 else
657 {
658 fillsize=newsize-length; /* increase size */
659 ret = False;
660 bufsize = obj->b.vfb.MBuffer ? obj->b.vfb.MBufSize : 8192;
661 bufsize = (unsigned) min(fillsize,bufsize);
662 if((buf = PMalloc(bufsize)) != NULL)
663 {
664 ret = True;
665 memset(buf, 0, bufsize); /* write zeros to pad file */
666 bioSeek(bioFile,0L,SEEKF_END);
667 do
668 {
669 numtowrite = (unsigned)min(bufsize,fillsize);
670 if(!bioWriteBuffer(bioFile, (void * )buf, numtowrite)) { ret = False; break; }
671 fillsize-=numtowrite;
672 } while(fillsize);
673 PFREE(buf);
674 }
675 }
676 }
677 return ret;
678 }
679
bioSetOptimization(BGLOBAL bioFile,unsigned flags)680 unsigned __FASTCALL__ bioSetOptimization(BGLOBAL bioFile,unsigned flags)
681 {
682 BFILE *obj = MK_FPTR(bioFile);
683 unsigned ret;
684 ret = obj->optimize;
685 obj->optimize = flags;
686 return ret;
687 return flags;
688 }
689
bioGetOptimization(BGLOBAL bioFile)690 unsigned __FASTCALL__ bioGetOptimization(BGLOBAL bioFile)
691 {
692 BFILE *obj = MK_FPTR(bioFile);
693 return obj->optimize;
694 }
695
bioHandle(BGLOBAL bioFile)696 bhandle_t __FASTCALL__ bioHandle(BGLOBAL bioFile)
697 {
698 BFILE *obj = MK_FPTR(bioFile);
699 return obj->b.vfb.handle;
700 }
701
bioFileName(BGLOBAL bioFile)702 char * __FASTCALL__ bioFileName(BGLOBAL bioFile)
703 {
704 BFILE *obj = MK_FPTR(bioFile);
705 return obj->FileName;
706 }
707
bioBuffer(BGLOBAL bioFile)708 void * __FASTCALL__ bioBuffer(BGLOBAL bioFile)
709 {
710 BFILE *obj = MK_FPTR(bioFile);
711 return obj->is_mmf ? obj->b.mmb->mmf_addr : obj->b.vfb.MBuffer;
712 }
713
bioBuffLen(BGLOBAL bioFile)714 unsigned __FASTCALL__ bioBuffLen(BGLOBAL bioFile)
715 {
716 BFILE *obj = MK_FPTR(bioFile);
717 return obj->is_mmf ? obj->FLength : obj->b.vfb.MBufLen;
718 }
719
bioBuffPos(BGLOBAL bioFile)720 unsigned __FASTCALL__ bioBuffPos(BGLOBAL bioFile)
721 {
722 BFILE *obj = MK_FPTR(bioFile);
723 return obj->is_mmf ? 0L : obj->b.vfb.MBufLen - (unsigned)(obj->FilePos - obj->b.vfb.FBufStart);
724 }
725
bioDupEx(BGLOBAL bioFile,unsigned buff_Size)726 BGLOBAL __FASTCALL__ bioDupEx(BGLOBAL bioFile,unsigned buff_Size)
727 {
728 BGLOBAL ret = NULL;
729 unsigned len;
730 ret = PMalloc(sizeof(BFILE));
731 if(ret)
732 {
733 BFILE * bFile,* fromFile;
734 bFile = MK_FPTR(ret);
735 fromFile = MK_FPTR(bioFile);
736 bFile->openmode = fromFile->openmode;
737 bFile->optimize = fromFile->optimize;
738 bFile->is_eof = fromFile->is_eof;
739 if(!(bFile->FileName = PMalloc(strlen(fromFile->FileName)+1)))
740 {
741 PFREE(bFile);
742 return &bNull;
743 }
744 strcpy(bFile->FileName,fromFile->FileName);
745
746 if(fromFile->is_mmf)
747 {
748 bFile->b.mmb = fromFile->b.mmb;
749 bFile->FilePos = fromFile->FilePos;
750 bFile->primary_mmf = False;
751 }
752 else
753 {
754 bFile->b.vfb.handle = __OsDupHandle(fromFile->b.vfb.handle);
755 bFile->b.vfb.updated = fromFile->b.vfb.updated;
756 }
757 bFile->is_mmf = fromFile->is_mmf;
758 if(bFile->b.vfb.handle == NULL_HANDLE)
759 {
760 PFREE(bFile->FileName);
761 PFREE(ret);
762 return &bNull;
763 }
764 bFile->FLength = fromFile->FLength;
765 len = buff_Size;
766 if(len && !bFile->is_mmf)
767 {
768 if((bFile->b.vfb.MBuffer = PMalloc(len)) != NULL)
769 {
770 if(IS_CACHE_VALID(fromFile))
771 {
772 bFile->b.vfb.MBufLen = min(len,fromFile->b.vfb.MBufLen);
773 bFile->b.vfb.MBufSize = len;
774 bFile->FilePos = min(fromFile->FilePos,fromFile->b.vfb.FBufStart+(len/2));
775 bFile->b.vfb.FBufStart = fromFile->b.vfb.FBufStart;
776 memcpy(bFile->b.vfb.MBuffer,fromFile->b.vfb.MBuffer,bFile->b.vfb.MBufLen);
777 }
778 else
779 {
780 bFile->b.vfb.MBufLen = 0;
781 bFile->b.vfb.MBufSize = 0;
782 bFile->FilePos = 0L;
783 bFile->b.vfb.FBufStart = 0;
784 }
785 }
786 else
787 {
788 PFREE(bFile->FileName);
789 __OsClose(bFile->b.vfb.handle);
790 PFREE(ret);
791 return &bNull;
792 }
793 }
794 else bFile->b.vfb.MBuffer = 0;
795 }
796 else ret = &bNull;
797 return ret;
798 }
799
bioDup(BGLOBAL bHandle)800 BGLOBAL __FASTCALL__ bioDup(BGLOBAL bHandle)
801 {
802 BFILE *fromFile = MK_FPTR(bHandle);
803 return bioDupEx(bHandle,fromFile->b.vfb.MBufSize);
804 }
805
bioEOF(BGLOBAL bHandle)806 tBool __FASTCALL__ bioEOF(BGLOBAL bHandle)
807 {
808 BFILE *obj = MK_FPTR(bHandle);
809 tBool retval;
810 if(IS_CACHE_VALID(obj) || obj->is_mmf) retval = obj->is_eof;
811 else retval = (__filesize_t)__OsTell(obj->b.vfb.handle) >= obj->FLength;
812 return retval;
813 }
814