--- a/ZipArchive.st Wed Dec 05 15:38:32 2012 +0100
+++ b/ZipArchive.st Sat Dec 08 21:05:28 2012 +0100
@@ -3156,14 +3156,11 @@
entries
"return a collection of fileName entries"
- |names|
-
- names := OrderedCollection new.
-
- self zipMembersDo:[:zipd |
- names add:(zipd fileName)
- ].
- ^ names
+ ^ zipMembersByName keys
+!
+
+file
+ ^ file
!
fileSize
@@ -3176,20 +3173,13 @@
members
"return a collection of members"
- |members|
-
- members := OrderedCollection new.
-
- self zipMembersDo:[:zipd |
- members add:zipd
- ].
- ^ members
+ ^ zipMembersByName values.
!
membersMatching:aFileMatchPattern
"return a collection of members which match aFileMatchPattern"
- ^ self members select:[:m | aFileMatchPattern match:m fileName]
+ ^ self zipMembersByName select:[:m | aFileMatchPattern match:m fileName]
!
name
@@ -3198,6 +3188,12 @@
^ archiveName
!
+numberOfEntries
+ "return the number of entries in the archive"
+
+ ^ zipMembersByName size
+!
+
pathName
"FileStream compatibility: answer the name of the underlying file - a String"
@@ -3211,6 +3207,10 @@
size
^self fileSize
+!
+
+zipMembersByName
+ ^ zipMembersByName
! !
!ZipArchive methodsFor:'error raising'!
@@ -3259,31 +3259,30 @@
archiveName := filename name.
mode := readOrWriteMode.
+ self openFile.
mode ~~ #write ifTrue:[
|mustCloseFile|
- mustCloseFile := true.
-
- self openFile.
[
+ mustCloseFile := true.
self readDirectory.
mustCloseFile := false.
mode == #append ifTrue:[
- members := self entries collect:[:eachEntryName | self findMember:eachEntryName] thenSelect:[:eachEntry | eachEntry notNil].
+ members := self zipMembersByName values.
members isEmptyOrNil ifTrue:[^ self].
- maxStartPosition := (members collect:[:eachMember | eachMember fileStart]) max.
- lastMember := members detect:[:eachMember | eachMember fileStart = maxStartPosition].
-
- file position0Based:(startOfArchive + lastMember fileStart + lastMember compressedSize).
+ maxStartPosition := members maxApplying:[:eachMember | self dataStartOf:eachMember].
+ lastMember := members detect:[:eachMember | eachMember dataStart = maxStartPosition].
+
+ file position0Based:(startOfArchive + lastMember dataStart + lastMember compressedSize).
mode := #write.
].
] ensure:[
mustCloseFile ifTrue:[self closeFile].
].
- ] ifFalse:[
- self openFile.
+ ] ifFalse:[
+ zipMembersByName := Dictionary new.
].
"Modified: / 31-08-2010 / 12:39:25 / sr"
@@ -3294,6 +3293,7 @@
"initialize the archive to read from aPositionableStream.
Obsolete - backward compatibility."
+ self obsoleteMethodWarning.
^ self readingFrom:aPositionableStream
!
@@ -3345,6 +3345,7 @@
] ifFalse:[
archiveName := 'internal stream'.
].
+ zipMembersByName := Dictionary new.
! !
!ZipArchive methodsFor:'private'!
@@ -3378,6 +3379,57 @@
]
!
+dataStartOf:zipEntry
+ "fetch the absolute start address of the data of a given zipEntry.
+ Note: extra field and extra field length may be different from that in
+ the central directory entry. Sow e have to fetch the local header."
+
+ |dataStart fileHeaderStart fileNameLength extraFieldLength|
+
+ dataStart := zipEntry dataStart.
+ dataStart notNil ifTrue:[
+ ^ dataStart.
+ ].
+
+ fileHeaderStart := zipEntry relativeLocalHeaderOffset + startOfArchive.
+ (fileHeaderStart + 30) > endOfArchive ifTrue: [
+ ^ ZipFileFormatErrorSignal raiseRequestErrorString:' - zipEntry end is out of the archive bounds'.
+ ].
+
+ "Now read the fileHeader:
+ 0 local file header signature 4 bytes (0x04034b50)
+ 4 version needed to extract 2 bytes
+ 6 general purpose bit flag 2 bytes
+ 8 compression method 2 bytes
+ 10 last mod file time 2 bytes
+ 12 last mod file date 2 bytes
+ 14 crc-32 4 bytes
+ 18 compressed size 4 bytes
+ 22 uncompressed size 4 bytes
+ 26 file name length (x) 2 bytes
+ 28 extra field length (y) 2 bytes
+ fixd size total len: 30
+ 30 file name (variable size)
+ 30+x extra field (variable size)
+ 30+x+y data
+ Note: extra field and extra field length may be different from that in
+ the central directory entry!!
+ "
+
+ file position0Based:fileHeaderStart+26.
+ fileNameLength := file nextUnsignedShortMSB:false.
+ extraFieldLength := file nextUnsignedShortMSB:false.
+
+ dataStart := fileHeaderStart + 30 + fileNameLength + extraFieldLength.
+
+ (dataStart + (zipEntry compressedSize)) > endOfArchive ifTrue: [
+ ^ ZipFileFormatErrorSignal raiseRequestErrorString:' - zipEntry end is out of the archive bounds'.
+ ].
+ zipEntry dataStart:dataStart.
+
+ ^ dataStart
+!
+
openFile
|fn|
@@ -3615,18 +3667,6 @@
"Modified: / 19-11-2010 / 16:23:36 / cg"
!
-addMember
- "add a zipMember"
-
- |zmemb |
-
- self addMember:(zmemb := ZipMember new).
- ^ zmemb.
-
- "Created: / 29.3.1998 / 18:22:25 / cg"
- "Modified: / 9.9.1998 / 20:33:32 / cg"
-!
-
addMember:zmemb
"add a zipMember"
@@ -3636,6 +3676,14 @@
lastEntry next:zmemb.
].
lastEntry := zmemb.
+ (zipMembersByName includesKey:zmemb fileName) ifTrue:[
+ "ignore duplicate entries for backward compatibility.
+ Argh: expecco once added wrong duplicates to the end of ets files.
+ The first entry is valid."
+ Transcript showCR:'Duplicate entry in ZIP (ignored): ', zmemb fileName.
+ ] ifFalse:[
+ zipMembersByName at:zmemb fileName put:zmemb.
+ ].
^ zmemb.
"Modified: / 30.3.1998 / 17:13:20 / cg"
@@ -3669,20 +3717,7 @@
findMember:name
"find a zipMember by name"
-"/ zipMembersByName isNil ifTrue:[
-"/ zipMembersByName := Dictionary new.
-"/ self zipMembersDo:[:zipd |
-"/ zipMembersByName at:(zipd fileName) put:zipd.
-"/ ].
-"/ ].
-"/ ^ zipMembersByName at:name ifAbsent:nil.
-
- self zipMembersDo:[:zipd |
- (zipd fileName = name) ifTrue:[^ zipd].
- ].
- ^ nil
-
- "Modified: / 18-11-2010 / 20:23:35 / cg"
+ ^ zipMembersByName at:name ifAbsent:[].
!
findMemberAllowForMissingTrailingSlash: name
@@ -3755,12 +3790,15 @@
centralDirectory readFrom:file.
"/ set file position to start of central directory
- (pos0 - (centralDirectory centralDirectorySize)) < startOfArchive ifTrue: [
+ (pos0 - centralDirectory centralDirectoryStartOffset - centralDirectory centralDirectorySize) < startOfArchive ifTrue: [
^ ZipFileFormatErrorSignal raiseRequestErrorString:' - central directory start is out of the archive bounds'.
].
+ startOfArchive := pos0 - centralDirectory centralDirectoryStartOffset - centralDirectory centralDirectorySize.
file position0Based:(pos0 - (centralDirectory centralDirectorySize)).
+ zipMembersByName := Dictionary new:centralDirectory centralDirectoryTotalNoOfEntries.
+
"/ read central directory entries
1 to:(centralDirectory centralDirectoryTotalNoOfEntries) do:[:i |
|zipd filename_length centralFileHeaderSignature relative_offset_local_header
@@ -3776,8 +3814,7 @@
^ self.
].
- zipd := ZipMember new.
- zipd readCentralDirectoryEntryFrom:file.
+ zipd := ZipMember new readCentralDirectoryEntryFrom:file.
self addMember:zipd.
].
@@ -3870,21 +3907,13 @@
!ZipArchive methodsFor:'queries'!
isValidPath: anArchivePathName
- ^ self members
- contains:[:aMember |
- |fn|
-
- fn := aMember fileName.
- ((fn startsWith:anArchivePathName,'/') or:[(fn = anArchivePathName)])
+ self zipMembersByName
+ keysDo:[:eachMemberName |
+ ((eachMemberName startsWith:anArchivePathName,'/')
+ or:[eachMemberName = anArchivePathName]) ifTrue:[^ true]
].
- "/ cg: wrong - what about (isValidPath:'foo'), if there is a file named 'foobar' ?!!
-"/ self members do: [:aMember|
-"/ (aMember fileName startsWith:anArchivePathName) ifTrue:[
-"/ ^ true
-"/ ].
-"/ ].
-"/ ^ false
+ ^ false.
! !
!ZipArchive methodsFor:'reading'!
@@ -4038,7 +4067,7 @@
!
withPositionAndMemberFor:fileName do:aBlock
- |zmemb |
+ |zmemb dataStart|
(file isNil or:[mode ~~ #read]) ifTrue:[
^ self error: 'ZipArchive not open for reading ...'.
@@ -4046,15 +4075,9 @@
zmemb := self findMember:fileName.
zmemb isNil ifTrue:[^ nil].
- (zmemb fileStart + startOfArchive) > endOfArchive ifTrue: [
- ^ ZipFileFormatErrorSignal raiseRequestErrorString:' - zipEntry start is out of the archive bounds'.
- ].
-
- (zmemb fileStart + startOfArchive + (zmemb compressedSize)) > endOfArchive ifTrue: [
- ^ ZipFileFormatErrorSignal raiseRequestErrorString:' - zipEntry end is out of the archive bounds'.
- ].
-
- aBlock value:zmemb value:(zmemb fileStart + startOfArchive)
+
+ dataStart := self dataStartOf:zmemb.
+ aBlock value:zmemb value:dataStart.
"Created: / 21-11-2010 / 11:51:41 / cg"
! !
@@ -4064,7 +4087,7 @@
readStreamFor:nameOfFileInArchive
"open a stream on archive contents identified by nameOfFileInArchive"
- |zipEntry|
+ |zipEntry dataStart|
(file isNil or:[mode ~~ #read]) ifTrue:[
^ OpenError raiseRequestWith:nameOfFileInArchive errorString:'ZipArchive not open for reading ...'.
@@ -4075,15 +4098,8 @@
^ OpenError raiseRequestWith:nameOfFileInArchive errorString:'ZipArchive member does not exist: '.
].
- (zipEntry fileStart + startOfArchive) > endOfArchive ifTrue: [
- ^ ZipFileFormatErrorSignal raiseRequestErrorString:' - zipEntry start is out of the archive bounds'.
- ].
-
- (zipEntry fileStart + startOfArchive + (zipEntry compressedSize)) > endOfArchive ifTrue: [
- ^ ZipFileFormatErrorSignal raiseRequestErrorString:' - zipEntry end is out of the archive bounds'.
- ].
-
- file position0Based:(zipEntry fileStart + startOfArchive).
+ dataStart := self dataStartOf:zipEntry.
+ file position0Based:dataStart.
^ (ZipReadStream zipFileStream:file zipEntry:zipEntry)
zipArchive:self.
@@ -4131,6 +4147,7 @@
<resource: #obsolete>
+ self obsoleteMethodWarning.
^ self addFile:aDirectoryName withContents:nil compressMethod:COMPRESSION_STORED asDirectory:true.
"Modified: / 19-11-2010 / 15:38:59 / cg"
@@ -4166,8 +4183,6 @@
].
zipEntry := ZipMember new default.
- self addMember:zipEntry.
-
theZipFileName := self validZipFileNameFrom:aFileName.
zipEntry fileName: theZipFileName.
@@ -4232,6 +4247,8 @@
zipEntry uncompressedSize: unCompressedDataSize.
zipEntry rewriteCrcAndSizeTo:file.
+ self addMember:zipEntry.
+
file setToEnd.
"Modified: / 19-11-2010 / 15:39:32 / cg"
@@ -4289,7 +4306,6 @@
theCompressMethod := COMPRESSION_STORED
].
zipEntry := ZipMember new default.
- self addMember:zipEntry.
theZipFileName := self validZipFileNameFrom:aFileName.
zipEntry fileName:theZipFileName.
zipEntry fileNameLength:theZipFileName size.
@@ -4349,6 +4365,7 @@
theCompressedData notNil ifTrue:[
file nextPutBytes:zipEntry compressedSize from:theCompressedData.
].
+ self addMember:zipEntry.
"Created: / 18-11-2010 / 19:31:10 / cg"
"Modified: / 19-11-2010 / 17:47:01 / cg"
@@ -4370,7 +4387,7 @@
|zipEntry curTime curDate theZipFileName theCompressMethod|
- (file isNil or: [mode ~~ #write]) ifTrue: [
+ (file isNil or:[mode ~~ #write]) ifTrue: [
^ self error: 'ZipArchive not open for writing ...'.
].
@@ -4384,8 +4401,6 @@
].
zipEntry := ZipMember new default.
- self addMember:zipEntry.
-
theZipFileName := self validZipFileNameFrom:nameOfFileInArchive.
zipEntry fileName: theZipFileName.
@@ -4406,6 +4421,7 @@
file setToEnd.
zipEntry writeTo:file.
+ self addMember:zipEntry.
^ (ZipWriteStream zipFileStream:file zipEntry:zipEntry)
zipArchive:self.
@@ -4644,13 +4660,8 @@
!
dataStart
- "tell the file offset, where tha data of this zip entry starts"
- dataStart isNil ifTrue: [
- dataStart := relativeLocalHeaderOffset
- + "C_SIZEOFLOCALHEADER" 30
- + fileNameLength
- + extraFieldLength.
- ].
+ "tell the file offset, where the data of this zip entry starts"
+
^ dataStart
"Created: / 29.3.1998 / 18:28:40 / cg"
!
@@ -4846,13 +4857,6 @@
!ZipArchive::ZipMember methodsFor:'queries'!
-fileStart
- ^ self dataStart
- "/ ^ relative_offset_local_header + ZipArchive LREC_SIZE + 4 + name size
-
- "Created: / 29.3.1998 / 19:10:57 / cg"
-!
-
isDirectory
^
((externalFileAttributes ? 0) bitTest:EXTERNALFILEATTRIBUTES_ISDIRECTORY)
@@ -4874,15 +4878,15 @@
lastModFileTime := aStream nextUnsignedShortMSB:false.
lastModFileDate := aStream nextUnsignedShortMSB:false.
crc32 := aStream nextUnsignedLongMSB: false.
- compressedSize := aStream nextLongMSB:false.
- uncompressedSize := aStream nextLongMSB:false.
+ compressedSize := aStream nextUnsignedLongMSB:false.
+ uncompressedSize := aStream nextUnsignedLongMSB:false.
fileNameLength := aStream nextUnsignedShortMSB:false.
extraFieldLength := aStream nextUnsignedShortMSB:false.
fileCommentLength := aStream nextUnsignedShortMSB:false.
diskNumberStart := aStream nextUnsignedShortMSB:false.
internalFileAttributes := aStream nextUnsignedShortMSB:false.
- externalFileAttributes := aStream nextLongMSB:false.
- relativeLocalHeaderOffset := aStream nextLongMSB:false.
+ externalFileAttributes := aStream nextUnsignedLongMSB:false.
+ relativeLocalHeaderOffset := aStream nextUnsignedLongMSB:false.
"/ (aStream position + fileNameLength) > endOfArchive ifTrue: [
"/ ^ ZipArchive zipFileFormatErrorSignal raiseRequestErrorString:' - central directory entry out of archive bounds'.
@@ -4894,7 +4898,7 @@
"/ (aStream position + extraFieldLength) > endOfArchive ifTrue: [
"/ ^ ZipArchive zipFileFormatErrorSignal raiseRequestErrorString:' - central directory entry out of archive bounds'.
"/ ].
- extraField := String new:extraFieldLength.
+ extraField := ByteArray new:extraFieldLength.
aStream nextBytes:extraFieldLength into:extraField.
].
@@ -5152,11 +5156,11 @@
!ZipArchive class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic2/ZipArchive.st,v 1.100 2012-12-05 14:38:32 stefan Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic2/ZipArchive.st,v 1.101 2012-12-08 20:05:28 stefan Exp $'
!
version_CVS
- ^ '$Header: /cvs/stx/stx/libbasic2/ZipArchive.st,v 1.100 2012-12-05 14:38:32 stefan Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic2/ZipArchive.st,v 1.101 2012-12-08 20:05:28 stefan Exp $'
! !
ZipArchive initialize!