/Gedemin/Common/gsMMFStream.pas

http://gedemin.googlecode.com/ · Pascal · 322 lines · 279 code · 42 blank · 1 comment · 36 complexity · dd7997a8f9b7a35b97a4b71a7a0a670e MD5 · raw file

  1. unit gsMMFStream;
  2. interface
  3. uses
  4. Classes, Windows, SysUtils, ContNrs;
  5. type
  6. TgsStream64 = class(TObject)
  7. private
  8. FHandle: THandle;
  9. FFileMapping: THandle;
  10. FPointer: PAnsiChar;
  11. FOwnFile: Boolean;
  12. FStreamStart, FStreamSize: Int64;
  13. FProtection, FAccessMode: DWORD;
  14. FViewStart: Int64;
  15. FViewSize, FOffset: Cardinal;
  16. function GetPosition: Int64;
  17. procedure SetPosition(const Value: Int64);
  18. procedure InitViewSize;
  19. procedure OpenFile;
  20. procedure MapView(ANewGlobalPos: Int64);
  21. public
  22. constructor Create; overload;
  23. constructor Create(AHandle: THandle; AProtection: DWORD;
  24. AStreamStart, AStreamSize: Int64); overload;
  25. destructor Destroy; override;
  26. function Read(var Buffer; Count: Longint): Longint;
  27. function Write(const Buffer; Count: Longint): Longint;
  28. function Seek(Offset: Int64; Origin: Word): Int64;
  29. procedure ReadBuffer(var Buffer; Count: Longint);
  30. procedure WriteBuffer(const Buffer; Count: Longint);
  31. procedure WriteString(const S: String);
  32. function ReadString(const AStrLen: Integer = -1): String;
  33. function CopyFrom(Source: TStream; Count: LongInt): LongInt;
  34. property Position: Int64 read GetPosition write SetPosition;
  35. property Size: Int64 read FStreamSize;
  36. property ViewSize: Cardinal read FViewSize;
  37. end;
  38. EgsMMFStream = class(Exception);
  39. implementation
  40. uses
  41. Consts;
  42. { TgsStream64 }
  43. constructor TgsStream64.Create;
  44. begin
  45. inherited Create;
  46. InitViewSize;
  47. FProtection := PAGE_READWRITE;
  48. FAccessMode := FILE_MAP_WRITE;
  49. FOwnFile := True;
  50. end;
  51. constructor TgsStream64.Create(AHandle: THandle; AProtection: DWORD;
  52. AStreamStart, AStreamSize: Int64);
  53. begin
  54. inherited Create;
  55. InitViewSize;
  56. FHandle := AHandle;
  57. FProtection := AProtection;
  58. if (FProtection and PAGE_READWRITE) <> 0 then
  59. FAccessMode := FILE_MAP_WRITE
  60. else
  61. FAccessMode := FILE_MAP_READ;
  62. FStreamStart := AStreamStart;
  63. FStreamSize := AStreamSize;
  64. MapView(FStreamStart);
  65. end;
  66. destructor TgsStream64.Destroy;
  67. begin
  68. UnMapViewOfFile(FPointer);
  69. CloseHandle(FFileMapping);
  70. if FOwnFile then
  71. CloseHandle(FHandle);
  72. inherited;
  73. end;
  74. function TgsStream64.CopyFrom(Source: TStream; Count: Integer): LongInt;
  75. var
  76. Buff: array[0..4096 - 1] of AnsiChar;
  77. L: LongInt;
  78. begin
  79. if Count = 0 then
  80. Source.Position := 0;
  81. Result := 0;
  82. repeat
  83. L := Source.Read(Buff, SizeOf(Buff));
  84. WriteBuffer(Buff, L);
  85. Result := Result + L;
  86. until L = 0;
  87. end;
  88. function TgsStream64.GetPosition: Int64;
  89. begin
  90. Result := FViewStart + FOffset - FStreamStart;
  91. end;
  92. procedure TgsStream64.InitViewSize;
  93. var
  94. SI: TSystemInfo;
  95. begin
  96. FViewSize := 65536;
  97. GetSystemInfo(SI);
  98. if FViewSize mod SI.dwAllocationGranularity <> 0 then
  99. FViewSize := SI.dwAllocationGranularity;
  100. end;
  101. procedure TgsStream64.MapView(ANewGlobalPos: Int64);
  102. var
  103. L: ULARGE_INTEGER;
  104. ANewViewStart: Int64;
  105. ANewOffset: Cardinal;
  106. begin
  107. ANewViewStart := (ANewGlobalPos div FViewSize) * FViewSize;
  108. ANewOffset := ANewGlobalPos - ANewViewStart;
  109. if (ANewViewStart <> FViewStart) or (FPointer = nil) then
  110. begin
  111. if FPointer <> nil then
  112. begin
  113. if not UnMapViewOfFile(FPointer) then
  114. raise EgsMMFStream.Create('Can not unmap view of file');
  115. end;
  116. if (ANewViewStart > FViewStart) or (FFileMapping = 0) then
  117. begin
  118. if FFileMapping <> 0 then
  119. begin
  120. if not CloseHandle(FFileMapping) then
  121. raise EgsMMFStream.Create('Can not close file mapping');
  122. end;
  123. if FOwnFile then
  124. L.QuadPart := ANewViewStart + FViewSize
  125. else
  126. L.QuadPart := FStreamStart + FStreamSize;
  127. FFileMapping := CreateFileMapping(FHandle,
  128. nil,
  129. FProtection,
  130. L.HighPart,
  131. L.LowPart,
  132. nil);
  133. if FFileMapping = 0 then
  134. raise EgsMMFStream.Create('Can not create a file mapping');
  135. end;
  136. FViewStart := ANewViewStart;
  137. L.QuadPart := FViewStart;
  138. FPointer := MapViewOfFile(FFileMapping,
  139. FAccessMode,
  140. L.HighPart,
  141. L.LowPart,
  142. FViewSize);
  143. if FPointer = nil then
  144. raise EgsMMFStream.CreateFmt('Can not map view of file, error #%d', [GetLastError]);
  145. end;
  146. FOffset := ANewOffset;
  147. end;
  148. procedure TgsStream64.OpenFile;
  149. var
  150. TempPath: array[0..1023] of Char;
  151. TempFileName: array[0..1023] of Char;
  152. begin
  153. if (GetTempPath(SizeOf(TempPath), TempPath) = 0) or
  154. (GetTempFileName(TempPath, 'gd', 0, TempFileName) = 0) then
  155. raise EgsMMFStream.Create('Can not get a name for temp file');
  156. FHandle := CreateFile(TempFileName,
  157. GENERIC_READ or GENERIC_WRITE,
  158. FILE_SHARE_READ,
  159. nil,
  160. CREATE_ALWAYS,
  161. FILE_ATTRIBUTE_TEMPORARY or FILE_FLAG_DELETE_ON_CLOSE,
  162. 0);
  163. if FHandle = INVALID_HANDLE_VALUE then
  164. raise EgsMMFStream.Create('Can not create a file for gsMMFStream');
  165. MapView(0);
  166. end;
  167. function TgsStream64.Read(var Buffer; Count: Integer): Longint;
  168. var
  169. ToCopy: Cardinal;
  170. Trg: Integer;
  171. begin
  172. Trg := 0;
  173. while Count > 0 do
  174. begin
  175. ToCopy := Count;
  176. if ToCopy > FViewSize - FOffset then
  177. ToCopy := FViewSize - FOffset;
  178. if ToCopy > FStreamStart + FStreamSize - FViewStart - FOffset then
  179. begin
  180. ToCopy := FStreamStart + FStreamSize - FViewStart - FOffset;
  181. if ToCopy = 0 then
  182. break;
  183. end;
  184. Move(FPointer[FOffset], Pointer(Longint(@Buffer) + Trg)^, ToCopy);
  185. Dec(Count, ToCopy);
  186. Inc(Trg, ToCopy);
  187. if FOffset + ToCopy = FViewSize then
  188. MapView(FViewStart + FViewSize)
  189. else
  190. Inc(FOffset, ToCopy);
  191. end;
  192. Result := Trg;
  193. end;
  194. procedure TgsStream64.ReadBuffer(var Buffer; Count: Integer);
  195. begin
  196. if (Count <> 0) and (Read(Buffer, Count) <> Count) then
  197. raise EReadError.CreateRes(@SReadError);
  198. end;
  199. function TgsStream64.ReadString(const AStrLen: Integer = -1): String;
  200. var
  201. L: Integer;
  202. begin
  203. if AStrLen = -1 then
  204. ReadBuffer(L, SizeOf(L))
  205. else
  206. L := AStrLen;
  207. if L < 0 then
  208. raise EgsMMFStream.Create('Invalid stream format');
  209. SetLength(Result, L);
  210. if L > 0 then
  211. ReadBuffer(Result[1], L * SizeOf(Char));
  212. end;
  213. function TgsStream64.Seek(Offset: Int64; Origin: Word): Int64;
  214. var
  215. NewGlobalPos: Int64;
  216. begin
  217. case Origin of
  218. soFromBeginning: NewGlobalPos := FStreamStart + Offset;
  219. soFromCurrent: NewGlobalPos := FViewStart + FOffset + Offset;
  220. else
  221. {soFromEnd:} NewGlobalPos := FStreamSize + Offset;
  222. end;
  223. if (NewGlobalPos < FStreamStart) or (NewGlobalPos > FStreamStart + FStreamSize) then
  224. raise EgsMMFStream.Create('Invalid offset');
  225. MapView(NewGlobalPos);
  226. Result := NewGlobalPos - FStreamStart;
  227. end;
  228. procedure TgsStream64.SetPosition(const Value: Int64);
  229. begin
  230. if (Value < 0) or (Value > FStreamSize - FStreamStart) then
  231. raise EgsMMFStream.Create('Invalid position');
  232. MapView(Value + FStreamStart);
  233. end;
  234. function TgsStream64.Write(const Buffer; Count: Integer): Longint;
  235. var
  236. Src, ToCopy: Integer;
  237. begin
  238. if FHandle = 0 then
  239. OpenFile;
  240. Src := 0;
  241. while Count > 0 do
  242. begin
  243. ToCopy := FViewSize - FOffset;
  244. if ToCopy > Count then
  245. ToCopy := Count;
  246. if not FOwnFile then
  247. begin
  248. if (FViewStart + FOffset + ToCopy) >= (FStreamStart + FStreamSize) then
  249. ToCopy := (FStreamStart + FStreamSize) - (FViewStart + FOffset + ToCopy);
  250. if ToCopy <= 0 then
  251. break;
  252. end;
  253. Move((PAnsiChar(@Buffer) + Src)^, (FPointer + FOffset)^, ToCopy);
  254. Inc(Src, ToCopy);
  255. Inc(FOffset, ToCopy);
  256. if (FViewStart + FOffset) > (FStreamStart + FStreamSize) then
  257. FStreamSize := FViewStart + FOffset - FStreamStart;
  258. if FOffset >= FViewSize then
  259. begin
  260. MapView(FViewStart + FViewSize);
  261. end;
  262. Dec(Count, ToCopy);
  263. end;
  264. Result := Src;
  265. end;
  266. procedure TgsStream64.WriteBuffer(const Buffer; Count: Integer);
  267. begin
  268. if (Count <> 0) and (Write(Buffer, Count) <> Count) then
  269. raise EWriteError.CreateRes(@SWriteError);
  270. end;
  271. procedure TgsStream64.WriteString(const S: String);
  272. var
  273. L: Integer;
  274. begin
  275. L := Length(S);
  276. WriteBuffer(L, SizeOf(L));
  277. if L > 0 then
  278. WriteBuffer(S[1], L * SizeOf(Char));
  279. end;
  280. end.