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

This commit is contained in:
Michal Novotny 2009-12-16 00:01:08 +01:00
parent a090ac8577
commit a107124c97
19 changed files with 246 additions and 135 deletions

View File

@ -259,14 +259,9 @@ nsJAR::Extract(const char *zipEntry, nsIFile* outFile)
} }
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
PRTime prtime = GetModTime(item->Date(), item->Time());
// nsIFile needs milliseconds, while prtime is in microseconds. // 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 // non-fatal if this fails, ignore errors
outFile->SetLastModifiedTime(newTime); outFile->SetLastModifiedTime(item->LastModTime() / PR_USEC_PER_MSEC);
return NS_OK; return NS_OK;
} }
@ -933,8 +928,7 @@ nsJARItem::nsJARItem(nsZipItem* aZipItem)
: mSize(aZipItem->Size()), : mSize(aZipItem->Size()),
mRealsize(aZipItem->RealSize()), mRealsize(aZipItem->RealSize()),
mCrc32(aZipItem->CRC32()), mCrc32(aZipItem->CRC32()),
mDate(aZipItem->Date()), mLastModTime(aZipItem->LastModTime()),
mTime(aZipItem->Time()),
mCompression(aZipItem->Compression()), mCompression(aZipItem->Compression()),
mIsDirectory(aZipItem->IsDirectory()), mIsDirectory(aZipItem->IsDirectory()),
mIsSynthetic(aZipItem->isSynthetic) mIsSynthetic(aZipItem->isSynthetic)
@ -1021,7 +1015,7 @@ nsJARItem::GetLastModifiedTime(PRTime* aLastModTime)
{ {
NS_ENSURE_ARG_POINTER(aLastModTime); NS_ENSURE_ARG_POINTER(aLastModTime);
*aLastModTime = GetModTime(mDate, mTime); *aLastModTime = mLastModTime;
return NS_OK; return NS_OK;
} }
@ -1267,27 +1261,4 @@ nsZipReaderCache::Observe(nsISupports *aSubject,
return NS_OK; 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);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -85,8 +85,6 @@ typedef enum
JAR_NOT_SIGNED = 7 JAR_NOT_SIGNED = 7
} JARManifestStatusType; } JARManifestStatusType;
PRTime GetModTime(PRUint16 aDate, PRUint16 aTime);
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* Class nsJAR declaration. * Class nsJAR declaration.
* nsJAR serves as an XPCOM wrapper for nsZipArchive with the addition of * nsJAR serves as an XPCOM wrapper for nsZipArchive with the addition of
@ -184,8 +182,7 @@ private:
PRUint32 mSize; /* size in original file */ PRUint32 mSize; /* size in original file */
PRUint32 mRealsize; /* inflated size */ PRUint32 mRealsize; /* inflated size */
PRUint32 mCrc32; PRUint32 mCrc32;
PRUint16 mDate; PRTime mLastModTime;
PRUint16 mTime;
PRUint16 mCompression; PRUint16 mCompression;
PRPackedBool mIsDirectory; PRPackedBool mIsDirectory;
PRPackedBool mIsSynthetic; PRPackedBool mIsSynthetic;

View File

