Debian lenny version packages
[pkg-perl] / deb-src / libarchive-zip-perl / libarchive-zip-perl-1.18 / docs / ideas.txt
1 Newsgroups: comp.lang.perl.modules
2 Subject: Best form for allowing module extension?
3 Reply-To: 
4 Followup-To: 
5 Keywords: 
6 Summary: 
7
8 I am writing a module (Archive::Zip) that implements the basic read and
9 write functionality for Zip archive files. These files have provisions
10 for extensions for specific platforms: each member has an 'extra field'
11 that can contain OS-specific (or, indeed, any member-specific) data. The
12 overall format of this data is specified (<Header ID>, <count>, <data>),
13 but the actual contents depends on the Header ID.
14
15 Because I'm only working in a couple of operating environments, and
16 because I'm not trying to write a full "unzip" or "PKZIP" replacement, I
17 don't really want to try to interpret all of these formats.
18
19 From the PKWARE Appnote.txt file:
20
21          The current Header ID mappings defined by PKWARE are:
22
23           0x0007        AV Info
24           0x0009        OS/2
25           0x000a        NTFS 
26           0x000c        VAX/VMS
27           0x000d        Unix
28           0x000f        Patch Descriptor
29
30           Several third party mappings commonly used are:
31
32           0x4b46        FWKCS MD5 (see below)
33           0x07c8        Macintosh
34           0x4341        Acorn/SparkFS 
35           0x4453        Windows NT security descriptor (binary ACL)
36           0x4704        VM/CMS
37           0x470f        MVS
38           0x4c41        OS/2 access control list (text ACL)
39           0x4d49        Info-ZIP VMS (VAX or Alpha)
40           0x5455        extended timestamp
41           0x5855        Info-ZIP Unix (original, also OS/2, NT, etc)
42           0x6542        BeOS/BeBox
43           0x756e        ASi Unix
44           0x7855        Info-ZIP Unix (new)
45           0xfd4a        SMS/QDOS
46
47 I want to make it easy for other people to provide this support without
48 changing my code.
49
50 Note that not all of these extensions have anything to do with file
51 permissions, although it may be helpful to provide one or more hooks for
52 extracting files:
53
54         * supply OS-specific filename
55         * open file for write (set permissions)
56         * after closing file (to set ownership, timestamps, etc.)
57
58 I can provide generic support for these extra fields, so that each
59 member can have 0 or more extra fields, each with a type tag and
60 uninterpreted data.
61
62 I have seen File::Spec and File::Spec::Unix, etc., and don't think that
63 this scheme is appropriate, since you could have a zip file that was
64 produced on one operating system being extracted by another.
65
66 Also, it is possible to have multiple types of extra fields in a single
67 zip file.
68
69 What I have thought about is this: a user who wants to interpret the
70 extended information in the zip members can include the appropriate
71 extension modules:
72
73 # ==================== in user's code ==================== 
74 use Archive::Zip;       # basic functionality
75 use Archive::Zip::Unix; # to interpret Unix file permissions, etc.
76 use Archive::Zip::MD5;  # to interpret MD5 extended info
77
78 my $zip = Archive::Zip->new();
79 $zip->read('ZIPFILE.ZIP');
80 foreach my $member ($zip->members())
81 {
82         foreach my $extraField ($member->extraFields())
83         {
84                 print $extraField->info() . "\n";
85         }
86
87         $member->extract();
88 }
89 # ==================== end user's code ====================
90
91 I can make an extensible class for writers of OS-specific modules to
92 inherit from:
93
94 # ==================== in my code ==================== 
95 package Archive::Zip::ExtraField;
96 my %Handlers;
97
98 # Each subclass must call this with their class name and tag ID.
99 sub registerType
100 {
101         my ($class, $tag) = @_;
102         $Handlers{ $tag } = $class;
103 }
104
105 # Overrideable methods
106 sub info 
107 {
108         my $self = shift;
109         ref($self) . " " . $self->{tag} . " " . $self->{dataLength};
110 }
111
112 # Provide OS-specific name if any or undef
113 sub preferredFileName { undef }
114
115 # Returns numeric arg for open() call or undef
116 sub openPermissions { undef }
117
118 # Hook for doing things after file is extracted
119 # Called as: $extraField->afterClosingExtractedFile($fileName)
120 sub afterClosingExtractedFile { }
121
122 package Archive::Zip::Member;
123
124 # return array of extra fields
125 sub extraFields() { ... }
126
127 sub extract
128 {
129         my $self = shift;
130         my ($preferredFileName) = 
131                 grep { $_ }
132                 (map { $_->preferredFileName() } $self->extraFields());
133         my $fileName = $preferredFileName || $self->fileName();
134         # ... similar things for open permissions ...
135         my $fh = FileHandle->new($fileName, $openPermissions);
136         # ... extract data to fh ...
137         $fh->close();
138         map { $_->afterClosingExtractedFile($fileName) }
139                 $self->extraFields();
140 }
141 # ==================== end my code ====================
142
143
144 Does this seem like a good way to go? Any other suggestions?
145
146 -- 
147 Ned Konz
148 currently: Stanwood, WA
149 email:     ned@bike-nomad.com
150 homepage:  http://www.bike-nomad.com