'From Squeak3.3alpha of 30 January 2002 [latest update: #4827] on 19 April 2002 at 9:09:10 am'! "Change Set: ZipFixes-nk Date: 27 March 2002 Author: Ned Konz Miscellaneous fixes and enhancements for Zip support and the ArchiveViewer: * Added support for prepended data (before the first member). This could be used (for instance) to make self-extracting archives. * Removed ArchiveViewer from Useful category in Objects tool (it is already in Tools) * Removed explicit font name from button creation in ArchiveViewer (should work better in systems without Comic 9) * Fixed bug in rewindData that would prevent writing out a zip that was recently read in. * Fixed bug where directories couldn't be renamed in ArchiveViewer. * Added window menu items to inspect the archive and to write it with a prepended file. "! !Archive commentStamp: 'nk 4/19/2002 08:31' prior: 0! This is the abstract superclass for file archives. Archives can be read from or written to files, and contain members that represent files and directories.! !ArchiveMember commentStamp: 'nk 4/19/2002 08:32' prior: 0! This is the abstract superclass for archive members, which are files or directories stored in archives.! !ArchiveViewer commentStamp: 'nk 4/19/2002 08:30' prior: 0! This is a viewer window that allows editing and viewing of Zip archives.! !TarArchive commentStamp: 'nk 4/19/2002 08:32' prior: 0! This is a kind of archive that uses the TAR format (popular in Unix). It is here as a placeholder.! ZipFileMember subclass: #ZipDirectoryMember instanceVariableNames: '' classVariableNames: '' module: #(Squeak Technology Archives)! !ArchiveViewer methodsFor: 'archive operations' stamp: 'nk 4/19/2002 09:08'! saveArchive | result name | self canSaveArchive ifFalse: [ ^self ]. result _ StandardFileMenu newFile. result ifNil: [ ^self ]. name _ result directory fullNameFor: result name. (archive canWriteToFileNamed: name) ifFalse: [ self inform: name, ' is used by one or more members in your archive, and cannot be overwritten. Try writing to another file name'. ^self ]. [ archive writeToFileNamed: name ] on: Error do: [ :ex | self inform: ex description. ]. self setLabel: name asString. self changed: #memberList "in case CRC's and compressed sizes got set"! ! !ArchiveViewer methodsFor: 'archive operations' stamp: 'nk 3/27/2002 12:57'! writePrependingFile | result name prependedName | self canSaveArchive ifFalse: [ ^self ]. result _ (StandardFileMenu newFileMenu: FileDirectory default) startUpWithCaption: 'Destination Zip File Name:'. result ifNil: [ ^self ]. name _ result directory fullNameFor: result name. (archive canWriteToFileNamed: name) ifFalse: [ self inform: name, ' is used by one or more members in your archive, and cannot be overwritten. Try writing to another file name'. ^self ]. result _ (StandardFileMenu oldFileMenu: FileDirectory default) startUpWithCaption: 'Prepended File:'. result ifNil: [ ^self ]. prependedName _ result directory fullNameFor: result name. [ archive writeToFileNamed: name prependingFileNamed: prependedName ] on: Error do: [ :ex | self inform: ex description. ]. self changed: #memberList "in case CRC's and compressed sizes got set"! ! !ArchiveViewer methodsFor: 'initialization' stamp: 'nk 3/27/2002 12:06'! createButtonBar | bar button narrowFont | narrowFont _ StrikeFont allSubInstances detectMin: [ :ea | ea widthOfString: 'Contents' from: 1 to: 8 ]. bar _ AlignmentMorph newRow. bar color: self backgroundColor; rubberBandCells: false; vResizing: #shrinkWrap; cellInset: 6@0. #( #( 'New\Archive' canCreateNewArchive createNewArchive 'Create a new, empty archive and discard this one' ) #( 'Load\Archive' canOpenNewArchive openNewArchive 'Open another archive and discard this one' ) #( 'Save\Archive As' canSaveArchive saveArchive 'Save this archive under a new name' ) #( 'Extract\All' canExtractAll extractAll 'Extract all this archive''s members into a directory' ) #( 'Add\File' canAddMember addMember 'Add a file to this archive' ) #( 'Add from\Clipboard' canAddMember addMemberFromClipboard 'Add the contents of the clipboard as a new file' ) #( 'Add\Directory' canAddMember addDirectory 'Add the entire contents of a directory, with all of its subdirectories' ) #( 'Extract\Member As' canExtractMember extractMember 'Extract the selected member to a file' ) #( 'Delete\Member' canDeleteMember deleteMember 'Remove the selected member from this archive' ) #( 'Rename\Member' canRenameMember renameMember 'Rename the selected member' ) #( 'View All\Contents' canViewAllContents changeViewAllContents 'Toggle the view of all the selected member''s contents' ) ) do: [ :arr | | buttonLabel | buttonLabel _ (TextMorph new) string: arr first withCRs fontName: narrowFont name size: narrowFont pointSize wrap: false; hResizing: #shrinkWrap; lock; yourself. (button _ PluggableButtonMorph on: self getState: arr second action: arr third) vResizing: #shrinkWrap; hResizing: #spaceFill; onColor: self buttonOnColor offColor: self buttonOffColor; label: buttonLabel; setBalloonText: arr fourth; yourself. bar addMorphBack: button. buttonLabel composeToBounds. ]. ^bar.! ! !ArchiveViewer methodsFor: 'menu' stamp: 'nk 3/27/2002 12:48'! buildWindowMenu | menu | menu _ super buildWindowMenu. menu addLine. menu add: 'inspect archive' target: archive action: #inspect. menu add: 'write prepending file...' target: self action: #writePrependingFile. ^menu.! ! !ArchiveViewer class methodsFor: 'parts bin' stamp: 'nk 3/27/2002 11:41'! descriptionForPartsBin ^ self partName: 'Zip Tool' categories: #(Tools) documentation: 'A viewer and editor for Zip archive files' ! ! !ZipArchive methodsFor: 'archive operations' stamp: 'nk 3/27/2002 10:42'! writeTo: stream prepending: aString stream binary. stream nextPutAll: aString. members do: [ :member | member writeTo: stream. member endRead. ]. writeCentralDirectoryOffset _ stream position. self writeCentralDirectoryTo: stream. ! ! !ZipArchive methodsFor: 'archive operations' stamp: 'nk 3/27/2002 12:41'! writeTo: stream prependingFileNamed: aFileName | prepended buffer | stream binary. prepended _ StandardFileStream readOnlyFileNamed: aFileName. prepended binary. buffer _ ByteArray new: (prepended size min: 32768). [ prepended atEnd ] whileFalse: [ | bytesRead | bytesRead _ prepended readInto: buffer startingAt: 1 count: buffer size. stream next: bytesRead putAll: buffer startingAt: 1 ]. members do: [ :member | member writeTo: stream. member endRead. ]. writeCentralDirectoryOffset _ stream position. self writeCentralDirectoryTo: stream. ! ! !ZipArchive methodsFor: 'archive operations' stamp: 'nk 3/27/2002 12:45'! writeToFileNamed: aFileName prepending: aString | stream | "Catch attempts to overwrite existing zip file" (self canWriteToFileNamed: aFileName) ifFalse: [ ^self error: (aFileName, ' is needed by one or more members in this archive') ]. stream _ StandardFileStream forceNewFileNamed: aFileName. self writeTo: stream prepending: aString. stream close.! ! !ZipArchive methodsFor: 'archive operations' stamp: 'nk 3/27/2002 12:58'! writeToFileNamed: aFileName prependingFileNamed: anotherFileName | stream | "Catch attempts to overwrite existing zip file" (self canWriteToFileNamed: aFileName) ifFalse: [ ^self error: (aFileName, ' is needed by one or more members in this archive') ]. stream _ StandardFileStream forceNewFileNamed: aFileName. self writeTo: stream prependingFileNamed: anotherFileName. stream close.! ! !ZipArchive methodsFor: 'accessing' stamp: 'nk 3/27/2002 11:23'! prependedDataSize "Answer the size of whatever data exists before my first member. Assumes that I was read from a file or stream (i.e. the first member is a ZipFileMember)" ^members isEmpty ifFalse: [ members first localHeaderRelativeOffset ] ifTrue: [ centralDirectoryOffsetWRTStartingDiskNumber ]! ! !ZipArchiveMember methodsFor: 'private-writing' stamp: 'nk 3/27/2002 11:09'! rewindData readDataRemaining _ (self compressionMethod == CompressionStored) ifTrue: [ uncompressedSize ] ifFalse: [ compressedSize ] ! ! !ZipFileMember methodsFor: 'private-writing' stamp: 'nk 3/27/2002 11:20'! localHeaderRelativeOffset ^localHeaderRelativeOffset! ! !ZipDirectoryMember methodsFor: 'testing' stamp: 'nk 3/27/2002 11:29'! usesFileNamed: aName ^false! ! !ZipDirectoryMember methodsFor: 'private' stamp: 'nk 3/27/2002 11:30'! rewindData! ! !ZipDirectoryMember methodsFor: 'accessing' stamp: 'nk 3/27/2002 11:37'! fileName: aString | dir entry parent | super fileName: aString. fileName last = $/ ifFalse: [ fileName _ fileName, '/' ]. parent _ FileDirectory default. (parent directoryExists: fileName) ifTrue: [ dir _ FileDirectory on: (parent fullNameFor: fileName). entry _ dir directoryEntry. self setLastModFileDateTimeFrom: entry modificationTime ] ! !