@ -346,7 +346,7 @@ nsJARInputStream::ReadDirectory(char* aBuffer, PRUint32 aCount, PRUint32 *aBytes
// Last Modified Time // Last Modified Time
PRExplodedTime tm; PRExplodedTime tm;
PR_ExplodeTime(GetModTime(ze->Date(), ze->Time()), PR_GMTParameters, &tm); PR_ExplodeTime(ze->LastModTime(), PR_GMTParameters, &tm);
char itemLastModTime[65]; char itemLastModTime[65];
PR_FormatTimeUSEnglish(itemLastModTime, PR_FormatTimeUSEnglish(itemLastModTime,
sizeof(itemLastModTime), sizeof(itemLastModTime),

View File

@ -104,8 +104,8 @@ static const PRUint32 kMaxNameLength = PATH_MAX; /* Maximum name length */
static const PRUint16 kSyntheticTime = 0; static const PRUint16 kSyntheticTime = 0;
static const PRUint16 kSyntheticDate = (1 + (1 << 5) + (0 << 9)); static const PRUint16 kSyntheticDate = (1 + (1 << 5) + (0 << 9));
static PRUint16 xtoint(const unsigned char *ii); static PRUint16 xtoint(const PRUint8 *ii);
static PRUint32 xtolong(const unsigned char *ll); static PRUint32 xtolong(const PRUint8 *ll);
static PRUint32 HashName(const char* aName, PRUint16 nameLen); static PRUint32 HashName(const char* aName, PRUint16 nameLen);
#if defined(XP_UNIX) || defined(XP_BEOS) #if defined(XP_UNIX) || defined(XP_BEOS)
static nsresult ResolveSymlink(const char *path); 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 * Converts a two byte ugly endianed integer
* to our platform's 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)); 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 * Converts a four byte ugly endianed integer
* to our platform's integer. * to our platform's integer.
*/ */
static PRUint32 xtolong (const unsigned char *ll) static PRUint32 xtolong (const PRUint8 *ll)
{ {
return (PRUint32)( (ll [0] << 0) | return (PRUint32)( (ll [0] << 0) |
(ll [1] << 8) | (ll [1] << 8) |
@ -867,56 +867,129 @@ static PRUint32 xtolong (const unsigned char *ll)
(ll [3] << 24) ); (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); return xtolong(central->localhdr_offset);
} }
PRUint32 const nsZipItem::Size() PRUint32 nsZipItem::Size()
{ {
return isSynthetic ? 0 : xtolong(central->size); return isSynthetic ? 0 : xtolong(central->size);
} }
PRUint32 const nsZipItem::RealSize() PRUint32 nsZipItem::RealSize()
{ {
return isSynthetic ? 0 : xtolong(central->orglen); return isSynthetic ? 0 : xtolong(central->orglen);
} }
PRUint32 const nsZipItem::CRC32() PRUint32 nsZipItem::CRC32()
{ {
return isSynthetic ? 0 : xtolong(central->crc32); return isSynthetic ? 0 : xtolong(central->crc32);
} }
PRUint16 const nsZipItem::Date() PRUint16 nsZipItem::Date()
{ {
return isSynthetic ? kSyntheticDate : xtoint(central->date); return isSynthetic ? kSyntheticDate : xtoint(central->date);
} }
PRUint16 const nsZipItem::Time() PRUint16 nsZipItem::Time()
{ {
return isSynthetic ? kSyntheticTime : xtoint(central->time); return isSynthetic ? kSyntheticTime : xtoint(central->time);
} }
PRUint16 const nsZipItem::Compression() PRUint16 nsZipItem::Compression()
{ {
return isSynthetic ? STORED : xtoint(central->method); return isSynthetic ? STORED : xtoint(central->method);
} }
bool const nsZipItem::IsDirectory() bool nsZipItem::IsDirectory()
{ {
return isSynthetic || ((nameLength > 0) && ('/' == Name()[nameLength - 1])); return isSynthetic || ((nameLength > 0) && ('/' == Name()[nameLength - 1]));
} }
PRUint16 const nsZipItem::Mode() PRUint16 nsZipItem::Mode()
{ {
if (isSynthetic) return 0755; if (isSynthetic) return 0755;
return ((PRUint16)(central->external_attributes[2]) | 0x100); 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) #if defined(XP_UNIX) || defined(XP_BEOS)
bool const nsZipItem::IsSymlink() bool nsZipItem::IsSymlink()
{ {
if (isSynthetic) return false; if (isSynthetic) return false;
return (xtoint(central->external_attributes+2) & S_IFMT) == S_IFLNK; return (xtoint(central->external_attributes+2) & S_IFMT) == S_IFLNK;
} }
#endif #endif

View File

@ -83,18 +83,20 @@ class nsZipItem
public: public:
const char* Name() { return ((const char*)central) + ZIPCENTRAL_SIZE; } const char* Name() { return ((const char*)central) + ZIPCENTRAL_SIZE; }
PRUint32 const LocalOffset(); PRUint32 LocalOffset();
PRUint32 const Size(); PRUint32 Size();
PRUint32 const RealSize(); PRUint32 RealSize();
PRUint32 const CRC32(); PRUint32 CRC32();
PRUint16 const Date(); PRUint16 Date();
PRUint16 const Time(); PRUint16 Time();
PRUint16 const Compression(); PRUint16 Compression();
bool const IsDirectory(); bool IsDirectory();
PRUint16 const Mode(); PRUint16 Mode();
const PRUint8* GetExtraField(PRUint16 aTag, PRUint16 *aBlockSize);
PRTime LastModTime();
#if defined(XP_UNIX) || defined(XP_BEOS) #if defined(XP_UNIX) || defined(XP_BEOS)
bool const IsSymlink(); bool IsSymlink();
#endif #endif
nsZipItem* next; nsZipItem* next;

View File

@ -7,8 +7,8 @@ const path = "data/test_bug379841.zip";
const MAX_TIME_DIFF = 2000000; const MAX_TIME_DIFF = 2000000;
var ENTRY_NAME = "test"; var ENTRY_NAME = "test";
// Actual time of file was 07 May 2007 14:35:49 // Actual time of file was 07 May 2007 13:35:49 UTC
var ENTRY_TIME = new Date(2007, 4, 7, 14, 35, 49, 0); var ENTRY_TIME = new Date(Date.UTC(2007, 4, 7, 13, 35, 49, 0));
function run_test() { function run_test() {
var file = do_get_file(path); var file = do_get_file(path);

View File

@ -122,6 +122,10 @@ typedef struct ZipEnd_
#define CENTRALSIG 0x02014B50l #define CENTRALSIG 0x02014B50l
#define ENDSIG 0x06054B50l #define ENDSIG 0x06054B50l
/* extra fields */
#define EXTENDED_TIMESTAMP_FIELD 0x5455
#define EXTENDED_TIMESTAMP_MODTIME 0x01
/* compression methods */ /* compression methods */
#define STORED 0 #define STORED 0
#define SHRUNK 1 #define SHRUNK 1

View File

@ -50,47 +50,43 @@
* The off argument, where present, is incremented according to the number of * The off argument, where present, is incremented according to the number of
* bytes consumed from the buffer. * 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; WRITE8(buf, off, val & 0xff);
buf[(*off)++] = (val >> 8) & 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; WRITE16(buf, off, val & 0xffff);
buf[(*off)++] = (val >> 8) & 0xff; WRITE16(buf, off, (val >> 16) & 0xffff);
buf[(*off)++] = (val >> 16) & 0xff;
buf[(*off)++] = (val >> 24) & 0xff;
} }
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; PRUint16 val = READ8(buf, off);
val |= ((PRUint16)buf[(*off)++] & 0xff) << 8; val |= READ8(buf, off) << 8;
return val; 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; PRUint32 val = READ16(buf, off);
val |= ((PRUint32)buf[(*off)++] & 0xff) << 8; val |= READ16(buf, off) << 16;
val |= ((PRUint32)buf[(*off)++] & 0xff) << 16;
val |= ((PRUint32)buf[(*off)++] & 0xff) << 24;
return val; return val;
} }
inline NS_HIDDEN_(PRUint32) PEEK32(unsigned char *buf) inline NS_HIDDEN_(PRUint32) PEEK32(const PRUint8* buf)
{ {
return (PRUint32)( (buf [0] ) | return (PRUint32)( (buf [0] ) |
(buf [1] << 8) | (buf [1] << 8) |

View File

@ -47,6 +47,9 @@
#define FLAGS_IS_UTF8 0x800 #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. * nsZipHeader represents an entry from a zip file.
*/ */
@ -105,11 +108,28 @@ NS_IMETHODIMP nsZipHeader::GetLastModifiedTime(PRTime *aLastModifiedTime)
{ {
NS_ASSERTION(mInited, "Not initalised"); 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; PRExplodedTime time;
time.tm_usec = 0; time.tm_usec = 0;
time.tm_hour = mTime >> 11; time.tm_hour = (mTime >> 11) & 0x1F;
time.tm_min = (mTime >> 5) & 0x3F; time.tm_min = (mTime >> 5) & 0x3F;
time.tm_sec = (mTime & 0x1F) * 2; time.tm_sec = (mTime & 0x1F) * 2;
@ -121,7 +141,9 @@ NS_IMETHODIMP nsZipHeader::GetLastModifiedTime(PRTime *aLastModifiedTime)
time.tm_params.tp_dst_offset = 0; time.tm_params.tp_dst_offset = 0;
PR_NormalizeTime(&time, PR_GMTParameters); 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); *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) + mDate = time.tm_mday + ((time.tm_month + 1) << 5) +
((time.tm_year - 1980) << 9); ((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; mEAttr = aAttr;
mOffset = aOffset; mOffset = aOffset;
mName = aPath; mName = aPath;
@ -160,14 +203,14 @@ void nsZipHeader::Init(const nsACString & aPath, PRTime aDate, PRUint32 aAttr,
PRUint32 nsZipHeader::GetFileHeaderLength() PRUint32 nsZipHeader::GetFileHeaderLength()
{ {
return ZIP_FILE_HEADER_SIZE + mName.Length(); return ZIP_FILE_HEADER_SIZE + mName.Length() + mLocalFieldLength;
} }
nsresult nsZipHeader::WriteFileHeader(nsIOutputStream *aStream) nsresult nsZipHeader::WriteFileHeader(nsIOutputStream *aStream)
{ {
NS_ASSERTION(mInited, "Not initalised"); NS_ASSERTION(mInited, "Not initalised");
char buf[ZIP_FILE_HEADER_SIZE]; PRUint8 buf[ZIP_FILE_HEADER_SIZE];
PRUint32 pos = 0; PRUint32 pos = 0;
WRITE32(buf, &pos, ZIP_FILE_HEADER_SIGNATURE); WRITE32(buf, &pos, ZIP_FILE_HEADER_SIGNATURE);
WRITE16(buf, &pos, mVersionNeeded); WRITE16(buf, &pos, mVersionNeeded);
@ -179,12 +222,21 @@ nsresult nsZipHeader::WriteFileHeader(nsIOutputStream *aStream)
WRITE32(buf, &pos, mCSize); WRITE32(buf, &pos, mCSize);
WRITE32(buf, &pos, mUSize); WRITE32(buf, &pos, mUSize);
WRITE16(buf, &pos, mName.Length()); 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); 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() PRUint32 nsZipHeader::GetCDSHeaderLength()
@ -197,7 +249,7 @@ nsresult nsZipHeader::WriteCDSHeader(nsIOutputStream *aStream)
{ {
NS_ASSERTION(mInited, "Not initalised"); NS_ASSERTION(mInited, "Not initalised");
char buf[ZIP_CDS_HEADER_SIZE]; PRUint8 buf[ZIP_CDS_HEADER_SIZE];
PRUint32 pos = 0; PRUint32 pos = 0;
WRITE32(buf, &pos, ZIP_CDS_HEADER_SIGNATURE); WRITE32(buf, &pos, ZIP_CDS_HEADER_SIGNATURE);
WRITE16(buf, &pos, mVersionMade); WRITE16(buf, &pos, mVersionMade);
@ -217,13 +269,13 @@ nsresult nsZipHeader::WriteCDSHeader(nsIOutputStream *aStream)
WRITE32(buf, &pos, mEAttr); WRITE32(buf, &pos, mEAttr);
WRITE32(buf, &pos, mOffset); 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); NS_ENSURE_SUCCESS(rv, rv);
rv = ZW_WriteData(aStream, mName.get(), mName.Length()); rv = ZW_WriteData(aStream, mName.get(), mName.Length());
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (mExtraField) { if (mExtraField) {
rv = ZW_WriteData(aStream, mExtraField, mFieldLength); rv = ZW_WriteData(aStream, (const char *)mExtraField.get(), mFieldLength);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
return ZW_WriteData(aStream, mComment.get(), mComment.Length()); return ZW_WriteData(aStream, mComment.get(), mComment.Length());
@ -233,9 +285,9 @@ nsresult nsZipHeader::ReadCDSHeader(nsIInputStream *stream)
{ {
NS_ASSERTION(!mInited, "Already initalised"); 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); NS_ENSURE_SUCCESS(rv, rv);
PRUint32 pos = 0; PRUint32 pos = 0;
@ -271,9 +323,9 @@ nsresult nsZipHeader::ReadCDSHeader(nsIInputStream *stream)
mName = NS_LITERAL_CSTRING(""); mName = NS_LITERAL_CSTRING("");
if (mFieldLength > 0) { if (mFieldLength > 0) {
mExtraField = new char[mFieldLength]; mExtraField = new PRUint8[mFieldLength];
NS_ENSURE_TRUE(mExtraField, NS_ERROR_OUT_OF_MEMORY); 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); NS_ENSURE_SUCCESS(rv, rv);
} }
@ -290,3 +342,25 @@ nsresult nsZipHeader::ReadCDSHeader(nsIInputStream *stream)
mInited = PR_TRUE; mInited = PR_TRUE;
return NS_OK; 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;
}

View File

@ -68,6 +68,7 @@ public:
mEAttr(0), mEAttr(0),
mOffset(0), mOffset(0),
mFieldLength(0), mFieldLength(0),
mLocalFieldLength(0),
mVersionMade(0x0300 + 23), // Generated on Unix by v2.3 (matches infozip) mVersionMade(0x0300 + 23), // Generated on Unix by v2.3 (matches infozip)
mVersionNeeded(20), // Requires v2.0 to extract mVersionNeeded(20), // Requires v2.0 to extract
mFlags(0), mFlags(0),
@ -77,13 +78,15 @@ public:
mDisk(0), mDisk(0),
mIAttr(0), mIAttr(0),
mInited(PR_FALSE), mInited(PR_FALSE),
mExtraField(NULL) mExtraField(NULL),
mLocalExtraField(NULL)
{ {
} }
~nsZipHeader() ~nsZipHeader()
{ {
mExtraField = NULL; mExtraField = NULL;
mLocalExtraField = NULL;
} }
PRUint32 mCRC; PRUint32 mCRC;
@ -92,6 +95,7 @@ public:
PRUint32 mEAttr; PRUint32 mEAttr;
PRUint32 mOffset; PRUint32 mOffset;
PRUint32 mFieldLength; PRUint32 mFieldLength;
PRUint32 mLocalFieldLength;
PRUint16 mVersionMade; PRUint16 mVersionMade;
PRUint16 mVersionNeeded; PRUint16 mVersionNeeded;
PRUint16 mFlags; PRUint16 mFlags;
@ -103,7 +107,8 @@ public:
PRPackedBool mInited; PRPackedBool mInited;
nsCString mName; nsCString mName;
nsCString mComment; nsCString mComment;
nsAutoArrayPtr<char> mExtraField; nsAutoArrayPtr<PRUint8> mExtraField;
nsAutoArrayPtr<PRUint8> mLocalExtraField;
void Init(const nsACString & aPath, PRTime aDate, PRUint32 aAttr, void Init(const nsACString & aPath, PRTime aDate, PRUint32 aAttr,
PRUint32 aOffset); PRUint32 aOffset);
@ -112,6 +117,7 @@ public:
PRUint32 GetCDSHeaderLength(); PRUint32 GetCDSHeaderLength();
nsresult WriteCDSHeader(nsIOutputStream *aStream); nsresult WriteCDSHeader(nsIOutputStream *aStream);
nsresult ReadCDSHeader(nsIInputStream *aStream); nsresult ReadCDSHeader(nsIInputStream *aStream);
const PRUint8 * GetExtraField(PRUint16 aTag, PRBool aLocal, PRUint16 *aBlockSize);
}; };
#endif #endif

View File

@ -147,7 +147,7 @@ nsresult nsZipWriter::ReadFile(nsIFile *aFile)
rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), aFile); rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), aFile);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
char buf[1024]; PRUint8 buf[1024];
PRInt64 seek = size - 1024; PRInt64 seek = size - 1024;
PRUint32 length = 1024; PRUint32 length = 1024;
@ -164,7 +164,7 @@ nsresult nsZipWriter::ReadFile(nsIFile *aFile)
inputStream->Close(); inputStream->Close();
return rv; return rv;
} }
rv = ZW_ReadData(inputStream, buf, length); rv = ZW_ReadData(inputStream, (char *)buf, length);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
inputStream->Close(); inputStream->Close();
return rv; return rv;
@ -177,7 +177,7 @@ nsresult nsZipWriter::ReadFile(nsIFile *aFile)
// We know it's at least this far from the end // We know it's at least this far from the end
for (PRUint32 pos = length - ZIP_EOCDR_HEADER_SIZE; for (PRUint32 pos = length - ZIP_EOCDR_HEADER_SIZE;
(PRInt32)pos >= 0; pos--) { (PRInt32)pos >= 0; pos--) {
PRUint32 sig = PEEK32((unsigned char *)buf + pos); PRUint32 sig = PEEK32(buf + pos);
if (sig == ZIP_EOCDR_HEADER_SIGNATURE) { if (sig == ZIP_EOCDR_HEADER_SIGNATURE) {
// Skip down to entry count // Skip down to entry count
pos += 10; pos += 10;
@ -190,7 +190,7 @@ nsresult nsZipWriter::ReadFile(nsIFile *aFile)
if (commentlen == 0) if (commentlen == 0)
mComment.Truncate(); mComment.Truncate();
else if (pos + commentlen <= length) else if (pos + commentlen <= length)
mComment.Assign(buf + pos, commentlen); mComment.Assign((const char *)buf + pos, commentlen);
else { else {
if ((seek + pos + commentlen) > size) { if ((seek + pos + commentlen) > size) {
inputStream->Close(); inputStream->Close();
@ -682,7 +682,7 @@ NS_IMETHODIMP nsZipWriter::Close()
size += mHeaders[i]->GetCDSHeaderLength(); size += mHeaders[i]->GetCDSHeaderLength();
} }
char buf[ZIP_EOCDR_HEADER_SIZE]; PRUint8 buf[ZIP_EOCDR_HEADER_SIZE];
PRUint32 pos = 0; PRUint32 pos = 0;
WRITE32(buf, &pos, ZIP_EOCDR_HEADER_SIGNATURE); WRITE32(buf, &pos, ZIP_EOCDR_HEADER_SIGNATURE);
WRITE16(buf, &pos, 0); WRITE16(buf, &pos, 0);
@ -693,7 +693,7 @@ NS_IMETHODIMP nsZipWriter::Close()
WRITE32(buf, &pos, mCDSOffset); WRITE32(buf, &pos, mCDSOffset);
WRITE16(buf, &pos, mComment.Length()); 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)) { if (NS_FAILED(rv)) {
Cleanup(); Cleanup();
return rv; return rv;

View File

@ -55,12 +55,10 @@ const ZIP_FILE_HEADER_SIZE = 30;
const ZIP_CDS_HEADER_SIZE = 46; const ZIP_CDS_HEADER_SIZE = 46;
const ZIP_METHOD_STORE = 0 const ZIP_METHOD_STORE = 0
const ZIP_METHOD_DEFLATE = 8 const ZIP_METHOD_DEFLATE = 8
const ZIP_EXTENDED_TIMESTAMP_SIZE = 9;
const PR_USEC_PER_MSEC = 1000; const PR_USEC_PER_MSEC = 1000;
// ZIP times are stored at a 2 second resolution.
const TIME_RESOLUTION = 2000;
const DATA_DIR = "data/"; const DATA_DIR = "data/";
var ZipWriter = Components.Constructor("@mozilla.org/zipwriter;1", var ZipWriter = Components.Constructor("@mozilla.org/zipwriter;1",

View File

@ -77,11 +77,8 @@ var observer = {
do_check_eq(entry.realSize, TESTS[i].size); do_check_eq(entry.realSize, TESTS[i].size);
do_check_eq(entry.size, TESTS[i].size); do_check_eq(entry.size, TESTS[i].size);
do_check_eq(entry.CRC32, TESTS[i].crc); do_check_eq(entry.CRC32, TESTS[i].crc);
do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC,
var diff = Math.abs((entry.lastModifiedTime/PR_USEC_PER_MSEC) -
source.lastModifiedTime); source.lastModifiedTime);
if (diff > TIME_RESOLUTION)
do_throw(diff);
zipR.test(TESTS[i].name); zipR.test(TESTS[i].name);
} }
@ -100,6 +97,7 @@ function run_test()
zipW.addEntryFile(TESTS[i].name, Ci.nsIZipWriter.COMPRESSION_NONE, source, zipW.addEntryFile(TESTS[i].name, Ci.nsIZipWriter.COMPRESSION_NONE, source,
true); true);
size += ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + size += ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE +
(ZIP_EXTENDED_TIMESTAMP_SIZE * 2) +
(TESTS[i].name.length*2) + TESTS[i].size; (TESTS[i].name.length*2) + TESTS[i].size;
} }
do_test_pending(); do_test_pending();

View File

@ -55,9 +55,7 @@ function testpass(source)
// Should be stored // Should be stored
do_check_eq(entry.compression, ZIP_METHOD_DEFLATE); do_check_eq(entry.compression, ZIP_METHOD_DEFLATE);
var diff = Math.abs((entry.lastModifiedTime / PR_USEC_PER_MSEC) - time); do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC, time);
if (diff > TIME_RESOLUTION)
do_throw(diff);
// File size should match our data size. // File size should match our data size.
do_check_eq(entry.realSize, DATA.length); do_check_eq(entry.realSize, DATA.length);

View File

@ -57,6 +57,8 @@ function run_test()
// Adding the directory would have added a fixed amount to the file size. // Adding the directory would have added a fixed amount to the file size.
// Any difference suggests the CDS was written out incorrectly. // 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); do_check_eq(source.fileSize + extra, tmpFile.fileSize);
} }

View File

@ -65,9 +65,7 @@ function run_test()
do_check_eq(entry.compression, ZIP_METHOD_DEFLATE); do_check_eq(entry.compression, ZIP_METHOD_DEFLATE);
do_check_eq(entry.CRC32, CRC); do_check_eq(entry.CRC32, CRC);
do_check_eq(entry.realSize, DATA.length); do_check_eq(entry.realSize, DATA.length);
var diff = Math.abs((entry.lastModifiedTime/PR_USEC_PER_MSEC) - time); do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC, time);
if (diff > TIME_RESOLUTION)
do_throw(diff);
zipW.close(); zipW.close();

View File

@ -42,13 +42,13 @@ var TESTS = [
name: "test.txt", name: "test.txt",
size: 232, size: 232,
crc: 0x0373ac26, crc: 0x0373ac26,
time: new Date(2007, 4, 1, 21, 44, 56) time: Date.UTC(2007, 4, 1, 20, 44, 55)
}, },
{ {
name: "test.png", name: "test.png",
size: 3402, size: 3402,
crc: 0x504a5c30, crc: 0x504a5c30,
time: new Date(2007, 4, 1, 21, 49, 40) time: Date.UTC(2007, 4, 1, 20, 49, 39)
} }
]; ];
var BADENTRY = "unknown.txt"; var BADENTRY = "unknown.txt";
@ -70,10 +70,7 @@ function run_test()
do_check_eq(entry.realSize, TESTS[i].size); do_check_eq(entry.realSize, TESTS[i].size);
do_check_eq(entry.CRC32, TESTS[i].crc); do_check_eq(entry.CRC32, TESTS[i].crc);
var diff = Math.abs(TESTS[i].time - do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC, TESTS[i].time);
(entry.lastModifiedTime / PR_USEC_PER_MSEC));
if (diff > TIME_RESOLUTION)
do_throw(diff);
} }
try { try {

View File

@ -56,9 +56,7 @@ function testpass(source)
// Should be stored // Should be stored
do_check_eq(entry.compression, ZIP_METHOD_STORE); do_check_eq(entry.compression, ZIP_METHOD_STORE);
var diff = Math.abs((entry.lastModifiedTime / PR_USEC_PER_MSEC) - time); do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC, time);
if (diff > TIME_RESOLUTION)
do_throw(diff);
// File size should match our data size. // File size should match our data size.
do_check_eq(entry.realSize, DATA.length); do_check_eq(entry.realSize, DATA.length);
@ -90,6 +88,7 @@ function run_test()
do_check_eq(tmpFile.fileSize, do_check_eq(tmpFile.fileSize,
DATA.length + ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + DATA.length + ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE +
(ZIP_EXTENDED_TIMESTAMP_SIZE * 2) +
(FILENAME.length * 2) + ZIP_EOCDR_HEADER_SIZE); (FILENAME.length * 2) + ZIP_EOCDR_HEADER_SIZE);
// Check to see if we get the same results loading afresh. // Check to see if we get the same results loading afresh.

View File

@ -60,6 +60,7 @@ function run_test()
zipW.addEntryFile(TESTS[i].name, Ci.nsIZipWriter.COMPRESSION_NONE, source, zipW.addEntryFile(TESTS[i].name, Ci.nsIZipWriter.COMPRESSION_NONE, source,
false); false);
size += ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + size += ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE +
(ZIP_EXTENDED_TIMESTAMP_SIZE * 2) +
(TESTS[i].name.length*2) + TESTS[i].size; (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.realSize, TESTS[i].size);
do_check_eq(entry.size, TESTS[i].size); do_check_eq(entry.size, TESTS[i].size);
do_check_eq(entry.CRC32, TESTS[i].crc); do_check_eq(entry.CRC32, TESTS[i].crc);
do_check_eq(entry.lastModifiedTime / PR_USEC_PER_MSEC,
var diff = Math.abs((entry.lastModifiedTime/PR_USEC_PER_MSEC) -
source.lastModifiedTime); source.lastModifiedTime);
if (diff > TIME_RESOLUTION)
do_throw(diff);
zipR.test(TESTS[i].name); zipR.test(TESTS[i].name);
} }