GXS.FileZLIB.pas 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. //
  2. // Graphic Scene Engine, http://glscene.org
  3. //
  4. unit GXS.FileZLIB;
  5. {$I Stage.Defines.inc}
  6. interface
  7. uses
  8. System.Classes,
  9. System.SysUtils,
  10. GXS.ArchiveManager,
  11. GXS.zLibEx;
  12. const
  13. SIGN = 'ZLIB'; //Signature for compressed zlib.
  14. Type
  15. TZLibHeader = record
  16. Signature: array[0..3] of AnsiChar;
  17. DirOffset: integer;
  18. DirLength: integer;
  19. end;
  20. TFileSection = record
  21. FileName: array[0..119] of AnsiChar;
  22. FilePos: integer;
  23. FileLength: integer;
  24. CbrMode: TCompressionLevel;
  25. end;
  26. { TZLibArchive }
  27. TZLibArchive=class(TgxBaseArchive)
  28. private
  29. FHeader: TZLibHeader;
  30. FStream: TFileStream;
  31. function GetContentCount: integer;
  32. procedure MakeContentList;
  33. public
  34. property ContentCount: integer Read GetContentCount;
  35. destructor Destroy; override;
  36. procedure LoadFromFile(const FileName: string); override;
  37. procedure Clear; override;
  38. function ContentExists(ContentName: string): boolean;override;
  39. function GetContent(aStream: TStream; index: integer): TStream; override;
  40. function GetContent(index: integer): TStream; override;
  41. function GetContent(ContentName: string): TStream; override;
  42. function GetContentSize(index: integer): integer; override;
  43. function GetContentSize(ContentName: string): integer; override;
  44. procedure AddFromStream(ContentName, Path: string; FS: TStream);override;
  45. procedure AddFromFile(FileName, Path: string); override;
  46. procedure RemoveContent(index: integer); overload; override;
  47. procedure RemoveContent(ContentName: string); overload;override;
  48. procedure Extract(index: integer; NewName: string); override;
  49. procedure Extract(ContentName, NewName: string); override;
  50. end;
  51. implementation
  52. var
  53. Dir: TFileSection;
  54. { TZLibArchive }
  55. function TZLibArchive.GetContentCount: integer;
  56. begin
  57. Result := FHeader.DirLength div SizeOf(TFileSection);
  58. end;
  59. procedure TZLibArchive.MakeContentList;
  60. var
  61. I: integer;
  62. begin
  63. FStream.Seek(FHeader.DirOffset, soFromBeginning);
  64. FContentList.Clear;
  65. for i := 0 to ContentCount - 1 do
  66. begin
  67. FStream.ReadBuffer(Dir, SizeOf(TFileSection));
  68. FContentList.Add(string(Dir.FileName));
  69. end;
  70. end;
  71. destructor TZLibArchive.Destroy;
  72. begin
  73. inherited Destroy;
  74. end;
  75. procedure TZLibArchive.LoadFromFile(const FileName: string);
  76. begin
  77. FFileName := FileName;
  78. FStream := TFileStream.Create(FileName, fmOpenReadWrite or fmShareDenyWrite);
  79. if FStream.Size = 0 then
  80. begin
  81. FHeader.Signature := SIGN;
  82. FHeader.DirOffset := SizeOf(TZLibHeader);
  83. FHeader.DirLength := 0;
  84. FStream.WriteBuffer(FHeader, SizeOf(TZlibHeader));
  85. FStream.Position := 0;
  86. end;
  87. FStream.ReadBuffer(FHeader, SizeOf(TZlibHeader));
  88. if FHeader.Signature <> SIGN then
  89. begin
  90. FStream.Free;
  91. raise Exception.Create(FileName+' - This is not ZLIB file');
  92. Exit;
  93. end;
  94. if ContentCount <> 0 then
  95. MakeContentList;
  96. end;
  97. procedure TZLibArchive.Clear;
  98. begin
  99. FContentList.Clear;
  100. If FStream <> nil then FStream.Free;
  101. end;
  102. function TZLibArchive.ContentExists(ContentName: string): boolean;
  103. begin
  104. Result := (FContentList.IndexOf(ContentName) > -1);
  105. end;
  106. function TZLibArchive.GetContent(aStream: TStream; index: integer): TStream;
  107. var
  108. tempStream: TMemoryStream;
  109. decompr : TZDecompressionStream;
  110. begin
  111. Result := nil;
  112. If FStream = nil then exit;
  113. Result := aStream;
  114. //Èùåì ôàéë
  115. FStream.Seek(FHeader.DirOffset + SizeOf(TFileSection) * index, soFromBeginning);
  116. FStream.Read(Dir, SizeOf(TFileSection));
  117. FStream.Seek(Dir.FilePos, soFromBeginning);
  118. //êîïèðóåì ôàéë èç îáùåãî ïîòîêà âî âðåìåííûé ïîòîê
  119. tempStream := TMemoryStream.Create;
  120. tempStream.CopyFrom(FStream, Dir.FileLength);
  121. tempStream.Position := 0;
  122. //äåêîìïðåññèì
  123. decompr := TZDecompressionStream.Create(tempStream);
  124. try
  125. //Êîïèðóåì ðåçóëüòàò
  126. Result.CopyFrom(decompr, 0);
  127. finally
  128. decompr.Free;
  129. tempStream.Free;
  130. end;
  131. Result.Position := 0;
  132. end;
  133. function TZLibArchive.GetContent(index: integer): TStream;
  134. begin
  135. Result:=GetContent(TMemoryStream.Create,index);
  136. end;
  137. function TZLibArchive.GetContent(ContentName: string): TStream;
  138. begin
  139. Result := nil;
  140. if ContentExists(ContentName) then
  141. Result := GetContent(FContentList.IndexOf(ContentName));
  142. end;
  143. function TZLibArchive.GetContentSize(index: integer): integer;
  144. begin
  145. Result := -1;
  146. If FStream = nil then exit;
  147. FStream.Seek(FHeader.DirOffset + SizeOf(TFileSection) * index, soFromBeginning);
  148. FStream.Read(Dir, SizeOf(Dir));
  149. Result := Dir.FileLength;
  150. end;
  151. function TZLibArchive.GetContentSize(ContentName: string): integer;
  152. begin
  153. Result := -1;
  154. if ContentExists(ContentName) then
  155. Result := GetContentSize(FContentList.IndexOf(ContentName));
  156. end;
  157. procedure TZLibArchive.AddFromStream(ContentName, Path: string; FS: TStream);
  158. var
  159. Temp, compressed: TMemoryStream;
  160. FCompressor: TZCompressionStream;
  161. begin
  162. //Äîáàâëåíèå ôàéëà
  163. If (FStream = nil) or ContentExists(ContentName) then exit;
  164. FStream.Position := FHeader.DirOffset;
  165. //???
  166. if FHeader.DirLength > 0 then
  167. begin
  168. Temp := TMemoryStream.Create;
  169. Temp.CopyFrom(FStream, FHeader.DirLength);
  170. Temp.Position := 0;
  171. FStream.Position := FHeader.DirOffset;
  172. end
  173. else
  174. Temp := nil;
  175. Dir.FilePos := FHeader.DirOffset;
  176. Dir.CbrMode := compressionLevel;
  177. //Ñîçäàåì ïîòîê äëÿ ðàçàðõèâàöèè â íåãî
  178. compressed := TMemoryStream.Create;
  179. //Ðàçàðõèâèðóåì äàííûå â íåãî
  180. FCompressor := TZCompressionStream.Create(compressed,TZCompressionLevel(compressionLevel));
  181. FCompressor.CopyFrom(FS, FS.Size);
  182. FCompressor.Free;
  183. //Êîïèðóåì ðåçóëüòàò
  184. FStream.CopyFrom(compressed, 0);
  185. //Çàïîìèíàåì ðàçìåð ôàéëà
  186. Dir.FileLength := compressed.Size;
  187. Compressed .Free;
  188. //???
  189. FHeader.DirOffset := FStream.Position;
  190. if FHeader.DirLength > 0 then
  191. begin
  192. FStream.CopyFrom(Temp, 0);
  193. Temp.Free;
  194. end;
  195. //Ñêëàäûâàåì èìÿ ôàéëà ñ êàòàëîãîì
  196. StrPCopy(Dir.FileName, AnsiString(Path + ExtractFileName(ContentName)));
  197. //Çàïèñûâàåì äàííûå î ôàéëå
  198. FStream.WriteBuffer(Dir, SizeOf(TFileSection));
  199. //Çàïèñûâàåì èçìåíåíèÿ â õèäåð
  200. FHeader.DirLength := FHeader.DirLength + SizeOf(TFileSection);
  201. FStream.Position := 0;
  202. FStream.WriteBuffer(FHeader, SizeOf(TZLibHeader));
  203. FContentList.Add(string(Dir.FileName));
  204. end;
  205. procedure TZLibArchive.AddFromFile(FileName, Path: string);
  206. var
  207. FS: TFileStream;
  208. begin
  209. if not SysUtils.FileExists(FileName) then
  210. exit;
  211. FS := TFileStream.Create(FileName, fmOpenRead);
  212. try
  213. AddFromStream(FileName, Path, FS);
  214. finally
  215. FS.Free;
  216. end;
  217. end;
  218. procedure TZLibArchive.RemoveContent(index: integer);
  219. var
  220. Temp: TMemoryStream;
  221. i: integer;
  222. f: TFileSection;
  223. begin
  224. Temp := TMemoryStream.Create;
  225. FStream.Seek(FHeader.DirOffset + SizeOf(TFileSection) * index, soFromBeginning);
  226. FStream.ReadBuffer(Dir, SizeOf(TFileSection));
  227. FStream.Seek(Dir.FilePos + Dir.FileLength, soFromBeginning);
  228. Temp.CopyFrom(FStream, FStream.Size - FStream.Position);
  229. FStream.Position := Dir.FilePos;
  230. FStream.CopyFrom(Temp, 0);
  231. FHeader.DirOffset := FHeader.DirOffset - dir.FileLength;
  232. Temp.Clear;
  233. for i := 0 to ContentCount - 1 do
  234. if i > index then
  235. begin
  236. FStream.Seek(FHeader.DirOffset + SizeOf(TFileSection) * i, soFromBeginning);
  237. FStream.ReadBuffer(f, SizeOf(TFileSection));
  238. FStream.Position := FStream.Position - SizeOf(TFileSection);
  239. f.FilePos := f.FilePos - dir.FileLength;
  240. FStream.WriteBuffer(f, SizeOf(TFileSection));
  241. end;
  242. i := FHeader.DirOffset + SizeOf(TFileSection) * index;
  243. FStream.Position := Cardinal(i + SizeOf(TFileSection));
  244. if FStream.Position < FStream.Size then
  245. begin
  246. Temp.CopyFrom(FStream, FStream.Size - FStream.Position);
  247. FStream.Position := i;
  248. FStream.CopyFrom(Temp, 0);
  249. end;
  250. Temp.Free;
  251. FHeader.DirLength := FHeader.DirLength - SizeOf(TFileSection);
  252. FStream.Position := 0;
  253. FStream.WriteBuffer(FHeader, SizeOf(TZLibHeader));
  254. FStream.Size := FStream.Size - dir.FileLength - SizeOf(TFileSection);
  255. MakeContentList;
  256. end;
  257. procedure TZLibArchive.RemoveContent(ContentName: string);
  258. begin
  259. if ContentExists(ContentName) then
  260. RemoveContent(FContentList.IndexOf(ContentName));
  261. end;
  262. procedure TZLibArchive.Extract(index: integer; NewName: string);
  263. var
  264. vExtractFileStream: TFileStream;
  265. vTmpStream: Tstream;
  266. begin
  267. if NewName = '' then
  268. Exit;
  269. if (index < 0) or (index >= ContentCount) then
  270. exit;
  271. vExtractFileStream := TFileStream.Create(NewName, fmCreate);
  272. vTmpStream := GetContent(index);
  273. vExtractFileStream.CopyFrom(vTmpStream, 0);
  274. vTmpStream.Free;
  275. vExtractFileStream.Free;
  276. end;
  277. procedure TZLibArchive.Extract(ContentName, NewName: string);
  278. begin
  279. if ContentExists(ContentName) then
  280. Extract(FContentList.IndexOf(ContentName), NewName);
  281. end;
  282. initialization
  283. // Ôàéë èñïîëüçóþùèé Àëãîðèòì ñæàòèÿ zlib
  284. RegisterArchiveFormat('zlib', 'using the zlib compression algorithm', TZLibArchive);
  285. end.