| Filename | /home/micha/.plenv/versions/5.38.2/lib/perl5/site_perl/5.38.2/Archive/Zip/ZipFileMember.pm |
| Statements | Executed 625 statements in 1.39ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 10 | 1 | 1 | 98µs | 178µs | Archive::Zip::ZipFileMember::_readCentralDirectoryFileHeader |
| 7 | 1 | 1 | 91µs | 1.85ms | Archive::Zip::ZipFileMember::rewindData |
| 7 | 1 | 1 | 72µs | 162µs | Archive::Zip::ZipFileMember::_skipLocalFileHeader |
| 7 | 1 | 1 | 61µs | 193µs | Archive::Zip::ZipFileMember::_seekToLocalHeader |
| 11 | 1 | 1 | 37µs | 247µs | Archive::Zip::ZipFileMember::_newFromZipFile |
| 21 | 2 | 2 | 28µs | 42µs | Archive::Zip::ZipFileMember::isDirectory |
| 7 | 1 | 1 | 22µs | 591µs | Archive::Zip::ZipFileMember::_readRawChunk |
| 1 | 1 | 1 | 10µs | 12µs | Archive::Zip::ZipFileMember::BEGIN@3 |
| 1 | 1 | 1 | 9µs | 178µs | Archive::Zip::ZipFileMember::BEGIN@11 |
| 1 | 1 | 1 | 7µs | 7µs | Archive::Zip::ZipFileMember::BEGIN@6 |
| 7 | 1 | 1 | 4µs | 4µs | Archive::Zip::ZipFileMember::dataOffset |
| 7 | 1 | 1 | 4µs | 4µs | Archive::Zip::ZipFileMember::localHeaderRelativeOffset |
| 1 | 1 | 1 | 3µs | 21µs | Archive::Zip::ZipFileMember::BEGIN@4 |
| 0 | 0 | 0 | 0s | 0s | Archive::Zip::ZipFileMember::_become |
| 0 | 0 | 0 | 0s | 0s | Archive::Zip::ZipFileMember::_readDataDescriptor |
| 0 | 0 | 0 | 0s | 0s | Archive::Zip::ZipFileMember::_readLocalFileHeader |
| 0 | 0 | 0 | 0s | 0s | Archive::Zip::ZipFileMember::diskNumberStart |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package Archive::Zip::ZipFileMember; | ||||
| 2 | |||||
| 3 | 2 | 21µs | 2 | 13µs | # spent 12µs (10+2) within Archive::Zip::ZipFileMember::BEGIN@3 which was called:
# once (10µs+2µs) by Spreadsheet::ParseXLSX::BEGIN@11 at line 3 # spent 12µs making 1 call to Archive::Zip::ZipFileMember::BEGIN@3
# spent 2µs making 1 call to strict::import |
| 4 | 2 | 22µs | 2 | 38µs | # spent 21µs (3+17) within Archive::Zip::ZipFileMember::BEGIN@4 which was called:
# once (3µs+17µs) by Spreadsheet::ParseXLSX::BEGIN@11 at line 4 # spent 21µs making 1 call to Archive::Zip::ZipFileMember::BEGIN@4
# spent 17µs making 1 call to vars::import |
| 5 | |||||
| 6 | # spent 7µs within Archive::Zip::ZipFileMember::BEGIN@6 which was called:
# once (7µs+0s) by Spreadsheet::ParseXLSX::BEGIN@11 at line 9 | ||||
| 7 | 1 | 200ns | $VERSION = '1.68'; | ||
| 8 | 1 | 7µs | @ISA = qw ( Archive::Zip::FileMember ); | ||
| 9 | 1 | 15µs | 1 | 7µs | } # spent 7µs making 1 call to Archive::Zip::ZipFileMember::BEGIN@6 |
| 10 | |||||
| 11 | 1 | 2µs | 1 | 169µs | # spent 178µs (9+169) within Archive::Zip::ZipFileMember::BEGIN@11 which was called:
# once (9µs+169µs) by Spreadsheet::ParseXLSX::BEGIN@11 at line 16 # spent 169µs making 1 call to Exporter::import |
| 12 | :CONSTANTS | ||||
| 13 | :ERROR_CODES | ||||
| 14 | :PKZIP_CONSTANTS | ||||
| 15 | :UTILITY_METHODS | ||||
| 16 | 1 | 968µs | 1 | 178µs | ); # spent 178µs making 1 call to Archive::Zip::ZipFileMember::BEGIN@11 |
| 17 | |||||
| 18 | # Create a new Archive::Zip::ZipFileMember | ||||
| 19 | # given a filename and optional open file handle | ||||
| 20 | # | ||||
| 21 | # spent 247µs (37+210) within Archive::Zip::ZipFileMember::_newFromZipFile which was called 11 times, avg 22µs/call:
# 11 times (37µs+210µs) by Archive::Zip::Member::_newFromZipFile at line 47 of Archive/Zip/Member.pm, avg 22µs/call | ||||
| 22 | 11 | 1µs | my $class = shift; | ||
| 23 | 11 | 1µs | my $fh = shift; | ||
| 24 | 11 | 2µs | my $externalFileName = shift; | ||
| 25 | 11 | 2µs | my $archiveZip64 = @_ ? shift : 0; | ||
| 26 | 11 | 1µs | my $possibleEocdOffset = @_ ? shift : 0; # normally 0 | ||
| 27 | |||||
| 28 | 11 | 10µs | 11 | 210µs | my $self = $class->new( # spent 210µs making 11 calls to Archive::Zip::Member::new, avg 19µs/call |
| 29 | 'eocdCrc32' => 0, | ||||
| 30 | 'diskNumberStart' => 0, | ||||
| 31 | 'localHeaderRelativeOffset' => 0, | ||||
| 32 | 'dataOffset' => 0, # localHeaderRelativeOffset + header length | ||||
| 33 | @_ | ||||
| 34 | ); | ||||
| 35 | 11 | 3µs | $self->{'externalFileName'} = $externalFileName; | ||
| 36 | 11 | 2µs | $self->{'fh'} = $fh; | ||
| 37 | 11 | 2µs | $self->{'archiveZip64'} = $archiveZip64; | ||
| 38 | 11 | 2µs | $self->{'possibleEocdOffset'} = $possibleEocdOffset; | ||
| 39 | 11 | 9µs | return $self; | ||
| 40 | } | ||||
| 41 | |||||
| 42 | # spent 42µs (28+13) within Archive::Zip::ZipFileMember::isDirectory which was called 21 times, avg 2µs/call:
# 11 times (15µs+7µs) by Archive::Zip::Member::unixFileAttributes at line 399 of Archive/Zip/Member.pm, avg 2µs/call
# 10 times (13µs+7µs) by Archive::Zip::Archive::readFromFileHandle at line 797 of Archive/Zip/Archive.pm, avg 2µs/call | ||||
| 43 | 21 | 2µs | my $self = shift; | ||
| 44 | 21 | 28µs | 21 | 13µs | return (substr($self->fileName, -1, 1) eq '/' # spent 13µs making 21 calls to Archive::Zip::Member::fileName, avg 633ns/call |
| 45 | and $self->uncompressedSize == 0); | ||||
| 46 | } | ||||
| 47 | |||||
| 48 | # Seek to the beginning of the local header, just past the signature. | ||||
| 49 | # Verify that the local header signature is in fact correct. | ||||
| 50 | # Update the localHeaderRelativeOffset if necessary by adding the possibleEocdOffset. | ||||
| 51 | # Returns status. | ||||
| 52 | |||||
| 53 | # spent 193µs (61+132) within Archive::Zip::ZipFileMember::_seekToLocalHeader which was called 7 times, avg 28µs/call:
# 7 times (61µs+132µs) by Archive::Zip::ZipFileMember::rewindData at line 450, avg 28µs/call | ||||
| 54 | 7 | 700ns | my $self = shift; | ||
| 55 | 7 | 1µs | my $where = shift; # optional | ||
| 56 | 7 | 500ns | my $previousWhere = shift; # optional | ||
| 57 | |||||
| 58 | 7 | 7µs | 7 | 4µs | $where = $self->localHeaderRelativeOffset() unless defined($where); # spent 4µs making 7 calls to Archive::Zip::ZipFileMember::localHeaderRelativeOffset, avg 500ns/call |
| 59 | |||||
| 60 | # avoid loop on certain corrupt files (from Julian Field) | ||||
| 61 | 7 | 2µs | return _formatError("corrupt zip file") | ||
| 62 | if defined($previousWhere) && $where == $previousWhere; | ||||
| 63 | |||||
| 64 | 7 | 1µs | my $status; | ||
| 65 | my $signature; | ||||
| 66 | |||||
| 67 | 7 | 9µs | 14 | 31µs | $status = $self->fh()->seek($where, IO::Seekable::SEEK_SET); # spent 20µs making 7 calls to IO::Seekable::seek, avg 3µs/call
# spent 11µs making 7 calls to Archive::Zip::FileMember::fh, avg 2µs/call |
| 68 | 7 | 1µs | return _ioError("seeking to local header") unless $status; | ||
| 69 | |||||
| 70 | 7 | 13µs | 21 | 97µs | ($status, $signature) = # spent 84µs making 7 calls to Archive::Zip::_readSignature, avg 12µs/call
# spent 10µs making 7 calls to Archive::Zip::FileMember::fh, avg 1µs/call
# spent 3µs making 7 calls to Archive::Zip::FileMember::externalFileName, avg 429ns/call |
| 71 | _readSignature($self->fh(), $self->externalFileName(), | ||||
| 72 | LOCAL_FILE_HEADER_SIGNATURE, 1); | ||||
| 73 | 7 | 1µs | return $status if $status == AZ_IO_ERROR; | ||
| 74 | |||||
| 75 | # retry with EOCD offset if any was given. | ||||
| 76 | 7 | 1µs | if ($status == AZ_FORMAT_ERROR && $self->{'possibleEocdOffset'}) { | ||
| 77 | $status = $self->_seekToLocalHeader( | ||||
| 78 | $self->localHeaderRelativeOffset() + $self->{'possibleEocdOffset'}, | ||||
| 79 | $where | ||||
| 80 | ); | ||||
| 81 | if ($status == AZ_OK) { | ||||
| 82 | $self->{'localHeaderRelativeOffset'} += | ||||
| 83 | $self->{'possibleEocdOffset'}; | ||||
| 84 | $self->{'possibleEocdOffset'} = 0; | ||||
| 85 | } | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | 7 | 8µs | return $status; | ||
| 89 | } | ||||
| 90 | |||||
| 91 | # Because I'm going to delete the file handle, read the local file | ||||
| 92 | # header if the file handle is seekable. If it is not, I assume that | ||||
| 93 | # I've already read the local header. | ||||
| 94 | # Return ( $status, $self ) | ||||
| 95 | |||||
| 96 | sub _become { | ||||
| 97 | my $self = shift; | ||||
| 98 | my $newClass = shift; | ||||
| 99 | return $self if ref($self) eq $newClass; | ||||
| 100 | |||||
| 101 | my $status = AZ_OK; | ||||
| 102 | |||||
| 103 | if (_isSeekable($self->fh())) { | ||||
| 104 | my $here = $self->fh()->tell(); | ||||
| 105 | $status = $self->_seekToLocalHeader(); | ||||
| 106 | $status = $self->_readLocalFileHeader() if $status == AZ_OK; | ||||
| 107 | $self->fh()->seek($here, IO::Seekable::SEEK_SET); | ||||
| 108 | return $status unless $status == AZ_OK; | ||||
| 109 | } | ||||
| 110 | |||||
| 111 | delete($self->{'eocdCrc32'}); | ||||
| 112 | delete($self->{'diskNumberStart'}); | ||||
| 113 | delete($self->{'localHeaderRelativeOffset'}); | ||||
| 114 | delete($self->{'dataOffset'}); | ||||
| 115 | delete($self->{'archiveZip64'}); | ||||
| 116 | delete($self->{'possibleEocdOffset'}); | ||||
| 117 | |||||
| 118 | return $self->SUPER::_become($newClass); | ||||
| 119 | } | ||||
| 120 | |||||
| 121 | sub diskNumberStart { | ||||
| 122 | shift->{'diskNumberStart'}; | ||||
| 123 | } | ||||
| 124 | |||||
| 125 | # spent 4µs within Archive::Zip::ZipFileMember::localHeaderRelativeOffset which was called 7 times, avg 500ns/call:
# 7 times (4µs+0s) by Archive::Zip::ZipFileMember::_seekToLocalHeader at line 58, avg 500ns/call | ||||
| 126 | 7 | 7µs | shift->{'localHeaderRelativeOffset'}; | ||
| 127 | } | ||||
| 128 | |||||
| 129 | # spent 4µs within Archive::Zip::ZipFileMember::dataOffset which was called 7 times, avg 557ns/call:
# 7 times (4µs+0s) by Archive::Zip::ZipFileMember::rewindData at line 458, avg 557ns/call | ||||
| 130 | 7 | 7µs | shift->{'dataOffset'}; | ||
| 131 | } | ||||
| 132 | |||||
| 133 | # Skip local file header, updating only extra field stuff. | ||||
| 134 | # Assumes that fh is positioned before signature. | ||||
| 135 | # spent 162µs (72+89) within Archive::Zip::ZipFileMember::_skipLocalFileHeader which was called 7 times, avg 23µs/call:
# 7 times (72µs+89µs) by Archive::Zip::ZipFileMember::rewindData at line 454, avg 23µs/call | ||||
| 136 | 7 | 800ns | my $self = shift; | ||
| 137 | 7 | 500ns | my $header; | ||
| 138 | 7 | 7µs | 14 | 22µs | my $bytesRead = $self->fh()->read($header, LOCAL_FILE_HEADER_LENGTH); # spent 13µs making 7 calls to Archive::Zip::FileMember::fh, avg 2µs/call
# spent 9µs making 7 calls to IO::Handle::read, avg 1µs/call |
| 139 | 7 | 1µs | if ($bytesRead != LOCAL_FILE_HEADER_LENGTH) { | ||
| 140 | return _ioError("reading local file header"); | ||||
| 141 | } | ||||
| 142 | 7 | 1µs | my $fileNameLength; | ||
| 143 | my $extraFieldLength; | ||||
| 144 | my $bitFlag; | ||||
| 145 | ( | ||||
| 146 | undef, # $self->{'versionNeededToExtract'}, | ||||
| 147 | 7 | 15µs | 7 | 5µs | $bitFlag, # spent 5µs making 7 calls to CORE::unpack, avg 657ns/call |
| 148 | undef, # $self->{'compressionMethod'}, | ||||
| 149 | undef, # $self->{'lastModFileDateTime'}, | ||||
| 150 | undef, # $crc32, | ||||
| 151 | undef, # $compressedSize, | ||||
| 152 | undef, # $uncompressedSize, | ||||
| 153 | $fileNameLength, | ||||
| 154 | $extraFieldLength | ||||
| 155 | ) = unpack(LOCAL_FILE_HEADER_FORMAT, $header); | ||||
| 156 | |||||
| 157 | 7 | 8µs | 14 | 34µs | if ($fileNameLength) { # spent 23µs making 7 calls to IO::Seekable::seek, avg 3µs/call
# spent 11µs making 7 calls to Archive::Zip::FileMember::fh, avg 2µs/call |
| 158 | $self->fh()->seek($fileNameLength, IO::Seekable::SEEK_CUR) | ||||
| 159 | or return _ioError("skipping local file name"); | ||||
| 160 | } | ||||
| 161 | |||||
| 162 | 7 | 1µs | my $zip64 = 0; | ||
| 163 | 7 | 1µs | if ($extraFieldLength) { | ||
| 164 | $bytesRead = | ||||
| 165 | 2 | 3µs | 4 | 9µs | $self->fh()->read($self->{'localExtraField'}, $extraFieldLength); # spent 6µs making 2 calls to IO::Handle::read, avg 3µs/call
# spent 3µs making 2 calls to Archive::Zip::FileMember::fh, avg 1µs/call |
| 166 | 2 | 1µs | if ($bytesRead != $extraFieldLength) { | ||
| 167 | return _ioError("reading local extra field"); | ||||
| 168 | } | ||||
| 169 | 2 | 700ns | if ($self->{'archiveZip64'}) { | ||
| 170 | my $status; | ||||
| 171 | ($status, $zip64) = | ||||
| 172 | $self->_extractZip64ExtraField($self->{'localExtraField'}, undef, undef); | ||||
| 173 | return $status if $status != AZ_OK; | ||||
| 174 | $self->{'zip64'} ||= $zip64; | ||||
| 175 | } | ||||
| 176 | } | ||||
| 177 | |||||
| 178 | 7 | 8µs | 14 | 20µs | $self->{'dataOffset'} = $self->fh()->tell(); # spent 10µs making 7 calls to Archive::Zip::FileMember::fh, avg 1µs/call
# spent 10µs making 7 calls to IO::Seekable::tell, avg 1µs/call |
| 179 | |||||
| 180 | 7 | 2µs | if ($bitFlag & GPBF_HAS_DATA_DESCRIPTOR_MASK) { | ||
| 181 | |||||
| 182 | # Read the crc32, compressedSize, and uncompressedSize from the | ||||
| 183 | # extended data descriptor, which directly follows the compressed data. | ||||
| 184 | # | ||||
| 185 | # Skip over the compressed file data (assumes that EOCD compressedSize | ||||
| 186 | # was correct) | ||||
| 187 | $self->fh()->seek($self->{'compressedSize'}, IO::Seekable::SEEK_CUR) | ||||
| 188 | or return _ioError("seeking to extended local header"); | ||||
| 189 | |||||
| 190 | # these values should be set correctly from before. | ||||
| 191 | my $oldCrc32 = $self->{'eocdCrc32'}; | ||||
| 192 | my $oldCompressedSize = $self->{'compressedSize'}; | ||||
| 193 | my $oldUncompressedSize = $self->{'uncompressedSize'}; | ||||
| 194 | |||||
| 195 | my $status = $self->_readDataDescriptor($zip64); | ||||
| 196 | return $status unless $status == AZ_OK; | ||||
| 197 | |||||
| 198 | # The buffer with encrypted data is prefixed with a new | ||||
| 199 | # encrypted 12 byte header. The size only changes when | ||||
| 200 | # the buffer is also compressed | ||||
| 201 | $self->isEncrypted && $oldUncompressedSize > $self->{'uncompressedSize'} | ||||
| 202 | and $oldUncompressedSize -= DATA_DESCRIPTOR_LENGTH; | ||||
| 203 | |||||
| 204 | return _formatError( | ||||
| 205 | "CRC or size mismatch while skipping data descriptor") | ||||
| 206 | if ( $oldCrc32 != $self->{'crc32'} | ||||
| 207 | || $oldUncompressedSize != $self->{'uncompressedSize'}); | ||||
| 208 | |||||
| 209 | $self->{'crc32'} = 0 | ||||
| 210 | if $self->compressionMethod() == COMPRESSION_STORED ; | ||||
| 211 | } | ||||
| 212 | |||||
| 213 | 7 | 8µs | return AZ_OK; | ||
| 214 | } | ||||
| 215 | |||||
| 216 | # Read from a local file header into myself. Returns AZ_OK (in | ||||
| 217 | # scalar context) or a pair (AZ_OK, $headerSize) (in list | ||||
| 218 | # context) if successful. | ||||
| 219 | # Assumes that fh is positioned after signature. | ||||
| 220 | # Note that crc32, compressedSize, and uncompressedSize will be 0 if | ||||
| 221 | # GPBF_HAS_DATA_DESCRIPTOR_MASK is set in the bitFlag. | ||||
| 222 | |||||
| 223 | sub _readLocalFileHeader { | ||||
| 224 | my $self = shift; | ||||
| 225 | my $header; | ||||
| 226 | my $bytesRead = $self->fh()->read($header, LOCAL_FILE_HEADER_LENGTH); | ||||
| 227 | if ($bytesRead != LOCAL_FILE_HEADER_LENGTH) { | ||||
| 228 | return _ioError("reading local file header"); | ||||
| 229 | } | ||||
| 230 | my $fileNameLength; | ||||
| 231 | my $crc32; | ||||
| 232 | my $compressedSize; | ||||
| 233 | my $uncompressedSize; | ||||
| 234 | my $extraFieldLength; | ||||
| 235 | ( | ||||
| 236 | $self->{'versionNeededToExtract'}, $self->{'bitFlag'}, | ||||
| 237 | $self->{'compressionMethod'}, $self->{'lastModFileDateTime'}, | ||||
| 238 | $crc32, $compressedSize, | ||||
| 239 | $uncompressedSize, $fileNameLength, | ||||
| 240 | $extraFieldLength | ||||
| 241 | ) = unpack(LOCAL_FILE_HEADER_FORMAT, $header); | ||||
| 242 | |||||
| 243 | if ($fileNameLength) { | ||||
| 244 | my $fileName; | ||||
| 245 | $bytesRead = $self->fh()->read($fileName, $fileNameLength); | ||||
| 246 | if ($bytesRead != $fileNameLength) { | ||||
| 247 | return _ioError("reading local file name"); | ||||
| 248 | } | ||||
| 249 | $self->fileName($fileName); | ||||
| 250 | } | ||||
| 251 | |||||
| 252 | my $zip64 = 0; | ||||
| 253 | if ($extraFieldLength) { | ||||
| 254 | $bytesRead = | ||||
| 255 | $self->fh()->read($self->{'localExtraField'}, $extraFieldLength); | ||||
| 256 | if ($bytesRead != $extraFieldLength) { | ||||
| 257 | return _ioError("reading local extra field"); | ||||
| 258 | } | ||||
| 259 | if ($self->{'archiveZip64'}) { | ||||
| 260 | my $status; | ||||
| 261 | ($status, $zip64) = | ||||
| 262 | $self->_extractZip64ExtraField($self->{'localExtraField'}, | ||||
| 263 | $uncompressedSize, | ||||
| 264 | $compressedSize); | ||||
| 265 | return $status if $status != AZ_OK; | ||||
| 266 | $self->{'zip64'} ||= $zip64; | ||||
| 267 | } | ||||
| 268 | } | ||||
| 269 | |||||
| 270 | $self->{'dataOffset'} = $self->fh()->tell(); | ||||
| 271 | |||||
| 272 | if ($self->hasDataDescriptor()) { | ||||
| 273 | |||||
| 274 | # Read the crc32, compressedSize, and uncompressedSize from the | ||||
| 275 | # extended data descriptor. | ||||
| 276 | # Skip over the compressed file data (assumes that EOCD compressedSize | ||||
| 277 | # was correct) | ||||
| 278 | $self->fh()->seek($self->{'compressedSize'}, IO::Seekable::SEEK_CUR) | ||||
| 279 | or return _ioError("seeking to extended local header"); | ||||
| 280 | |||||
| 281 | my $status = $self->_readDataDescriptor($zip64); | ||||
| 282 | return $status unless $status == AZ_OK; | ||||
| 283 | } else { | ||||
| 284 | return _formatError( | ||||
| 285 | "CRC or size mismatch after reading data descriptor") | ||||
| 286 | if ( $self->{'crc32'} != $crc32 | ||||
| 287 | || $self->{'uncompressedSize'} != $uncompressedSize); | ||||
| 288 | } | ||||
| 289 | |||||
| 290 | return | ||||
| 291 | wantarray | ||||
| 292 | ? (AZ_OK, | ||||
| 293 | SIGNATURE_LENGTH, | ||||
| 294 | LOCAL_FILE_HEADER_LENGTH + | ||||
| 295 | $fileNameLength + | ||||
| 296 | $extraFieldLength) | ||||
| 297 | : AZ_OK; | ||||
| 298 | } | ||||
| 299 | |||||
| 300 | # This will read the data descriptor, which is after the end of compressed file | ||||
| 301 | # data in members that have GPBF_HAS_DATA_DESCRIPTOR_MASK set in their bitFlag. | ||||
| 302 | # The only reliable way to find these is to rely on the EOCD compressedSize. | ||||
| 303 | # Assumes that file is positioned immediately after the compressed data. | ||||
| 304 | # Returns status; sets crc32, compressedSize, and uncompressedSize. | ||||
| 305 | sub _readDataDescriptor { | ||||
| 306 | my $self = shift; | ||||
| 307 | my $zip64 = shift; | ||||
| 308 | my $signatureData; | ||||
| 309 | my $header; | ||||
| 310 | my $crc32; | ||||
| 311 | my $compressedSize; | ||||
| 312 | my $uncompressedSize; | ||||
| 313 | |||||
| 314 | my $bytesRead = $self->fh()->read($signatureData, SIGNATURE_LENGTH); | ||||
| 315 | return _ioError("reading header signature") | ||||
| 316 | if $bytesRead != SIGNATURE_LENGTH; | ||||
| 317 | my $signature = unpack(SIGNATURE_FORMAT, $signatureData); | ||||
| 318 | |||||
| 319 | my $dataDescriptorLength; | ||||
| 320 | my $dataDescriptorFormat; | ||||
| 321 | my $dataDescriptorLengthNoSig; | ||||
| 322 | my $dataDescriptorFormatNoSig; | ||||
| 323 | if (! $zip64) { | ||||
| 324 | $dataDescriptorLength = DATA_DESCRIPTOR_LENGTH; | ||||
| 325 | $dataDescriptorFormat = DATA_DESCRIPTOR_FORMAT; | ||||
| 326 | $dataDescriptorLengthNoSig = DATA_DESCRIPTOR_LENGTH_NO_SIG; | ||||
| 327 | $dataDescriptorFormatNoSig = DATA_DESCRIPTOR_FORMAT_NO_SIG | ||||
| 328 | } | ||||
| 329 | else { | ||||
| 330 | $dataDescriptorLength = DATA_DESCRIPTOR_ZIP64_LENGTH; | ||||
| 331 | $dataDescriptorFormat = DATA_DESCRIPTOR_ZIP64_FORMAT; | ||||
| 332 | $dataDescriptorLengthNoSig = DATA_DESCRIPTOR_ZIP64_LENGTH_NO_SIG; | ||||
| 333 | $dataDescriptorFormatNoSig = DATA_DESCRIPTOR_ZIP64_FORMAT_NO_SIG | ||||
| 334 | } | ||||
| 335 | |||||
| 336 | # unfortunately, the signature appears to be optional. | ||||
| 337 | if ($signature == DATA_DESCRIPTOR_SIGNATURE | ||||
| 338 | && ($signature != $self->{'crc32'})) { | ||||
| 339 | $bytesRead = $self->fh()->read($header, $dataDescriptorLength); | ||||
| 340 | return _ioError("reading data descriptor") | ||||
| 341 | if $bytesRead != $dataDescriptorLength; | ||||
| 342 | |||||
| 343 | ($crc32, $compressedSize, $uncompressedSize) = | ||||
| 344 | unpack($dataDescriptorFormat, $header); | ||||
| 345 | } else { | ||||
| 346 | $bytesRead = $self->fh()->read($header, $dataDescriptorLengthNoSig); | ||||
| 347 | return _ioError("reading data descriptor") | ||||
| 348 | if $bytesRead != $dataDescriptorLengthNoSig; | ||||
| 349 | |||||
| 350 | $crc32 = $signature; | ||||
| 351 | ($compressedSize, $uncompressedSize) = | ||||
| 352 | unpack($dataDescriptorFormatNoSig, $header); | ||||
| 353 | } | ||||
| 354 | |||||
| 355 | $self->{'eocdCrc32'} = $self->{'crc32'} | ||||
| 356 | unless defined($self->{'eocdCrc32'}); | ||||
| 357 | $self->{'crc32'} = $crc32; | ||||
| 358 | $self->{'compressedSize'} = $compressedSize; | ||||
| 359 | $self->{'uncompressedSize'} = $uncompressedSize; | ||||
| 360 | |||||
| 361 | return AZ_OK; | ||||
| 362 | } | ||||
| 363 | |||||
| 364 | # Read a Central Directory header. Return AZ_OK on success. | ||||
| 365 | # Assumes that fh is positioned right after the signature. | ||||
| 366 | |||||
| 367 | # spent 178µs (98+80) within Archive::Zip::ZipFileMember::_readCentralDirectoryFileHeader which was called 10 times, avg 18µs/call:
# 10 times (98µs+80µs) by Archive::Zip::Archive::readFromFileHandle at line 792 of Archive/Zip/Archive.pm, avg 18µs/call | ||||
| 368 | 10 | 400ns | my $self = shift; | ||
| 369 | 10 | 6µs | 10 | 23µs | my $fh = $self->fh(); # spent 23µs making 10 calls to Archive::Zip::FileMember::fh, avg 2µs/call |
| 370 | 10 | 1µs | my $header = ''; | ||
| 371 | 10 | 5µs | 10 | 12µs | my $bytesRead = $fh->read($header, CENTRAL_DIRECTORY_FILE_HEADER_LENGTH); # spent 12µs making 10 calls to IO::Handle::read, avg 1µs/call |
| 372 | 10 | 1µs | if ($bytesRead != CENTRAL_DIRECTORY_FILE_HEADER_LENGTH) { | ||
| 373 | return _ioError("reading central dir header"); | ||||
| 374 | } | ||||
| 375 | 10 | 1µs | my ($fileNameLength, $extraFieldLength, $fileCommentLength); | ||
| 376 | ( | ||||
| 377 | $self->{'versionMadeBy'}, | ||||
| 378 | $self->{'fileAttributeFormat'}, | ||||
| 379 | $self->{'versionNeededToExtract'}, | ||||
| 380 | $self->{'bitFlag'}, | ||||
| 381 | $self->{'compressionMethod'}, | ||||
| 382 | $self->{'lastModFileDateTime'}, | ||||
| 383 | $self->{'crc32'}, | ||||
| 384 | $self->{'compressedSize'}, | ||||
| 385 | $self->{'uncompressedSize'}, | ||||
| 386 | $fileNameLength, | ||||
| 387 | $extraFieldLength, | ||||
| 388 | $fileCommentLength, | ||||
| 389 | $self->{'diskNumberStart'}, | ||||
| 390 | $self->{'internalFileAttributes'}, | ||||
| 391 | $self->{'externalFileAttributes'}, | ||||
| 392 | 10 | 25µs | 10 | 5µs | $self->{'localHeaderRelativeOffset'} # spent 5µs making 10 calls to CORE::unpack, avg 540ns/call |
| 393 | ) = unpack(CENTRAL_DIRECTORY_FILE_HEADER_FORMAT, $header); | ||||
| 394 | |||||
| 395 | 10 | 2µs | $self->{'eocdCrc32'} = $self->{'crc32'}; | ||
| 396 | |||||
| 397 | 10 | 2µs | if ($fileNameLength) { | ||
| 398 | 10 | 5µs | 10 | 11µs | $bytesRead = $fh->read($self->{'fileName'}, $fileNameLength); # spent 11µs making 10 calls to IO::Handle::read, avg 1µs/call |
| 399 | 10 | 1µs | if ($bytesRead != $fileNameLength) { | ||
| 400 | _ioError("reading central dir filename"); | ||||
| 401 | } | ||||
| 402 | } | ||||
| 403 | 10 | 1µs | if ($extraFieldLength) { | ||
| 404 | $bytesRead = $fh->read($self->{'cdExtraField'}, $extraFieldLength); | ||||
| 405 | if ($bytesRead != $extraFieldLength) { | ||||
| 406 | return _ioError("reading central dir extra field"); | ||||
| 407 | } | ||||
| 408 | if ($self->{'archiveZip64'}) { | ||||
| 409 | my ($status, $zip64) = | ||||
| 410 | $self->_extractZip64ExtraField($self->{'cdExtraField'}, | ||||
| 411 | $self->{'uncompressedSize'}, | ||||
| 412 | $self->{'compressedSize'}, | ||||
| 413 | $self->{'localHeaderRelativeOffset'}, | ||||
| 414 | $self->{'diskNumberStart'}); | ||||
| 415 | return $status if $status != AZ_OK; | ||||
| 416 | $self->{'zip64'} ||= $zip64; | ||||
| 417 | } | ||||
| 418 | } | ||||
| 419 | 10 | 900ns | if ($fileCommentLength) { | ||
| 420 | $bytesRead = $fh->read($self->{'fileComment'}, $fileCommentLength); | ||||
| 421 | if ($bytesRead != $fileCommentLength) { | ||||
| 422 | return _ioError("reading central dir file comment"); | ||||
| 423 | } | ||||
| 424 | } | ||||
| 425 | |||||
| 426 | # NK 10/21/04: added to avoid problems with manipulated headers | ||||
| 427 | 10 | 3µs | if ( $self->{'uncompressedSize'} != $self->{'compressedSize'} | ||
| 428 | and $self->{'compressionMethod'} == COMPRESSION_STORED) { | ||||
| 429 | $self->{'uncompressedSize'} = $self->{'compressedSize'}; | ||||
| 430 | } | ||||
| 431 | |||||
| 432 | 10 | 11µs | 20 | 29µs | $self->desiredCompressionMethod($self->compressionMethod()); # spent 24µs making 10 calls to Archive::Zip::Member::desiredCompressionMethod, avg 2µs/call
# spent 5µs making 10 calls to Archive::Zip::Member::compressionMethod, avg 470ns/call |
| 433 | |||||
| 434 | 10 | 9µs | return AZ_OK; | ||
| 435 | } | ||||
| 436 | |||||
| 437 | # spent 1.85ms (91µs+1.76) within Archive::Zip::ZipFileMember::rewindData which was called 7 times, avg 264µs/call:
# 7 times (91µs+1.76ms) by Archive::Zip::Member::contents at line 1290 of Archive/Zip/Member.pm, avg 264µs/call | ||||
| 438 | 7 | 800ns | my $self = shift; | ||
| 439 | |||||
| 440 | 7 | 7µs | 7 | 912µs | my $status = $self->SUPER::rewindData(@_); # spent 912µs making 7 calls to Archive::Zip::Member::rewindData, avg 130µs/call |
| 441 | 7 | 2µs | return $status unless $status == AZ_OK; | ||
| 442 | |||||
| 443 | 7 | 6µs | 7 | 425µs | return AZ_IO_ERROR unless $self->fh(); # spent 425µs making 7 calls to Archive::Zip::FileMember::fh, avg 61µs/call |
| 444 | |||||
| 445 | 7 | 23µs | 14 | 24µs | $self->fh()->clearerr(); # spent 18µs making 7 calls to Archive::Zip::FileMember::fh, avg 2µs/call
# spent 7µs making 7 calls to IO::Handle::clearerr, avg 957ns/call |
| 446 | |||||
| 447 | # Seek to local file header. | ||||
| 448 | # The only reason that I'm doing this this way is that the extraField | ||||
| 449 | # length seems to be different between the CD header and the LF header. | ||||
| 450 | 7 | 6µs | 7 | 193µs | $status = $self->_seekToLocalHeader(); # spent 193µs making 7 calls to Archive::Zip::ZipFileMember::_seekToLocalHeader, avg 28µs/call |
| 451 | 7 | 1µs | return $status unless $status == AZ_OK; | ||
| 452 | |||||
| 453 | # skip local file header | ||||
| 454 | 7 | 7µs | 7 | 162µs | $status = $self->_skipLocalFileHeader(); # spent 162µs making 7 calls to Archive::Zip::ZipFileMember::_skipLocalFileHeader, avg 23µs/call |
| 455 | 7 | 1µs | return $status unless $status == AZ_OK; | ||
| 456 | |||||
| 457 | # Seek to beginning of file data | ||||
| 458 | 7 | 10µs | 21 | 42µs | $self->fh()->seek($self->dataOffset(), IO::Seekable::SEEK_SET) # spent 21µs making 7 calls to Archive::Zip::FileMember::fh, avg 3µs/call
# spent 17µs making 7 calls to IO::Seekable::seek, avg 2µs/call
# spent 4µs making 7 calls to Archive::Zip::ZipFileMember::dataOffset, avg 557ns/call |
| 459 | or return _ioError("seeking to beginning of file data"); | ||||
| 460 | |||||
| 461 | 7 | 8µs | return AZ_OK; | ||
| 462 | } | ||||
| 463 | |||||
| 464 | # Return bytes read. Note that first parameter is a ref to a buffer. | ||||
| 465 | # my $data; | ||||
| 466 | # my ( $bytesRead, $status) = $self->readRawChunk( \$data, $chunkSize ); | ||||
| 467 | # spent 591µs (22+569) within Archive::Zip::ZipFileMember::_readRawChunk which was called 7 times, avg 84µs/call:
# 7 times (22µs+569µs) by Archive::Zip::Member::readChunk at line 1118 of Archive/Zip/Member.pm, avg 84µs/call | ||||
| 468 | 7 | 2µs | my ($self, $dataRef, $chunkSize) = @_; | ||
| 469 | 7 | 1µs | return (0, AZ_OK) unless $chunkSize; | ||
| 470 | 7 | 7µs | 14 | 569µs | my $bytesRead = $self->fh()->read($$dataRef, $chunkSize) # spent 558µs making 7 calls to IO::Handle::read, avg 80µs/call
# spent 11µs making 7 calls to Archive::Zip::FileMember::fh, avg 2µs/call |
| 471 | or return (0, _ioError("reading data")); | ||||
| 472 | 7 | 7µs | return ($bytesRead, AZ_OK); | ||
| 473 | } | ||||
| 474 | |||||
| 475 | 1 | 2µs | 1; |