From a107124c97570208df619af6a2968bcda8b26fdc Mon Sep 17 00:00:00 2001 From: Michal Novotny Date: Wed, 16 Dec 2009 00:01:08 +0100 Subject: [PATCH] Bug 525741 - two JAR tests fail if modification date of their files is on day daylight saving time starts or ends and after time change. r=dtownsend,tglek --- modules/libjar/nsJAR.cpp | 35 +----- modules/libjar/nsJAR.h | 5 +- modules/libjar/nsJARInputStream.cpp | 2 +- modules/libjar/nsZipArchive.cpp | 101 ++++++++++++++--- modules/libjar/nsZipArchive.h | 22 ++-- modules/libjar/test/unit/test_bug379841.js | 4 +- modules/libjar/zipstruct.h | 4 + .../libjar/zipwriter/src/StreamFunctions.h | 38 +++---- modules/libjar/zipwriter/src/nsZipHeader.cpp | 102 +++++++++++++++--- modules/libjar/zipwriter/src/nsZipHeader.h | 10 +- modules/libjar/zipwriter/src/nsZipWriter.cpp | 12 +-- .../zipwriter/test/unit/head_zipwriter.js | 4 +- .../zipwriter/test/unit/test_asyncadd.js | 8 +- .../zipwriter/test/unit/test_bug419769_1.js | 4 +- .../zipwriter/test/unit/test_bug425768.js | 4 +- .../zipwriter/test/unit/test_deflatedata.js | 4 +- .../zipwriter/test/unit/test_editexisting.js | 9 +- .../zipwriter/test/unit/test_storedata.js | 5 +- .../libjar/zipwriter/test/unit/test_sync.js | 8 +- 19 files changed, 246 insertions(+), 135 deletions(-) diff --git a/modules/libjar/nsJAR.cpp b/modules/libjar/nsJAR.cpp index 8cf28c65ba1..a28293bb3b0 100644 --- a/modules/libjar/nsJAR.cpp +++ b/modules/libjar/nsJAR.cpp @@ -259,14 +259,9 @@ nsJAR::Extract(const char *zipEntry, nsIFile* outFile) } if (NS_FAILED(rv)) return rv; - PRTime prtime = GetModTime(item->Date(), item->Time()); // nsIFile needs milliseconds, while prtime is in microseconds. - PRTime conversion = LL_ZERO; - PRTime newTime = LL_ZERO; - LL_I2L(conversion, PR_USEC_PER_MSEC); - LL_DIV(newTime, prtime, conversion); // non-fatal if this fails, ignore errors - outFile->SetLastModifiedTime(newTime); + outFile->SetLastModifiedTime(item->LastModTime() / PR_USEC_PER_MSEC); return NS_OK; } @@ -933,8 +928,7 @@ nsJARItem::nsJARItem(nsZipItem* aZipItem) : mSize(aZipItem->Size()), mRealsize(aZipItem->RealSize()), mCrc32(aZipItem->CRC32()), - mDate(aZipItem->Date()), - mTime(aZipItem->Time()), + mLastModTime(aZipItem->LastModTime()), mCompression(aZipItem->Compression()), mIsDirectory(aZipItem->IsDirectory()), mIsSynthetic(aZipItem->isSynthetic) @@ -1021,7 +1015,7 @@ nsJARItem::GetLastModifiedTime(PRTime* aLastModTime) { NS_ENSURE_ARG_POINTER(aLastModTime); - *aLastModTime = GetModTime(mDate, mTime); + *aLastModTime = mLastModTime; return NS_OK; } @@ -1267,27 +1261,4 @@ nsZipReaderCache::Observe(nsISupports *aSubject, return NS_OK; } -PRTime GetModTime(PRUint16 aDate, PRUint16 aTime) -{ - PRExplodedTime time; - - time.tm_usec = 0; - - time.tm_hour = (aTime >> 11) & 0x1F; - time.tm_min = (aTime >> 5) & 0x3F; - time.tm_sec = (aTime & 0x1F) * 2; - - time.tm_year = (aDate >> 9) + 1980; - time.tm_month = ((aDate >> 5) & 0x0F)-1; - time.tm_mday = aDate & 0x1F; - - time.tm_params.tp_gmt_offset = 0; - time.tm_params.tp_dst_offset = 0; - - PR_NormalizeTime(&time, PR_GMTParameters); - time.tm_params = PR_LocalTimeParameters(&time); - - return PR_ImplodeTime(&time); -} - //////////////////////////////////////////////////////////////////////////////// diff --git a/modules/libjar/nsJAR.h b/modules/libjar/nsJAR.h index c8806009f17..ab7a3a7c72e 100644 --- a/modules/libjar/nsJAR.h +++ b/modules/libjar/nsJAR.h @@ -85,8 +85,6 @@ typedef enum JAR_NOT_SIGNED = 7 } JARManifestStatusType; -PRTime GetModTime(PRUint16 aDate, PRUint16 aTime); - /*------------------------------------------------------------------------- * Class nsJAR declaration. * nsJAR serves as an XPCOM wrapper for nsZipArchive with the addition of @@ -184,8 +182,7 @@ private: PRUint32 mSize; /* size in original file */ PRUint32 mRealsize; /* inflated size */ PRUint32 mCrc32; - PRUint16 mDate; - PRUint16 mTime; + PRTime mLastModTime; PRUint16 mCompression; PRPackedBool mIsDirectory; PRPackedBool mIsSynthetic; diff --git a/modules/libjar/nsJARInputStream.cpp b/modules/libjar/nsJARInputStream.cpp index 3c5e7a4dec4..838aebe54b4 100644 --- a/modules/libjar/nsJARInputStream.cpp +++ b/modules/libjar/nsJARInputStream.cpp @@ -346,7 +346,7 @@ nsJARInputStream::ReadDirectory(char* aBuffer, PRUint32 aCount, PRUint32 *aBytes // Last Modified Time PRExplodedTime tm; - PR_ExplodeTime(GetModTime(ze->Date(), ze->Time()), PR_GMTParameters, &tm); + PR_ExplodeTime(ze->LastModTime(), PR_GMTParameters, &tm); char itemLastModTime[65]; PR_FormatTimeUSEnglish(itemLastModTime, sizeof(itemLastModTime), diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp index 412b328d001..92c7e1c8cd1 100644 --- a/modules/libjar/nsZipArchive.cpp +++ b/modules/libjar/nsZipArchive.cpp @@ -104,8 +104,8 @@ static const PRUint32 kMaxNameLength = PATH_MAX; /* Maximum name length */ static const PRUint16 kSyntheticTime = 0; static const PRUint16 kSyntheticDate = (1 + (1 << 5) + (0 << 9)); -static PRUint16 xtoint(const unsigned char *ii); -static PRUint32 xtolong(const unsigned char *ll); +static PRUint16 xtoint(const PRUint8 *ii); +static PRUint32 xtolong(const PRUint8 *ll); static PRUint32 HashName(const char* aName, PRUint16 nameLen); #if defined(XP_UNIX) || defined(XP_BEOS) static nsresult ResolveSymlink(const char *path); @@ -848,7 +848,7 @@ static PRUint32 HashName(const char* aName, PRUint16 len) * Converts a two byte ugly endianed integer * to our platform's integer. */ -static PRUint16 xtoint (const unsigned char *ii) +static PRUint16 xtoint (const PRUint8 *ii) { return (PRUint16) ((ii [0]) | (ii [1] << 8)); } @@ -859,7 +859,7 @@ static PRUint16 xtoint (const unsigned char *ii) * Converts a four byte ugly endianed integer * to our platform's integer. */ -static PRUint32 xtolong (const unsigned char *ll) +static PRUint32 xtolong (const PRUint8 *ll) { return (PRUint32)( (ll [0] << 0) | (ll [1] << 8) | @@ -867,56 +867,129 @@ static PRUint32 xtolong (const unsigned char *ll) (ll [3] << 24) ); } -PRUint32 const nsZipItem::LocalOffset() +/* + * GetModTime + * + * returns last modification time in microseconds + */ +static PRTime GetModTime(PRUint16 aDate, PRUint16 aTime) +{ + // Note that on DST shift we can't handle correctly the hour that is valid + // in both DST zones + PRExplodedTime time; + + time.tm_usec = 0; + + time.tm_hour = (aTime >> 11) & 0x1F; + time.tm_min = (aTime >> 5) & 0x3F; + time.tm_sec = (aTime & 0x1F) * 2; + + time.tm_year = (aDate >> 9) + 1980; + time.tm_month = ((aDate >> 5) & 0x0F) - 1; + time.tm_mday = aDate & 0x1F; + + time.tm_params.tp_gmt_offset = 0; + time.tm_params.tp_dst_offset = 0; + + PR_NormalizeTime(&time, PR_GMTParameters); + time.tm_params.tp_gmt_offset = PR_LocalTimeParameters(&time).tp_gmt_offset; + PR_NormalizeTime(&time, PR_GMTParameters); + time.tm_params.tp_dst_offset = PR_LocalTimeParameters(&time).tp_dst_offset; + + return PR_ImplodeTime(&time); +} + +PRUint32 nsZipItem::LocalOffset() { return xtolong(central->localhdr_offset); } -PRUint32 const nsZipItem::Size() +PRUint32 nsZipItem::Size() { return isSynthetic ? 0 : xtolong(central->size); } -PRUint32 const nsZipItem::RealSize() +PRUint32 nsZipItem::RealSize() { return isSynthetic ? 0 : xtolong(central->orglen); } -PRUint32 const nsZipItem::CRC32() +PRUint32 nsZipItem::CRC32() { return isSynthetic ? 0 : xtolong(central->crc32); } -PRUint16 const nsZipItem::Date() +PRUint16 nsZipItem::Date() { return isSynthetic ? kSyntheticDate : xtoint(central->date); } -PRUint16 const nsZipItem::Time() +PRUint16 nsZipItem::Time() { return isSynthetic ? kSyntheticTime : xtoint(central->time); } -PRUint16 const nsZipItem::Compression() +PRUint16 nsZipItem::Compression() { return isSynthetic ? STORED : xtoint(central->method); } -bool const nsZipItem::IsDirectory() +bool nsZipItem::IsDirectory() { return isSynthetic || ((nameLength > 0) && ('/' == Name()[nameLength - 1])); } -PRUint16 const nsZipItem::Mode() +PRUint16 nsZipItem::Mode() { if (isSynthetic) return 0755; return ((PRUint16)(central->external_attributes[2]) | 0x100); } +const PRUint8 * nsZipItem::GetExtraField(PRUint16 aTag, PRUint16 *aBlockSize) +{ + if (isSynthetic) return NULL; + + const unsigned char *buf = ((const unsigned char*)central) + ZIPCENTRAL_SIZE + + nameLength; + PRUint32 buflen = (PRUint32)xtoint(central->extrafield_len); + PRUint32 pos = 0; + PRUint16 tag, blocksize; + + while (buf && (pos + 4) <= buflen) { + tag = xtoint(buf + pos); + blocksize = xtoint(buf + pos + 2); + + if (aTag == tag && (pos + 4 + blocksize) <= buflen) { + *aBlockSize = blocksize; + return buf + pos; + } + + pos += blocksize + 4; + } + + return NULL; +} + + +PRTime nsZipItem::LastModTime() +{ + if (isSynthetic) return GetModTime(kSyntheticDate, kSyntheticTime); + + // Try to read timestamp from extra field + PRUint16 blocksize; + const PRUint8 *tsField = GetExtraField(EXTENDED_TIMESTAMP_FIELD, &blocksize); + if (tsField && blocksize >= 5 && tsField[4] & EXTENDED_TIMESTAMP_MODTIME) { + return (PRTime)(xtolong(tsField + 5)) * PR_USEC_PER_SEC; + } + + return GetModTime(Date(), Time()); +} + #if defined(XP_UNIX) || defined(XP_BEOS) -bool const nsZipItem::IsSymlink() +bool nsZipItem::IsSymlink() { if (isSynthetic) return false; return (xtoint(central->external_attributes+2) & S_IFMT) == S_IFLNK; } #endif + diff --git a/modules/libjar/nsZipArchive.h b/modules/libjar/nsZipArchive.h index 277912d50b3..d202135480f 100644 --- a/modules/libjar/nsZipArchive.h +++ b/modules/libjar/nsZipArchive.h @@ -83,18 +83,20 @@ class nsZipItem public: const char* Name() { return ((const char*)central) + ZIPCENTRAL_SIZE; } - PRUint32 const LocalOffset(); - PRUint32 const Size(); - PRUint32 const RealSize(); - PRUint32 const CRC32(); - PRUint16 const Date(); - PRUint16 const Time(); - PRUint16 const Compression(); - bool const IsDirectory(); - PRUint16 const Mode(); + PRUint32 LocalOffset(); + PRUint32 Size(); + PRUint32 RealSize(); + PRUint32 CRC32(); + PRUint16 Date(); + PRUint16 Time(); + PRUint16 Compression(); + bool IsDirectory(); + PRUint16 Mode(); + const PRUint8* GetExtraField(PRUint16 aTag, PRUint16 *aBlockSize); + PRTime LastModTime(); #if defined(XP_UNIX) || defined(XP_BEOS) - bool const IsSymlink(); + bool IsSymlink(); #endif nsZipItem* next; diff --git a/modules/libjar/test/unit/test_bug379841.js b/modules/libjar/test/unit/test_bug379841.js index 469220e6252..98ed0cc144a 100644 --- a/modules/libjar/test/unit/test_bug379841.js +++ b/modules/libjar/test/unit/test_bug379841.js @@ -7,8 +7,8 @@ const path = "data/test_bug379841.zip"; const MAX_TIME_DIFF = 2000000; var ENTRY_NAME = "test"; -// Actual time of file was 07 May 2007 14:35:49 -var ENTRY_TIME = new Date(2007, 4, 7, 14, 35, 49, 0); +// Actual time of file was 07 May 2007 13:35:49 UTC +var ENTRY_TIME = new Date(Date.UTC(2007, 4, 7, 13, 35, 49, 0)); function run_test() { var file = do_get_file(path); diff --git a/modules/libjar/zipstruct.h b/modules/libjar/zipstruct.h index 9fcced54c8a..6da170abe38 100644 --- a/modules/libjar/zipstruct.h +++ b/modules/libjar/zipstruct.h @@ -122,6 +122,10 @@ typedef struct ZipEnd_ #define CENTRALSIG 0x02014B50l #define ENDSIG 0x06054B50l +/* extra fields */ +#define EXTENDED_TIMESTAMP_FIELD 0x5455 +#define EXTENDED_TIMESTAMP_MODTIME 0x01 + /* compression methods */ #define STORED 0 #define SHRUNK 1 diff --git a/modules/libjar/zipwriter/src/StreamFunctions.h b/modules/libjar/zipwriter/src/StreamFunctions.h index 38f864ba006..2f1a84f0d90 100644 --- a/modules/libjar/zipwriter/src/StreamFunctions.h +++ b/modules/libjar/zipwriter/src/StreamFunctions.h @@ -50,47 +50,43 @@ * The off argument, where present, is incremented according to the number of * bytes consumed from the buffer. */ -inline NS_HIDDEN_(void) WRITE8(char* buf, PRUint32* off, PRUint8 val) +inline NS_HIDDEN_(void) WRITE8(PRUint8* buf, PRUint32* off, PRUint8 val) { - buf[(*off)++] = val & 0xff; + buf[(*off)++] = val; } -inline NS_HIDDEN_(void) WRITE16(char* buf, PRUint32* off, PRUint16 val) +inline NS_HIDDEN_(void) WRITE16(PRUint8* buf, PRUint32* off, PRUint16 val) { - buf[(*off)++] = val & 0xff; - buf[(*off)++] = (val >> 8) & 0xff; + WRITE8(buf, off, val & 0xff); + WRITE8(buf, off, (val >> 8) & 0xff); } -inline NS_HIDDEN_(void) WRITE32(char* buf, PRUint32* off, PRUint32 val) +inline NS_HIDDEN_(void) WRITE32(PRUint8* buf, PRUint32* off, PRUint32 val) { - buf[(*off)++] = val & 0xff; - buf[(*off)++] = (val >> 8) & 0xff; - buf[(*off)++] = (val >> 16) & 0xff; - buf[(*off)++] = (val >> 24) & 0xff; + WRITE16(buf, off, val & 0xffff); + WRITE16(buf, off, (val >> 16) & 0xffff); } -inline NS_HIDDEN_(PRUint8) READ8(char* buf, PRUint32* off) +inline NS_HIDDEN_(PRUint8) READ8(const PRUint8* buf, PRUint32* off) { - return (PRUint8)buf[(*off)++]; + return buf[(*off)++]; } -inline NS_HIDDEN_(PRUint16) READ16(char* buf, PRUint32* off) +inline NS_HIDDEN_(PRUint16) READ16(const PRUint8* buf, PRUint32* off) { - PRUint16 val = (PRUint16)buf[(*off)++] & 0xff; - val |= ((PRUint16)buf[(*off)++] & 0xff) << 8; + PRUint16 val = READ8(buf, off); + val |= READ8(buf, off) << 8; return val; } -inline NS_HIDDEN_(PRUint32) READ32(char* buf, PRUint32* off) +inline NS_HIDDEN_(PRUint32) READ32(const PRUint8* buf, PRUint32* off) { - PRUint32 val = (PRUint32)buf[(*off)++] & 0xff; - val |= ((PRUint32)buf[(*off)++] & 0xff) << 8; - val |= ((PRUint32)buf[(*off)++] & 0xff) << 16; - val |= ((PRUint32)buf[(*off)++] & 0xff) << 24; + PRUint32 val = READ16(buf, off); + val |= READ16(buf, off) << 16; return val; } -inline NS_HIDDEN_(PRUint32) PEEK32(unsigned char *buf) +inline NS_HIDDEN_(PRUint32) PEEK32(const PRUint8* buf) { return (PRUint32)( (buf [0] ) | (buf [1] << 8) | diff --git a/modules/libjar/zipwriter/src/nsZipHeader.cpp b/modules/libjar/zipwriter/src/nsZipHeader.cpp index e83f8d28677..9e7c1e54a14 100644 --- a/modules/libjar/zipwriter/src/nsZipHeader.cpp +++ b/modules/libjar/zipwriter/src/nsZipHeader.cpp @@ -47,6 +47,9 @@ #define FLAGS_IS_UTF8 0x800 +#define ZIP_EXTENDED_TIMESTAMP_FIELD 0x5455 +#define ZIP_EXTENDED_TIMESTAMP_MODTIME 0x01 + /** * nsZipHeader represents an entry from a zip file. */ @@ -105,11 +108,28 @@ NS_IMETHODIMP nsZipHeader::GetLastModifiedTime(PRTime *aLastModifiedTime) { NS_ASSERTION(mInited, "Not initalised"); + // Try to read timestamp from extra field + PRUint16 blocksize; + const PRUint8 *tsField = GetExtraField(ZIP_EXTENDED_TIMESTAMP_FIELD, PR_FALSE, &blocksize); + if (tsField && blocksize >= 5) { + PRUint32 pos = 4; + PRUint8 flags; + flags = READ8(tsField, &pos); + if (flags & ZIP_EXTENDED_TIMESTAMP_MODTIME) { + *aLastModifiedTime = (PRTime)(READ32(tsField, &pos)) + * PR_USEC_PER_SEC; + return NS_OK; + } + } + + // Use DOS date/time fields + // Note that on DST shift we can't handle correctly the hour that is valid + // in both DST zones PRExplodedTime time; time.tm_usec = 0; - time.tm_hour = mTime >> 11; + time.tm_hour = (mTime >> 11) & 0x1F; time.tm_min = (mTime >> 5) & 0x3F; time.tm_sec = (mTime & 0x1F) * 2; @@ -121,7 +141,9 @@ NS_IMETHODIMP nsZipHeader::GetLastModifiedTime(PRTime *aLastModifiedTime) time.tm_params.tp_dst_offset = 0; PR_NormalizeTime(&time, PR_GMTParameters); - time.tm_params = PR_LocalTimeParameters(&time); + time.tm_params.tp_gmt_offset = PR_LocalTimeParameters(&time).tp_gmt_offset; + PR_NormalizeTime(&time, PR_GMTParameters); + time.tm_params.tp_dst_offset = PR_LocalTimeParameters(&time).tp_dst_offset; *aLastModifiedTime = PR_ImplodeTime(&time); @@ -149,6 +171,27 @@ void nsZipHeader::Init(const nsACString & aPath, PRTime aDate, PRUint32 aAttr, mDate = time.tm_mday + ((time.tm_month + 1) << 5) + ((time.tm_year - 1980) << 9); + // Store modification timestamp as extra field + // First fill CDS extra field + mFieldLength = 9; + mExtraField = new PRUint8[mFieldLength]; + if (!mExtraField) { + mFieldLength = 0; + } else { + PRUint32 pos = 0; + WRITE16(mExtraField.get(), &pos, ZIP_EXTENDED_TIMESTAMP_FIELD); + WRITE16(mExtraField.get(), &pos, 5); + WRITE8(mExtraField.get(), &pos, ZIP_EXTENDED_TIMESTAMP_MODTIME); + WRITE32(mExtraField.get(), &pos, aDate / PR_USEC_PER_SEC); + + // Fill local extra field + mLocalExtraField = new PRUint8[mFieldLength]; + if (mLocalExtraField) { + mLocalFieldLength = mFieldLength; + memcpy(mLocalExtraField.get(), mExtraField.get(), mLocalFieldLength); + } + } + mEAttr = aAttr; mOffset = aOffset; mName = aPath; @@ -160,14 +203,14 @@ void nsZipHeader::Init(const nsACString & aPath, PRTime aDate, PRUint32 aAttr, PRUint32 nsZipHeader::GetFileHeaderLength() { - return ZIP_FILE_HEADER_SIZE + mName.Length(); + return ZIP_FILE_HEADER_SIZE + mName.Length() + mLocalFieldLength; } nsresult nsZipHeader::WriteFileHeader(nsIOutputStream *aStream) { NS_ASSERTION(mInited, "Not initalised"); - char buf[ZIP_FILE_HEADER_SIZE]; + PRUint8 buf[ZIP_FILE_HEADER_SIZE]; PRUint32 pos = 0; WRITE32(buf, &pos, ZIP_FILE_HEADER_SIGNATURE); WRITE16(buf, &pos, mVersionNeeded); @@ -179,12 +222,21 @@ nsresult nsZipHeader::WriteFileHeader(nsIOutputStream *aStream) WRITE32(buf, &pos, mCSize); WRITE32(buf, &pos, mUSize); WRITE16(buf, &pos, mName.Length()); - WRITE16(buf, &pos, 0); + WRITE16(buf, &pos, mLocalFieldLength); - nsresult rv = ZW_WriteData(aStream, buf, pos); + nsresult rv = ZW_WriteData(aStream, (const char *)buf, pos); NS_ENSURE_SUCCESS(rv, rv); - return ZW_WriteData(aStream, mName.get(), mName.Length()); + rv = ZW_WriteData(aStream, mName.get(), mName.Length()); + NS_ENSURE_SUCCESS(rv, rv); + + if (mLocalFieldLength) + { + rv = ZW_WriteData(aStream, (const char *)mLocalExtraField.get(), mLocalFieldLength); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; } PRUint32 nsZipHeader::GetCDSHeaderLength() @@ -197,7 +249,7 @@ nsresult nsZipHeader::WriteCDSHeader(nsIOutputStream *aStream) { NS_ASSERTION(mInited, "Not initalised"); - char buf[ZIP_CDS_HEADER_SIZE]; + PRUint8 buf[ZIP_CDS_HEADER_SIZE]; PRUint32 pos = 0; WRITE32(buf, &pos, ZIP_CDS_HEADER_SIGNATURE); WRITE16(buf, &pos, mVersionMade); @@ -217,13 +269,13 @@ nsresult nsZipHeader::WriteCDSHeader(nsIOutputStream *aStream) WRITE32(buf, &pos, mEAttr); WRITE32(buf, &pos, mOffset); - nsresult rv = ZW_WriteData(aStream, buf, pos); + nsresult rv = ZW_WriteData(aStream, (const char *)buf, pos); NS_ENSURE_SUCCESS(rv, rv); rv = ZW_WriteData(aStream, mName.get(), mName.Length()); NS_ENSURE_SUCCESS(rv, rv); if (mExtraField) { - rv = ZW_WriteData(aStream, mExtraField, mFieldLength); + rv = ZW_WriteData(aStream, (const char *)mExtraField.get(), mFieldLength); NS_ENSURE_SUCCESS(rv, rv); } return ZW_WriteData(aStream, mComment.get(), mComment.Length()); @@ -233,9 +285,9 @@ nsresult nsZipHeader::ReadCDSHeader(nsIInputStream *stream) { NS_ASSERTION(!mInited, "Already initalised"); - char buf[ZIP_CDS_HEADER_SIZE]; + PRUint8 buf[ZIP_CDS_HEADER_SIZE]; - nsresult rv = ZW_ReadData(stream, buf, ZIP_CDS_HEADER_SIZE); + nsresult rv = ZW_ReadData(stream, (char *)buf, ZIP_CDS_HEADER_SIZE); NS_ENSURE_SUCCESS(rv, rv); PRUint32 pos = 0; @@ -271,9 +323,9 @@ nsresult nsZipHeader::ReadCDSHeader(nsIInputStream *stream) mName = NS_LITERAL_CSTRING(""); if (mFieldLength > 0) { - mExtraField = new char[mFieldLength]; + mExtraField = new PRUint8[mFieldLength]; NS_ENSURE_TRUE(mExtraField, NS_ERROR_OUT_OF_MEMORY); - rv = ZW_ReadData(stream, mExtraField.get(), mFieldLength); + rv = ZW_ReadData(stream, (char *)mExtraField.get(), mFieldLength); NS_ENSURE_SUCCESS(rv, rv); } @@ -290,3 +342,25 @@ nsresult nsZipHeader::ReadCDSHeader(nsIInputStream *stream) mInited = PR_TRUE; return NS_OK; } + +const PRUint8 * nsZipHeader::GetExtraField(PRUint16 aTag, PRBool aLocal, PRUint16 *aBlockSize) +{ + const PRUint8 *buf = aLocal ? mLocalExtraField : mExtraField; + PRUint32 buflen = aLocal ? mLocalFieldLength : mFieldLength; + PRUint32 pos = 0; + PRUint16 tag, blocksize; + + while (buf && (pos + 4) <= buflen) { + tag = READ16(buf, &pos); + blocksize = READ16(buf, &pos); + + if (aTag == tag && (pos + blocksize) <= buflen) { + *aBlockSize = blocksize; + return buf + pos - 4; + } + + pos += blocksize; + } + + return NULL; +} diff --git a/modules/libjar/zipwriter/src/nsZipHeader.h b/modules/libjar/zipwriter/src/nsZipHeader.h index b0714645043..22f86cc2cf3 100644 --- a/modules/libjar/zipwriter/src/nsZipHeader.h +++ b/modules/libjar/zipwriter/src/nsZipHeader.h @@ -68,6 +68,7 @@ public: mEAttr(0), mOffset(0), mFieldLength(0), + mLocalFieldLength(0), mVersionMade(0x0300 + 23), // Generated on Unix by v2.3 (matches infozip) mVersionNeeded(20), // Requires v2.0 to extract mFlags(0), @@ -77,13 +78,15 @@ public: mDisk(0), mIAttr(0), mInited(PR_FALSE), - mExtraField(NULL) + mExtraField(NULL), + mLocalExtraField(NULL) { } ~nsZipHeader() { mExtraField = NULL; + mLocalExtraField = NULL; } PRUint32 mCRC; @@ -92,6 +95,7 @@ public: PRUint32 mEAttr; PRUint32 mOffset; PRUint32 mFieldLength; + PRUint32 mLocalFieldLength; PRUint16 mVersionMade; PRUint16 mVersionNeeded; PRUint16 mFlags; @@ -103,7 +107,8 @@ public: PRPackedBool mInited; nsCString mName; nsCString mComment; - nsAutoArrayPtr mExtraField; + nsAutoArrayPtr mExtraField; + nsAutoArrayPtr mLocalExtraField; void Init(const nsACString & aPath, PRTime aDate, PRUint32 aAttr, PRUint32 aOffset); @@ -112,6 +117,7 @@ public: PRUint32 GetCDSHeaderLength(); nsresult WriteCDSHeader(nsIOutputStream *aStream); nsresult ReadCDSHeader(nsIInputStream *aStream); + const PRUint8 * GetExtraField(PRUint16 aTag, PRBool aLocal, PRUint16 *aBlockSize); }; #endif diff --git a/modules/libjar/zipwriter/src/nsZipWriter.cpp b/modules/libjar/zipwriter/src/nsZipWriter.cpp index 9894585c3a3..e5f7a434929 100644 --- a/modules/libjar/zipwriter/src/nsZipWriter.cpp +++ b/modules/libjar/zipwriter/src/nsZipWriter.cpp @@ -147,7 +147,7 @@ nsresult nsZipWriter::ReadFile(nsIFile *aFile) rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), aFile); NS_ENSURE_SUCCESS(rv, rv); - char buf[1024]; + PRUint8 buf[1024]; PRInt64 seek = size - 1024; PRUint32 length = 1024; @@ -164,7 +164,7 @@ nsresult nsZipWriter::ReadFile(nsIFile *aFile) inputStream->Close(); return rv; } - rv = ZW_ReadData(inputStream, buf, length); + rv = ZW_ReadData(inputStream, (char *)buf, length); if (NS_FAILED(rv)) { inputStream->Close(); return rv; @@ -177,7 +177,7 @@ nsresult nsZipWriter::ReadFile(nsIFile *aFile) // We know it's at least this far from the end for (PRUint32 pos = length - ZIP_EOCDR_HEADER_SIZE; (PRInt32)pos >= 0; pos--) { - PRUint32 sig = PEEK32((unsigned char *)buf + pos); + PRUint32 sig = PEEK32(buf + pos); if (sig == ZIP_EOCDR_HEADER_SIGNATURE) { // Skip down to entry count pos += 10; @@ -190,7 +190,7 @@ nsresult nsZipWriter::ReadFile(nsIFile *aFile) if (commentlen == 0) mComment.Truncate(); else if (pos + commentlen <= length) - mComment.Assign(buf + pos, commentlen); + mComment.Assign((const char *)buf + pos, commentlen); else { if ((seek + pos + commentlen) > size) { inputStream->Close(); @@ -682,7 +682,7 @@ NS_IMETHODIMP nsZipWriter::Close() size += mHeaders[i]->GetCDSHeaderLength(); } - char buf[ZIP_EOCDR_HEADER_SIZE]; + PRUint8 buf[ZIP_EOCDR_HEADER_SIZE]; PRUint32 pos = 0; WRITE32(buf, &pos, ZIP_EOCDR_HEADER_SIGNATURE); WRITE16(buf, &pos, 0); @@ -693,7 +693,7 @@ NS_IMETHODIMP nsZipWriter::Close() WRITE32(buf, &pos, mCDSOffset); WRITE16(buf, &pos, mComment.Length()); - nsresult rv = ZW_WriteData(mStream, buf, pos); + nsresult rv = ZW_WriteData(mStream, (const char *)buf, pos); if (NS_FAILED(rv)) { Cleanup(); return rv; diff --git a/modules/libjar/zipwriter/test/unit/head_zipwriter.js b/modules/libjar/zipwriter/test/unit/head_zipwriter.js index 07c3f97220e..2134263ae9c 100644 --- a/modules/libjar/zipwriter/test/unit/head_zipwriter.js +++ b/modules/libjar/zipwriter/test/unit/head_zipwriter.js @@ -55,12 +55,10 @@ const ZIP_FILE_HEADER_SIZE = 30; const ZIP_CDS_HEADER_SIZE = 46; const ZIP_METHOD_STORE = 0 const ZIP_METHOD_DEFLATE = 8 +const ZIP_EXTENDED_TIMESTAMP_SIZE = 9; const PR_USEC_PER_MSEC = 1000; -// ZIP times are stored at a 2 second resolution. -const TIME_RESOLUTION = 2000; - const DATA_DIR = "data/"; var ZipWriter = Components.Constructor("@mozilla.org/zipwriter;1", diff --git a/modules/libjar/zipwriter/test/unit/test_asyncadd.js b/modules/libjar/zipwriter/test/unit/test_asyncadd.js index c6792d40809..c63866fe5b0 100644 --- a/modules/libjar/zipwriter/test/unit/test_asyncadd.js +++ b/modules/libjar/zipwriter/test/unit/test_asyncadd.js @@ -77,11 +77,8 @@ var observer = { do_check_eq(entry.realSize, TESTS[i].size); do_check_eq(entry.size, TESTS[i].size); do_check_eq(entry.CRC32, TESTS[i].crc); - - var diff = Math.abs((entry.lastModifiedTime/PR_USEC_PER_MSEC) - - source.lastModifiedTime); - if (diff > TIME_RESOLUTION) - do_throw(diff); + do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC, + source.lastModifiedTime); zipR.test(TESTS[i].name); } @@ -100,6 +97,7 @@ function run_test() zipW.addEntryFile(TESTS[i].name, Ci.nsIZipWriter.COMPRESSION_NONE, source, true); size += ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + + (ZIP_EXTENDED_TIMESTAMP_SIZE * 2) + (TESTS[i].name.length*2) + TESTS[i].size; } do_test_pending(); diff --git a/modules/libjar/zipwriter/test/unit/test_bug419769_1.js b/modules/libjar/zipwriter/test/unit/test_bug419769_1.js index ac18ae6be8f..cb105e129f5 100644 --- a/modules/libjar/zipwriter/test/unit/test_bug419769_1.js +++ b/modules/libjar/zipwriter/test/unit/test_bug419769_1.js @@ -55,9 +55,7 @@ function testpass(source) // Should be stored do_check_eq(entry.compression, ZIP_METHOD_DEFLATE); - var diff = Math.abs((entry.lastModifiedTime / PR_USEC_PER_MSEC) - time); - if (diff > TIME_RESOLUTION) - do_throw(diff); + do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC, time); // File size should match our data size. do_check_eq(entry.realSize, DATA.length); diff --git a/modules/libjar/zipwriter/test/unit/test_bug425768.js b/modules/libjar/zipwriter/test/unit/test_bug425768.js index fcdb947f735..cbc008d6e4c 100644 --- a/modules/libjar/zipwriter/test/unit/test_bug425768.js +++ b/modules/libjar/zipwriter/test/unit/test_bug425768.js @@ -57,6 +57,8 @@ function run_test() // Adding the directory would have added a fixed amount to the file size. // Any difference suggests the CDS was written out incorrectly. - var extra = ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + (DIRNAME.length * 2); + var extra = ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + + (DIRNAME.length * 2) + (ZIP_EXTENDED_TIMESTAMP_SIZE * 2); + do_check_eq(source.fileSize + extra, tmpFile.fileSize); } diff --git a/modules/libjar/zipwriter/test/unit/test_deflatedata.js b/modules/libjar/zipwriter/test/unit/test_deflatedata.js index 20b67c10aae..d51aa52744d 100644 --- a/modules/libjar/zipwriter/test/unit/test_deflatedata.js +++ b/modules/libjar/zipwriter/test/unit/test_deflatedata.js @@ -65,9 +65,7 @@ function run_test() do_check_eq(entry.compression, ZIP_METHOD_DEFLATE); do_check_eq(entry.CRC32, CRC); do_check_eq(entry.realSize, DATA.length); - var diff = Math.abs((entry.lastModifiedTime/PR_USEC_PER_MSEC) - time); - if (diff > TIME_RESOLUTION) - do_throw(diff); + do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC, time); zipW.close(); diff --git a/modules/libjar/zipwriter/test/unit/test_editexisting.js b/modules/libjar/zipwriter/test/unit/test_editexisting.js index 23e1d1ef844..a055a0f095c 100644 --- a/modules/libjar/zipwriter/test/unit/test_editexisting.js +++ b/modules/libjar/zipwriter/test/unit/test_editexisting.js @@ -42,13 +42,13 @@ var TESTS = [ name: "test.txt", size: 232, crc: 0x0373ac26, - time: new Date(2007, 4, 1, 21, 44, 56) + time: Date.UTC(2007, 4, 1, 20, 44, 55) }, { name: "test.png", size: 3402, crc: 0x504a5c30, - time: new Date(2007, 4, 1, 21, 49, 40) + time: Date.UTC(2007, 4, 1, 20, 49, 39) } ]; var BADENTRY = "unknown.txt"; @@ -70,10 +70,7 @@ function run_test() do_check_eq(entry.realSize, TESTS[i].size); do_check_eq(entry.CRC32, TESTS[i].crc); - var diff = Math.abs(TESTS[i].time - - (entry.lastModifiedTime / PR_USEC_PER_MSEC)); - if (diff > TIME_RESOLUTION) - do_throw(diff); + do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC, TESTS[i].time); } try { diff --git a/modules/libjar/zipwriter/test/unit/test_storedata.js b/modules/libjar/zipwriter/test/unit/test_storedata.js index 8d8fae11be7..0e845d52321 100644 --- a/modules/libjar/zipwriter/test/unit/test_storedata.js +++ b/modules/libjar/zipwriter/test/unit/test_storedata.js @@ -56,9 +56,7 @@ function testpass(source) // Should be stored do_check_eq(entry.compression, ZIP_METHOD_STORE); - var diff = Math.abs((entry.lastModifiedTime / PR_USEC_PER_MSEC) - time); - if (diff > TIME_RESOLUTION) - do_throw(diff); + do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC, time); // File size should match our data size. do_check_eq(entry.realSize, DATA.length); @@ -90,6 +88,7 @@ function run_test() do_check_eq(tmpFile.fileSize, DATA.length + ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + + (ZIP_EXTENDED_TIMESTAMP_SIZE * 2) + (FILENAME.length * 2) + ZIP_EOCDR_HEADER_SIZE); // Check to see if we get the same results loading afresh. diff --git a/modules/libjar/zipwriter/test/unit/test_sync.js b/modules/libjar/zipwriter/test/unit/test_sync.js index 4a6862e89ba..37f710c46ed 100644 --- a/modules/libjar/zipwriter/test/unit/test_sync.js +++ b/modules/libjar/zipwriter/test/unit/test_sync.js @@ -60,6 +60,7 @@ function run_test() zipW.addEntryFile(TESTS[i].name, Ci.nsIZipWriter.COMPRESSION_NONE, source, false); size += ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + + (ZIP_EXTENDED_TIMESTAMP_SIZE * 2) + (TESTS[i].name.length*2) + TESTS[i].size; } @@ -79,11 +80,8 @@ function run_test() do_check_eq(entry.realSize, TESTS[i].size); do_check_eq(entry.size, TESTS[i].size); do_check_eq(entry.CRC32, TESTS[i].crc); - - var diff = Math.abs((entry.lastModifiedTime/PR_USEC_PER_MSEC) - - source.lastModifiedTime); - if (diff > TIME_RESOLUTION) - do_throw(diff); + do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC, + source.lastModifiedTime); zipR.test(TESTS[i].name); }