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