1 {$INCLUDE ../shared/a_modes.inc}
5 // Implementation restrictions:
6 // - File must start with LFH or EOCD signature
7 // - EOCD must be located strictly at the end of file
8 // - Multi-disk ZIP files are not supported
9 // - Expect UTF-8 or CP1251 encoded names
10 // - ZIP64 not supported
11 // - Encryption not supported
12 // - Zero-length file names not supported
13 // - CDR holds most actual data about file, LFH mostly ignored
14 // - Attributes, comments and extra data are ignored and not saved
15 // - Store and Deflate compression supported
17 interface
21 type
46 private
61 function InsertFileInfo(const section, name: AnsiString; pos, csize, usize, comp, crc, mtime, flags: UInt32; comment: AnsiString): PResource;
65 procedure ReadLFH(s: TStream; fname, xcomment: AnsiString; xcsize, xusize, xcomp, xcrc, xtime, xflags: UInt32);
70 procedure WriteLFH(s: TStream; flags, comp, mtime, crc, csize, usize: UInt32; const name: AnsiString);
71 procedure WriteCDR(s: TStream; flags, comp, mtime, crc, csize, usize, eattr, offset: UInt32; const name, com: AnsiString; cdrid: Integer);
74 public
81 function AddResource(Data: Pointer; Len: LongWord; Name, Section: String): Boolean; override; overload;
89 function GetResource(Section, Resource: String; var pData: Pointer; var Len: Integer): Boolean; override;
99 implementation
103 const
108 const
134 const
138 const
148 begin
150 begin
152 begin
154 exit;
162 begin
166 begin
177 begin
191 begin
192 try
201 begin
208 begin
210 Result := Name
211 else
215 function PrepString(const s: AnsiString; caseSensitive, extSensitive: Boolean): AnsiString; inline;
217 begin
220 begin
224 begin
231 function FindResourceIDRAW(p: PSection; name: AnsiString; caseSensitive, extSensitive: Boolean): Integer;
233 begin
235 begin
238 begin
240 begin
242 exit;
251 begin
254 begin
257 begin
260 begin
270 begin
274 else
282 begin
284 begin
287 begin
289 begin
291 exit;
300 begin
304 else
308 function TZIPEditor.InsertSectionRAW(name: AnsiString; mtime: UInt32; comment: AnsiString): PSection;
310 begin
324 begin
333 begin
340 function TZIPEditor.InsertSection(name: AnsiString; mtime: UInt32; comment: AnsiString): PSection;
341 begin
349 function TZIPEditor.InsertFileInfo(const section, name: AnsiString; pos, csize, usize, comp, crc, mtime, flags: UInt32; comment: AnsiString): PResource;
351 begin
374 begin
375 // Hard-links not supported in ZIP
376 // However, they never created by editor
385 begin
390 begin
392 try
394 begin
396 try
400 finally
405 begin
414 p := InsertFileInfo(Section, Name, $ffffffff, s.Size, Len, comp, crc, DateTimeToDosDateTime(Now()), 0, '');
417 except
426 begin
429 try
431 try
433 try
437 finally
440 finally
443 except
445 begin
454 begin
464 begin
471 begin
473 begin
475 begin
477 begin
479 begin
481 begin
491 begin
501 begin
504 begin
507 begin
509 try
511 begin
518 except
527 begin
529 begin
533 end
535 begin
539 end
540 else
541 begin
543 begin
545 begin
547 begin
549 begin
551 begin
553 e_WriteLog('DFZIP: CreateImage: failed to preload resource [' + FSection[i].name + '][' + FSection[i].list[j].name + ']', MSG_WARNING);
555 exit;
567 begin
574 begin
581 begin
588 begin
591 begin
594 end
596 begin
603 function TZIPEditor.GetResource(Section, Resource: String; var pData: Pointer; var Len: Integer): Boolean;
605 begin
614 begin
617 begin
619 ZIP_COMP_STORE:
620 begin
623 try
624 try
627 except
636 ZIP_COMP_DEFLATE:
637 try
639 try
641 try
644 except
648 finally
651 except
653 begin
659 otherwise
663 end
664 else
665 begin
671 begin
676 begin
680 end
681 else
682 begin
684 e_WriteLog('DFZIP: File integrity check failed: expected CRC32 $' + IntToHex(p.chksum, 8) + ', calculated CRC32 $' + IntToHex(crc, 8), MSG_WARNING);
688 end
689 else
690 begin
699 begin
704 begin
707 begin
715 begin
718 begin
721 begin
727 procedure TZIPEditor.ReadLFH(s: TStream; fname, xcomment: AnsiString; xcsize, xusize, xcomp, xcrc, xtime, xflags: UInt32);
735 begin
738 begin
741 begin
754 begin
759 e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Modification Time : ' + DosToStr(mtime), MSG_NOTIFY);
761 e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Compressed size : ' + IntToStr(csize), MSG_NOTIFY);
762 e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Decompressed size : ' + IntToStr(usize), MSG_NOTIFY);
764 e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Extension Length : ' + IntToStr(extlen), MSG_NOTIFY);
765 e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': <DATA OFFSET> : $' + IntToHex(datapos, 8), MSG_NOTIFY);
768 begin
770 begin
773 begin
777 end
778 else
779 begin
780 p := InsertFileInfo(section, name, datapos, xcsize, xusize, xcomp, xcrc, xtime, xflags and ZIP_COMP_MASK, xcomment);
784 end
785 else
787 end
788 else
789 begin
791 raise Exception.Create('Unsupported CDR version ' + IntToStr(va) + ', not in range [10..' + IntToStr(ZIP_MAXVERSION) + ']');
793 end
794 else
795 raise Exception.Create('Invalid LFH signature $' +IntToHex(Ord(sig[0]), 2) + ' $' +IntToHex(Ord(sig[1]), 2) + ' $' +IntToHex(Ord(sig[2]), 2) + ' $' +IntToHex(Ord(sig[3]), 2) + ' (corrupted file?)');
796 end
797 else
811 begin
815 begin
816 // Valid Central Directory Signature
837 begin
838 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Writer Version : ' + IntToStr(vva), MSG_NOTIFY);
839 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Writer System : ' + IntToStr(vvb), MSG_NOTIFY);
840 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Min Version : ' + IntToStr(va), MSG_NOTIFY);
841 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Min System : ' + IntToStr(vb), MSG_NOTIFY);
842 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Flags : $' + IntToHex(flags, 4), MSG_NOTIFY);
843 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Compression : ' + IntToStr(comp), MSG_NOTIFY);
844 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Modification Time : ' + DosToStr(mtime), MSG_NOTIFY);
845 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': CRC-32 : $' + IntToHex(crc, 8), MSG_NOTIFY);
846 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Compressed size : ' + IntToStr(csize), MSG_NOTIFY);
847 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Decompressed size : ' + IntToStr(usize), MSG_NOTIFY);
848 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Name Length : ' + IntToStr(fnlen), MSG_NOTIFY);
849 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Extension Length : ' + IntToStr(extlen), MSG_NOTIFY);
850 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Comment Length : ' + IntToStr(comlen), MSG_NOTIFY);
851 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Disk : ' + IntToStr(disk), MSG_NOTIFY);
852 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Internal Attrib : $' + IntToHex(iattr, 4), MSG_NOTIFY);
853 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': External Attrib : $' + IntToHex(eattr, 8), MSG_NOTIFY);
854 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': LFH Offset : $' + IntToHex(offset, 8), MSG_NOTIFY);
857 if (vva = $10) and (vvb = $0A) and (va = $10) and (vb = $00) and (flags = (1 << 10)) and (mtime = 0) and (iattr = 0) and (eattr = 0) then
858 begin
859 // HACK: Editor and wadcvt for long time sets incorrent flag for UTF-8
864 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': WADCVT BUG : ' + BoolToStr(cvtbug, True), MSG_NOTIFY);
866 begin
868 begin
869 if (csize <> $ffffffff) and (usize <> $ffffffff) and (disk <> $ffff) and (offset <> $ffffffff) then
870 begin
872 begin
874 begin
876 ZIP_COMP_STORE:
878 raise Exception.Create('Compressed size ' + IntToStr(csize) + ' != Descompressed size ' + IntToStr(usize) + 'for STORE method (corrupted file?)');
879 ZIP_COMP_SHRUNK,
880 ZIP_COMP_REDUCE1,
881 ZIP_COMP_REDUCE2,
882 ZIP_COMP_REDUCE3,
883 ZIP_COMP_REDUCE4,
884 ZIP_COMP_IMPLODE,
885 ZIP_COMP_DEFLATE,
886 ZIP_COMP_DEFLATE64,
887 ZIP_COMP_TERSE1,
888 ZIP_COMP_BZIP2,
889 ZIP_COMP_LZMA,
890 ZIP_COMP_CMPSC,
891 ZIP_COMP_TERSE2,
892 ZIP_COMP_LZ77,
893 ZIP_COMP_ZSTD1,
894 ZIP_COMP_ZSTD2,
895 ZIP_COMP_MP3,
896 ZIP_COMP_XZ,
897 ZIP_COMP_JPEG,
898 ZIP_COMP_WAVPACK,
899 ZIP_COMP_PPMD:
901 ZIP_COMP_AE:
903 otherwise
907 // Read Name
909 try
913 finally
916 // Skip ZIP extensions
918 // Read Comment
921 begin
923 try
927 finally
934 begin
939 begin
944 begin
945 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': UTF-8 Comatible : ' + BoolToStr(utf8, True), MSG_NOTIFY);
946 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Name : "' + name + '"', MSG_NOTIFY);
947 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Comment : "' + comment + '"', MSG_NOTIFY);
952 end
953 else
955 end
956 else
958 end
959 else
960 begin
964 end
965 else
966 begin
970 end
971 else
972 begin
974 raise Exception.Create('Unsupported CDR version ' + IntToStr(va) + ', not in range [10..' + IntToStr(ZIP_MAXVERSION) + ']');
976 end
977 else
978 raise Exception.Create('Invalid CDR signature $' + IntToHex(Ord(sig[0]), 2) + ' $' +IntToHex(Ord(sig[1]), 2) + ' $' +IntToHex(Ord(sig[2]), 2) + ' $' +IntToHex(Ord(sig[3]), 2) + ' (corrupted file?)');
985 begin
988 begin
993 begin
1009 begin
1014 begin
1016 begin
1017 // End of Central Directory found
1028 begin
1031 e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Disk ID with CD : ' + IntToStr(ndisk), MSG_NOTIFY);
1032 e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Available CDR''s : ' + IntToStr(nrec), MSG_NOTIFY);
1036 e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Comment Length : ' + IntToStr(comlen), MSG_NOTIFY);
1038 if (idisk <> $ffff) and (ndisk <> $ffff) and (nrec <> $ffff) and (total <> $ffff) and (csize <> $ffffffff) and (cpos <> $ffffffff) then
1039 begin
1041 begin
1043 begin
1045 begin
1047 begin
1050 begin
1052 try
1057 begin
1061 finally
1066 begin
1067 e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': UTF8 Comaptible : ' + BoolToStr(utf8, True), MSG_NOTIFY);
1073 begin
1082 end
1083 else
1085 end
1086 else
1088 end
1089 else
1091 end
1092 else
1094 end
1095 else
1097 end
1098 else
1104 begin
1107 try
1108 try
1110 try
1115 except
1119 except
1121 begin
1123 e_WriteLog('ZIP: Failed to read ZIP from file ' + FileName + ', reason: ' + e.Message, MSG_WARNING);
1127 except
1129 begin
1133 FLastError := DFWAD_ERROR_CANTOPENWAD
1134 else
1142 begin
1145 try
1147 try
1155 except
1159 except
1161 begin
1171 begin
1177 begin
1181 begin
1190 begin
1225 procedure TZIPEditor.WriteLFH(s: TStream; flags, comp, mtime, crc, csize, usize: UInt32; const name: AnsiString);
1227 begin
1234 begin
1237 e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Min System : ' + IntToStr(ZIP_SYSTEM), MSG_NOTIFY);
1240 e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Modification Time : ' + DosToStr(mtime), MSG_NOTIFY);
1242 e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Compressed size : ' + IntToStr(csize), MSG_NOTIFY);
1243 e_WriteLog('LFH @' + IntToHex(mypos, 8) + ': Decompressed size : ' + IntToStr(usize), MSG_NOTIFY);
1262 procedure TZIPEditor.WriteCDR(s: TStream; flags, comp, mtime, crc, csize, usize, eattr, offset: UInt32; const name, com: AnsiString; cdrid: Integer);
1264 begin
1272 begin
1274 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Writer Version : ' + IntToStr(ZIP_MAXVERSION), MSG_NOTIFY);
1275 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Writer System : ' + IntToStr(ZIP_SYSTEM), MSG_NOTIFY);
1276 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Min Version : ' + IntToStr(version), MSG_NOTIFY);
1277 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Min System : ' + IntToStr(ZIP_SYSTEM), MSG_NOTIFY);
1278 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Flags : $' + IntToHex(flags, 4), MSG_NOTIFY);
1279 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Compression : ' + IntToStr(comp), MSG_NOTIFY);
1280 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Modification Time : ' + DosToStr(mtime), MSG_NOTIFY);
1281 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': CRC-32 : $' + IntToHex(crc, 8), MSG_NOTIFY);
1282 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Compressed size : ' + IntToStr(csize), MSG_NOTIFY);
1283 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Decompressed size : ' + IntToStr(usize), MSG_NOTIFY);
1284 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Name Length : ' + IntToStr(fnlen), MSG_NOTIFY);
1285 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Extension Length : ' + IntToStr(0), MSG_NOTIFY);
1286 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Comment Length : ' + IntToStr(fclen), MSG_NOTIFY);
1287 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Disk : ' + IntToStr(0), MSG_NOTIFY);
1288 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Internal Attrib : $' + IntToHex(0, 4), MSG_NOTIFY);
1289 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': External Attrib : $' + IntToHex(eattr, 8), MSG_NOTIFY);
1290 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': LFH Offset : $' + IntToHex(offset, 8), MSG_NOTIFY);
1291 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Name : "' + name + '"', MSG_NOTIFY);
1292 e_WriteLog('CDR#' + IntToStr(cdrid) + ' @' + IntToHex(mypos, 8) + ': Comment : "' + com + '"', MSG_NOTIFY);
1322 begin
1323 // Write LFH headers and data
1327 begin
1329 begin
1331 begin
1333 begin
1338 begin
1341 end
1343 begin
1346 end
1347 else
1348 begin
1352 end
1353 else
1354 begin
1360 // Write CDR headers
1365 begin
1367 begin
1369 begin
1371 begin
1374 WriteCDR(s, p.flags, p.comp, p.mtime, p.chksum, p.csize, p.usize, $00, loffset, afname, p.comment, i);
1378 end
1379 else
1380 begin
1382 WriteCDR(s, 0, ZIP_COMP_STORE, FSection[i].mtime, zcrc, 0, 0, $10, loffset, afname, FSection[i].comment, i);
1391 // Write EOCD header
1395 begin
1399 e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Available CDR''s : ' + IntToStr(count), MSG_NOTIFY);
1402 e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': CD Offset : $' + IntToHex(offset, 8), MSG_NOTIFY);
1403 e_WriteLog('EOCD @' + IntToHex(mypos, 8) + ': Comment Length : ' + IntToStr(comlen), MSG_NOTIFY);
1420 begin
1421 try
1423 try
1425 finally
1428 except
1430 begin
1439 begin
1444 begin
1460 begin
1463 begin
1472 begin
1476 begin