Contributor: DAVID DANIEL ANDERSON (* SWAG submission | RECOMP v0.1 | As posted on: GDSOFT BBS (219) 875-8133 | | ~~~~~~~~~~~~~~~~~~~ | Author: David Daniel Anderson | Program: Recompress nested ZIP archives | Date: October 18, 1995 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Here is the basis for a program to recompress archives which may or may not contain nested archives. It will recompress all nested archives that it recognizes, up to at least six levels deep. Although this program is fully functional, it has severe limitations which preclude me from releasing it as a ready-to-use program. As written, this should only be for personal use, and to serve as an example of how to construct a release-worthy recompression program. Limitations of this program foundation: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It doesn't recognize anything besides ZIP files. It is hardcoded to use v2 of PKZIP/ PKUNZIP. It doesn't preserve directory structures in the ZIP files. It doesn't preserve the file attributes of the archived files. It doesn't preserve the extension of the main ZIP, it will always be renamed to *.ZIP. It doesn't preserve the authenticity verification, comments, or date of the original archive. It has almost no error detection. If an extraction fails, you are out of luck. It lacks an Exit or ExitOnError procedure. It doesn't verify that "COMSPEC" is set, and valid. In short, while the logic seems solid, it is not robust enough to handle varied or unexpected conditions. *) PROGRAM Recompress_Nested_ZIP_files; {$M 8192,0,0} {$I-} USES DOS; VAR RecursionLevel: BYTE; PROCEDURE CheckIO; BEGIN IF IOResult <> 0 THEN Halt (7); END; FUNCTION getFileName (fn : STRING): STRING; BEGIN IF (Pos ('.', fn) > 0) THEN getFileName := Copy (fn, 1, (Pos ('.', fn) - 1)) ELSE getFileName := fn; END; FUNCTION IsDir (CONST FileName: PATHSTR): BOOLEAN; VAR Attr : WORD; cFile : FILE; BEGIN Assign (cFile, FileName); GetFAttr (cFile, Attr); IF (DosError = 0) AND ((Attr AND Directory) = Directory) THEN IsDir := TRUE ELSE IsDir := FALSE; END; FUNCTION GetFilePath (CONST PSTR: STRING; VAR sDir: DIRSTR): PATHSTR; VAR jPath : PATHSTR; { file path, } jDir : DIRSTR; { directory, } jName : NAMESTR; { name, } jExt : EXTSTR; { extension. } BEGIN jPath := PSTR; IF jPath = '' THEN jPath := '*.*'; IF (NOT (jPath [Length (jPath)] IN [':', '\'])) AND IsDir (jPath) THEN jPath := jPath + '\'; IF (jPath [Length (jPath)] IN [':', '\']) THEN jPath := jPath + '*.*'; FSplit (FExpand (jPath), jDir, jName, jExt); jPath := jDir + jName+ jExt; sDir := jDir; GetFilePath := jPath; END; FUNCTION IsFile (CONST FileName: PATHSTR): BOOLEAN; VAR Attr : WORD; cFile : FILE; BEGIN Assign (cFile, FileName); GetFAttr (cFile, Attr); IF (DosError = 0) AND ((Attr AND Directory) <> Directory) THEN IsFile := TRUE ELSE IsFile := FALSE; END; PROCEDURE EraseFile (CONST FileName : STRING); VAR cFile : FILE; BEGIN IF IsFile (FileName) THEN BEGIN Assign (cFile, FileName); SetFAttr (cFile, 0); Erase (cFile); CheckIO; END; END; PROCEDURE RezipThem (dirname: PATHSTR); VAR fn: NAMESTR; fileinfo: SEARCHREC; Compression : STRING [4]; BEGIN FindFirst (dirname, Directory, fileinfo); WHILE DosError = 0 DO BEGIN fn := getFileName (fileinfo. Name); WriteLn ('Level: ', RecursionLevel, '; compressing: ', fn); erasefile (fn + '.zip'); IF RecursionLevel > 1 THEN compression := '-e0 ' { STORING the nested ZIP files } ELSE compression := '-ex '; { results in smaller ZIP overall } SwapVectors; Exec (GetEnv ('COMSPEC'),' /c pkzip -# '+compression+fn+'.zip -m '+ fileinfo.Name+'\*.*'); SwapVectors; IF IsDir (fileinfo. Name) THEN RmDir (fileinfo. Name); FindNext (fileinfo); END; Dec (RecursionLevel); END; PROCEDURE UnzipThem (zipname: PATHSTR); VAR StartDir: PATHSTR; fn: NAMESTR; fileinfo: SEARCHREC; BEGIN Inc (RecursionLevel); IF RecursionLevel = 1 THEN WriteLn ('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); GetDir (0, StartDir); FindFirst (zipname, Archive, fileinfo); WHILE DosError = 0 DO BEGIN fn := getFileName (fileinfo. Name); WriteLn ('Level: ', RecursionLevel, '; extracting: ', fn); MkDir (fn + '.dir'); ChDir (fn + '.dir'); SwapVectors; Exec (GetEnv ('COMSPEC'), ' /c pkunzip -# ..\' + fileinfo. Name); SwapVectors; UnzipThem ('*.zip'); ChDir (StartDir); FindNext (fileinfo); END; RezipThem ('*.dir'); END; VAR fPath: PATHSTR; fDir: DIRSTR; BEGIN RecursionLevel := 0; fPath := GetFilePath (ParamStr(1), fDir); UnzipThem (fPath); END.