fcache.pas 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. Unit FCache;
  2. interface
  3. { ---------------------- File Cache -------------------------- }
  4. { implements a simple file cache and mimic C getc and ungetc
  5. functions. }
  6. const
  7. BufMemSize = 4096;
  8. EOF = ^Z;
  9. type
  10. Cache = record
  11. active : boolean;
  12. BildOffset : LongInt;
  13. Buffer : array[0..BufMemSize-1] of byte;
  14. FVarPtr : ^file;
  15. FileOfs : LongInt;
  16. BufPos : integer;
  17. BufSize : integer;
  18. end;
  19. Procedure fc_Init(var fc : Cache;
  20. var f : file; FPos : LongInt);
  21. Procedure fc_Close(var fc : Cache);
  22. Procedure fc_Done(var fc : Cache;
  23. var f : file);
  24. Procedure fc_ReadBlock(var fc : Cache);
  25. Function fc_getc(var fc : Cache) : Byte;
  26. { Read a byte at the current buffer read-index, increment the buffer
  27. read-index }
  28. function fc_ungetc (var fc : Cache; ch : char) : Byte;
  29. { Read a byte at the current buffer read-index, increment the buffer
  30. read-index }
  31. procedure fc_WriteTo(var fc : Cache;
  32. var Buf; Count : Word);
  33. implementation
  34. {$IFDEF USE_DOS}
  35. uses
  36. Dos;
  37. {$ENDIF}
  38. Procedure fc_Init(var fc : Cache;
  39. var f : file; FPos : LongInt);
  40. begin
  41. with fc do
  42. begin
  43. active := false;
  44. FVarPtr := @f;
  45. FileOfs := FPos;
  46. BufSize := 0;
  47. BufPos := 0;
  48. {$IFDEF USE_DOS}
  49. if TFileRec(f).Mode <> fmClosed then
  50. {$ENDIF}
  51. begin
  52. {$PUSH} {$I-}
  53. Seek(f, FPos);
  54. BlockRead(f, Buffer, BufMemSize, BufSize);
  55. {$POP}
  56. if (IOResult = 0) and (BufSize <> 0) then
  57. active := true;
  58. end;
  59. end;
  60. end;
  61. Procedure fc_Done(var fc : Cache;
  62. var f : file);
  63. begin
  64. with fc do
  65. if FVarPtr = @f then
  66. begin
  67. active := false;
  68. FVarPtr := NIL;
  69. FileOfs := 0;
  70. BufSize := 0;
  71. BufPos := 0;
  72. end;
  73. end;
  74. Procedure fc_Close(var fc : Cache);
  75. begin
  76. with fc do
  77. begin
  78. if Assigned(FVarPtr) then
  79. Close(FVarPtr^);
  80. fc_Done(fc, FVarPtr^);
  81. end;
  82. end;
  83. Procedure fc_ReadBlock(var fc : Cache);
  84. Begin
  85. with fc do
  86. if active then
  87. begin
  88. {$push}{$I-}
  89. Seek(FVarPtr^, FileOfs);
  90. BlockRead(FVarPtr^, Buffer, BufMemSize, BufSize);
  91. {$pop}
  92. BufPos := 0;
  93. active := (IOResult = 0) and (BufSize <> 0);
  94. end;
  95. End;
  96. Function fc_getc(var fc : Cache) : Byte;
  97. { Read a byte at the current buffer read-index, increment the buffer
  98. read-index }
  99. begin
  100. with fc do
  101. if active then
  102. begin
  103. fc_GetC := Buffer[BufPos];
  104. Inc(BufPos);
  105. if BufPos = BufSize then
  106. begin
  107. Inc(FileOfs, BufSize);
  108. fc_ReadBlock(fc);
  109. end;
  110. end
  111. else
  112. fc_getc := Byte(EOF);
  113. end;
  114. function fc_ungetc (var fc : Cache; ch : char) : Byte;
  115. { Read a byte at the current buffer read-index, increment the buffer
  116. read-index }
  117. begin
  118. with fc do
  119. begin
  120. fc_UnGetC := Byte(EOF);
  121. if active and (FileOfs > 0) then
  122. begin
  123. if BufPos = 0 then
  124. begin
  125. Dec(FileOfs);
  126. fc_ReadBlock(fc);
  127. end;
  128. if BufPos > 0 then
  129. begin
  130. Dec(BufPos);
  131. fc_UnGetC := Buffer[BufPos];
  132. end;
  133. end;
  134. end;
  135. end;
  136. procedure fc_WriteTo(var fc : Cache;
  137. var Buf; Count : Word);
  138. type
  139. PByte = ^Byte;
  140. var
  141. ChunkSize : Word;
  142. DestPtr : PByte;
  143. Begin
  144. with fc do
  145. if active then
  146. begin
  147. ChunkSize := BufSize - BufPos;
  148. DestPtr := PByte(@Buf);
  149. if Count > ChunkSize then
  150. begin
  151. { the amount we need to read straddles a buffer boundary,
  152. we need two or more chunks. This implementation doesn't try
  153. to read more than two chunks. }
  154. Move(Buffer[BufPos], Buf, ChunkSize);
  155. Inc(DestPtr, ChunkSize);
  156. Dec(count, ChunkSize);
  157. Inc(FileOfs, BufSize);
  158. fc_ReadBlock(fc);
  159. end;
  160. { we are now completely within the buffer boundary,
  161. do a simple mem move }
  162. Move(Buffer[BufPos], DestPtr^, count);
  163. end;
  164. End;
  165. { ---------------------- End File Cache -------------------------- }
  166. end.