65 TZIPFile::TZIPFile() : TArchiveFile()
76 TZIPFile::TZIPFile(
const char *archive,
const char *member, TFile *file)
77 : TArchiveFile(archive, member, file)
88 Int_t TZIPFile::OpenArchive()
90 if (ReadEndHeader(FindEndHeader()) == -1)
92 return ReadDirectory();
98 Long64_t TZIPFile::FindEndHeader()
100 const Int_t kBUFSIZE = 1024;
101 Long64_t size = fFile->GetSize();
102 Long64_t limit = TMath::Min(size, Long64_t(kMAX_VAR_LEN));
103 char buf[kBUFSIZE+4];
108 for (Long64_t offset = 4; offset < limit; ) {
109 offset = TMath::Min(offset + kBUFSIZE, limit);
111 Long64_t pos = size - offset;
112 Int_t n = TMath::Min(kBUFSIZE+4, Int_t(offset));
115 if (fFile->ReadBuffer(buf, n)) {
116 Error(
"FindEndHeader",
"error reading %d bytes at %lld", n, pos);
120 for (Int_t i = n - 4; i > 0; i--)
121 if (buf[i] == 0x50 && buf[i+1] == 0x4b &&
122 buf[i+2] == 0x05 && buf[i+3] == 0x06) {
127 Error(
"FindEndHeader",
"did not find end header in %s", fArchiveName.Data());
139 Int_t TZIPFile::ReadEndHeader(Long64_t pos)
141 char buf[kEND_HEADER_SIZE];
145 if (fFile->ReadBuffer(buf, kZIP_MAGIC_LEN) ||
146 Get(buf, kZIP_MAGIC_LEN) != kEND_HEADER_MAGIC) {
147 Error(
"ReadEndHeader",
"wrong end header magic in %s", fArchiveName.Data());
152 if (fFile->ReadBuffer(buf + kZIP_MAGIC_LEN, kEND_HEADER_SIZE - kZIP_MAGIC_LEN)) {
153 Error(
"ReadEndHeader",
"error reading %d end header bytes from %s",
154 kEND_HEADER_SIZE - kZIP_MAGIC_LEN, fArchiveName.Data());
158 UInt_t disk = Get(buf + kEND_DISK_OFF, kEND_DISK_LEN);
159 UInt_t dirdisk = Get(buf + kEND_DIR_DISK_OFF, kEND_DIR_DISK_LEN);
160 UInt_t dhdrs = Get(buf + kEND_DISK_HDRS_OFF, kEND_DISK_HDRS_LEN);
161 UInt_t thdrs = Get(buf + kEND_TOTAL_HDRS_OFF, kEND_TOTAL_HDRS_LEN);
162 Long64_t dirsz = Get(buf + kEND_DIR_SIZE_OFF, kEND_DIR_SIZE_LEN);
163 Long64_t diroff = Get(buf + kEND_DIR_OFFSET_OFF, kEND_DIR_OFFSET_LEN);
164 Int_t commlen = Get(buf + kEND_COMMENTLEN_OFF, kEND_COMMENTLEN_LEN);
166 if (disk != 0 || dirdisk != 0) {
167 Error(
"ReadHeader",
"only single disk archives are supported in %s",
168 fArchiveName.Data());
171 if (dhdrs != thdrs) {
172 Error(
"ReadEndHeader",
"inconsistency in end header data in %s",
173 fArchiveName.Data());
177 char *comment =
new char[commlen+1];
178 if (fFile->ReadBuffer(comment, commlen)) {
179 Error(
"ReadEndHeader",
"error reading %d end header comment bytes from %s",
180 commlen, fArchiveName.Data());
184 comment[commlen] =
'\0';
187 fDirOffset = fDirPos = diroff;
193 Long64_t recoff = ReadZip64EndLocator(pos - kZIP64_EDL_HEADER_SIZE);
200 if (ReadZip64EndRecord(recoff) < 0)
211 Long64_t TZIPFile::ReadZip64EndLocator(Long64_t pos)
213 char buf[kZIP64_EDL_HEADER_SIZE];
217 if (fFile->ReadBuffer(buf, kZIP_MAGIC_LEN) ||
218 Get(buf, kZIP_MAGIC_LEN) != kZIP64_EDL_HEADER_MAGIC) {
223 if (fFile->ReadBuffer(buf + kZIP_MAGIC_LEN, kZIP64_EDL_HEADER_SIZE - kZIP_MAGIC_LEN)) {
224 Error(
"ReadZip64EndLocator",
"error reading %d Zip64 end locator header bytes from %s",
225 kZIP64_EDL_HEADER_SIZE - kZIP_MAGIC_LEN, fArchiveName.Data());
229 UInt_t dirdisk = Get( buf + kZIP64_EDL_DISK_OFF, kZIP64_EDL_DISK_LEN);
230 Long64_t recoff = Get64(buf + kZIP64_EDL_REC_OFFSET_OFF, kZIP64_EDL_REC_OFFSET_LEN);
231 UInt_t totdisk = Get( buf + kZIP64_EDL_TOTAL_DISK_OFF, kZIP64_EDL_TOTAL_DISK_LEN);
233 if (dirdisk != 0 || totdisk != 1) {
234 Error(
"ReadZip64EndLocator",
"only single disk archives are supported in %s",
235 fArchiveName.Data());
246 Int_t TZIPFile::ReadZip64EndRecord(Long64_t pos)
248 char buf[kZIP64_EDR_HEADER_SIZE];
252 if (fFile->ReadBuffer(buf, kZIP_MAGIC_LEN) ||
253 Get(buf, kZIP_MAGIC_LEN) != kZIP64_EDR_HEADER_MAGIC) {
254 Error(
"ReadZip64EndRecord",
"no Zip64 end of directory record\n");
259 if (fFile->ReadBuffer(buf + kZIP_MAGIC_LEN, kZIP64_EDR_HEADER_SIZE - kZIP_MAGIC_LEN)) {
260 Error(
"ReadZip64EndRecord",
"error reading %d Zip64 end record header bytes from %s",
261 kZIP64_EDR_HEADER_SIZE - kZIP_MAGIC_LEN, fArchiveName.Data());
265 Long64_t dirsz = Get64(buf + kZIP64_EDR_DIR_SIZE_OFF, kZIP64_EDR_DIR_SIZE_LEN);
266 Long64_t diroff = Get64(buf + kZIP64_EDR_DIR_OFFSET_OFF, kZIP64_EDR_DIR_OFFSET_LEN);
268 fDirOffset = fDirPos = diroff;
278 Int_t TZIPFile::ReadDirectory()
280 char buf[kDIR_HEADER_SIZE];
284 fFile->Seek(fDirPos);
285 if (fFile->ReadBuffer(buf, kZIP_MAGIC_LEN) ||
286 (n = Get(buf, kZIP_MAGIC_LEN)) != kDIR_HEADER_MAGIC) {
287 Error(
"ReadDirectory",
"wrong directory header magic in %s",
288 fArchiveName.Data());
293 for (i = 0; n == kDIR_HEADER_MAGIC; i++) {
295 if (fFile->ReadBuffer(buf + kZIP_MAGIC_LEN, kDIR_HEADER_SIZE - kZIP_MAGIC_LEN)) {
296 Error(
"ReadDirectory",
"error reading %d directory bytes from %s",
297 kDIR_HEADER_SIZE - kZIP_MAGIC_LEN, fArchiveName.Data());
301 UInt_t version = Get(buf + kDIR_VREQD_OFF, kDIR_VREQD_LEN);
302 UInt_t flags = Get(buf + kDIR_FLAG_OFF, kDIR_FLAG_LEN);
303 UInt_t method = Get(buf + kDIR_METHOD_OFF, kDIR_METHOD_LEN);
304 UInt_t time = Get(buf + kDIR_DATE_OFF, kDIR_DATE_LEN);
305 UInt_t crc32 = Get(buf + kDIR_CRC32_OFF, kDIR_CRC32_LEN);
306 Long64_t csize = Get(buf + kDIR_CSIZE_OFF, kDIR_CSIZE_LEN);
307 Long64_t usize = Get(buf + kDIR_USIZE_OFF, kDIR_USIZE_LEN);
308 Int_t namelen = Get(buf + kDIR_NAMELEN_OFF, kDIR_NAMELEN_LEN);
309 Int_t extlen = Get(buf + kDIR_EXTRALEN_OFF, kDIR_EXTRALEN_LEN);
310 Int_t commlen = Get(buf + kDIR_COMMENTLEN_OFF, kDIR_COMMENTLEN_LEN);
311 UInt_t disk = Get(buf + kDIR_DISK_START_OFF, kDIR_DISK_START_LEN);
312 UInt_t iattr = Get(buf + kDIR_INT_ATTR_OFF, kDIR_INT_ATTR_LEN);
313 UInt_t xattr = Get(buf + kDIR_EXT_ATTR_OFF, kDIR_EXT_ATTR_LEN);
314 Long64_t offset = Get(buf + kDIR_ENTRY_POS_OFF, kDIR_ENTRY_POS_LEN);
317 if (Get(buf + kDIR_MAGIC_OFF, kZIP_MAGIC_LEN) != kDIR_HEADER_MAGIC ||
318 version > kARCHIVE_VERSION ||
320 (method != kSTORED && method != kDEFLATED) ||
326 Error(
"ReadDirectory",
"inconsistency in directory data in %s",
327 fArchiveName.Data());
331 char *name =
new char[namelen+1];
332 char *extra =
new char[extlen];
333 char *comment =
new char[commlen+1];
334 if (fFile->ReadBuffer(name, namelen) ||
335 fFile->ReadBuffer(extra, extlen) ||
336 fFile->ReadBuffer(comment, commlen)) {
337 Error(
"ReadDirectory",
"error reading additional directory data from %s",
338 fArchiveName.Data());
344 name[namelen] =
'\0';
345 comment[commlen] =
'\0';
348 TZIPMember *m =
new TZIPMember(name);
352 m->fLevel = method == kSTORED ? 0
353 : (flags & 6)/2 == 0 ? 3
354 : (flags & 6)/2 == 1 ? 9
355 : (flags & 6)/2 == 2 ? 2
356 : (flags & 6)/2 == 3 ? 1
361 m->fModTime.Set(time, kTRUE);
362 m->fGlobalLen = extlen;
364 m->fComment = comment;
367 m->fPosition = offset;
373 if (DecodeZip64ExtendedExtraField(m) == -1)
377 Info(
"ReadDirectory",
"%lld %lld %s %s",
378 m->GetDecompressedSize(), m->GetCompressedSize(),
379 m->GetModTime().AsSQLString(), m->GetName());
382 if (fFile->ReadBuffer(buf, kZIP_MAGIC_LEN)) {
383 Error(
"ReadDirectory",
"error reading %d directory bytes from %s",
384 kZIP_MAGIC_LEN, fArchiveName.Data());
387 n = Get(buf, kZIP_MAGIC_LEN);
391 if (n != kEND_HEADER_MAGIC && n != kZIP64_EDR_HEADER_MAGIC) {
392 Error(
"ReadDirectory",
"wrong end header magic in %s", fArchiveName.Data());
404 Int_t TZIPFile::ReadMemberHeader(TZIPMember *member)
408 char buf[kENTRY_HEADER_SIZE];
411 fFile->Seek(member->fPosition);
412 if (fFile->ReadBuffer(buf, kZIP_MAGIC_LEN) ||
413 Get(buf, kZIP_MAGIC_LEN) != kENTRY_HEADER_MAGIC) {
414 Error(
"ReadMemberHeader",
"wrong entry header magic in %s",
415 fArchiveName.Data());
420 if (fFile->ReadBuffer(buf + kZIP_MAGIC_LEN, kENTRY_HEADER_SIZE - kZIP_MAGIC_LEN)) {
421 Error(
"ReadMemberHeader",
"error reading %d member header bytes from %s",
422 kENTRY_HEADER_SIZE - kZIP_MAGIC_LEN, fArchiveName.Data());
425 Int_t namelen = Get(buf + kENTRY_NAMELEN_OFF, kENTRY_NAMELEN_LEN);
426 Int_t extlen = Get(buf + kENTRY_EXTRALEN_OFF, kENTRY_EXTRALEN_LEN);
428 member->fFilePosition = member->fPosition + kENTRY_HEADER_SIZE +
441 Int_t TZIPFile::DecodeZip64ExtendedExtraField(TZIPMember *m, Bool_t global)
448 buf = (
char *) m->fGlobal;
451 buf = (
char *) m->fLocal;
461 UInt_t tag = Get(buf + off + kZIP64_EXTENDED_MAGIC_OFF, kZIP64_EXTENDED_MAGIC_LEN);
462 UInt_t size = Get(buf + off + kZIP64_EXTENDED_SIZE_OFF, kZIP64_EXTENDED_SIZE_LEN);
463 if (tag == kZIP64_EXTENDED_MAGIC) {
464 Long64_t usize = Get64(buf + off + kZIP64_EXTENDED_USIZE_OFF, kZIP64_EXTENDED_USIZE_LEN);
465 Long64_t csize = Get64(buf + off + kZIP64_EXTENTED_CSIZE_OFF, kZIP64_EXTENDED_CSIZE_LEN);
469 Long64_t offset = Get64(buf + off + kZIP64_EXTENDED_HDR_OFFSET_OFF, kZIP64_EXTENDED_HDR_OFFSET_LEN);
470 m->fPosition = offset;
475 len -= (Int_t)size + kZIP64_EXTENDED_MAGIC_LEN + kZIP64_EXTENDED_MAGIC_LEN;
476 off += (Int_t)size + kZIP64_EXTENDED_MAGIC_LEN + kZIP64_EXTENDED_MAGIC_LEN;
486 Int_t TZIPFile::SetCurrentMember()
490 if (fMemberIndex > -1) {
491 fCurMember = (TZIPMember *) fMembers->At(fMemberIndex);
494 fMemberName = fCurMember->GetName();
496 for (
int i = 0; i < fMembers->GetEntriesFast(); i++) {
497 TZIPMember *m = (TZIPMember *) fMembers->At(i);
498 if (fMemberName == m->fName) {
508 return ReadMemberHeader((TZIPMember *)fCurMember);
514 UInt_t TZIPFile::Get(
const void *buffer, Int_t bytes)
519 Error(
"Get",
"can not read > 4 byte integers, use Get64");
523 memcpy(&value, buffer, bytes);
525 const UChar_t *buf =
static_cast<const unsigned char *
>(buffer);
526 for (UInt_t shift = 0; bytes; shift += 8, --bytes, ++buf)
527 value += *buf << shift;
535 ULong64_t TZIPFile::Get64(
const void *buffer, Int_t bytes)
540 Error(
"Get64",
"bytes must be 8 (asked for %d)", bytes);
545 memcpy(&value, buffer, bytes);
547 const UChar_t *buf =
static_cast<const unsigned char *
>(buffer);
548 for (UInt_t shift = 0; bytes; shift += 8, --bytes, ++buf)
549 value += *buf << shift;
557 void TZIPFile::Print(Option_t *)
const
564 ClassImp(TZIPMember);
569 TZIPMember::TZIPMember()
585 TZIPMember::TZIPMember(
const char *name)
586 : TArchiveMember(name)
602 TZIPMember::TZIPMember(
const TZIPMember &member)
603 : TArchiveMember(member)
606 fLocalLen = member.fLocalLen;
608 fGlobalLen = member.fGlobalLen;
609 fCRC32 = member.fCRC32;
610 fAttrInt = member.fAttrInt;
611 fAttrExt = member.fAttrExt;
612 fMethod = member.fMethod;
613 fLevel = member.fLevel;
616 fLocal =
new char [fLocalLen];
617 memcpy(fLocal, member.fLocal, fLocalLen);
619 if (member.fGlobal) {
620 fGlobal =
new char [fGlobalLen];
621 memcpy(fGlobal, member.fGlobal, fGlobalLen);
628 TZIPMember &TZIPMember::operator=(
const TZIPMember &rhs)
631 TArchiveMember::operator=(rhs);
633 delete [] (
char*) fLocal;
634 delete [] (
char*) fGlobal;
637 fLocalLen = rhs.fLocalLen;
639 fGlobalLen = rhs.fGlobalLen;
641 fAttrInt = rhs.fAttrInt;
642 fAttrExt = rhs.fAttrExt;
643 fMethod = rhs.fMethod;
647 fLocal =
new char [fLocalLen];
648 memcpy(fLocal, rhs.fLocal, fLocalLen);
651 fGlobal =
new char [fGlobalLen];
652 memcpy(fGlobal, rhs.fGlobal, fGlobalLen);
661 TZIPMember::~TZIPMember()
663 delete [] (
char*) fLocal;
664 delete [] (
char*) fGlobal;
670 void TZIPMember::Print(Option_t *)
const
672 printf(
"%-20lld", fDsize);
673 printf(
" %s %s\n", fModTime.AsSQLString(), fName.Data());