diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index 11ba314c9c4d..db69e1e5eeae 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -148,6 +148,7 @@ MOZ_PLACES_BOOKMARKS = @MOZ_PLACES_BOOKMARKS@ MOZ_STORAGE = @MOZ_STORAGE@ MOZ_SAFE_BROWSING = @MOZ_SAFE_BROWSING@ MOZ_URL_CLASSIFIER = @MOZ_URL_CLASSIFIER@ +MOZ_ZIPWRITER = @MOZ_ZIPWRITER@ MOZ_MORK = @MOZ_MORK@ MOZ_MORKREADER = @MOZ_MORKREADER@ MOZ_NO_XPCOM_OBSOLETE = @MOZ_NO_XPCOM_OBSOLETE@ diff --git a/configure.in b/configure.in index 6103aee4143c..f11e35b30d74 100644 --- a/configure.in +++ b/configure.in @@ -4164,6 +4164,7 @@ MOZ_XSLT_STANDALONE= MOZ_XTF=1 MOZ_XUL=1 MOZ_XUL_APP=1 +MOZ_ZIPWRITER=1 NS_PRINTING=1 NECKO_COOKIES=1 NECKO_DISK_CACHE=1 @@ -4281,6 +4282,7 @@ basic) MOZ_XPFE_COMPONENTS= MOZ_XPINSTALL= MOZ_XTF= + MOZ_ZIPWRITER= NECKO_DISK_CACHE= NECKO_PROTOCOLS_DEFAULT="about data http file res" NECKO_SMALL_BUFFERS=1 @@ -4331,6 +4333,7 @@ minimal) MOZ_XPINSTALL= MOZ_XTF= MOZ_XUL= + MOZ_ZIPWRITER= MOZ_RDF= NECKO_DISK_CACHE= NECKO_PROTOCOLS_DEFAULT="about data http file res" @@ -5903,6 +5906,15 @@ if test -n "$MOZ_URL_CLASSIFIER"; then fi AC_SUBST(MOZ_URL_CLASSIFIER) +dnl ======================================================== +dnl = Disable zipwriter +dnl ======================================================== +MOZ_ARG_DISABLE_BOOL(zipwriter, +[ --disable-zipwriter Disable zipwriter component], + MOZ_ZIPWRITER=, + MOZ_ZIPWRITER=1 ) +AC_SUBST(MOZ_ZIPWRITER) + dnl ======================================================== dnl = Enable Ultrasparc specific optimizations for JS dnl ======================================================== diff --git a/modules/libjar/Makefile.in b/modules/libjar/Makefile.in index 69ee7dd38781..1245ea34cf69 100644 --- a/modules/libjar/Makefile.in +++ b/modules/libjar/Makefile.in @@ -44,9 +44,15 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk include $(srcdir)/objs.mk +DIRS = + +ifdef MOZ_ZIPWRITER +DIRS += zipwriter +endif + ifdef MOZ_INSTALLER # Linux and Solaris installer needs standalone libjar -DIRS = standalone +DIRS += standalone # Make this a true dynamic component even in static builds because # this component is shared by installer diff --git a/modules/libjar/zipwriter/Makefile.in b/modules/libjar/zipwriter/Makefile.in new file mode 100644 index 000000000000..ec852fd20126 --- /dev/null +++ b/modules/libjar/zipwriter/Makefile.in @@ -0,0 +1,53 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Zip Writer Component. +# +# The Initial Developer of the Original Code is +# Dave Townsend . +# +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = zipwriter + +DIRS = public src + +ifdef ENABLE_TESTS +DIRS += test +endif + +include $(topsrcdir)/config/rules.mk diff --git a/modules/libjar/zipwriter/public/Makefile.in b/modules/libjar/zipwriter/public/Makefile.in new file mode 100644 index 000000000000..f3c87f334449 --- /dev/null +++ b/modules/libjar/zipwriter/public/Makefile.in @@ -0,0 +1,51 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Zip Writer Component. +# +# The Initial Developer of the Original Code is +# Dave Townsend . +# +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = zipwriter + +XPIDLSRCS = \ + nsIZipWriter.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/modules/libjar/zipwriter/public/nsIZipWriter.idl b/modules/libjar/zipwriter/public/nsIZipWriter.idl new file mode 100644 index 000000000000..28c1cd943012 --- /dev/null +++ b/modules/libjar/zipwriter/public/nsIZipWriter.idl @@ -0,0 +1,242 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include "nsISupports.idl" +interface nsIChannel; +interface nsIInputStream; +interface nsIRequestObserver; +interface nsIFile; +interface nsIZipEntry; + +/** + * nsIZipWriter + * + * An interface for a zip archiver that can be used from script. + * + * The interface supports both a synchronous method of archiving data and a + * queueing system to allow operations to be prepared then run in sequence + * with notification after completion. + * + * Operations added to the queue do not get performed until performQueue is + * called at which point they will be performed in the order that they were + * added to the queue. + * + * Operations performed on the queue will throw any errors out to the + * observer. + * + * An attempt to perform a synchronous operation while the background queue + * is in progress will throw NS_ERROR_IN_PROGRESS. + * + * Entry names should use /'s as path separators and should not start with + * a /. + * + * It is not generally necessary to add directory entries in order to add file + * entries within them, however it is possible that some zip programs may + * experience problems what that. + */ +[scriptable, uuid(6d4ef074-206c-4649-9884-57bc355864d6)] +interface nsIZipWriter : nsISupports +{ + /** + * Some predefined compression levels + */ + const PRUint32 COMPRESSION_NONE = 0; + const PRUint32 COMPRESSION_FASTEST = 1; + const PRUint32 COMPRESSION_DEFAULT = 6; + const PRUint32 COMPRESSION_BEST = 9; + + /** + * Gets or sets the comment associated with the open zip file. + * + * @throws NS_ERROR_NOT_INITIALIZED if no zip file has been opened + */ + attribute ACString comment; + + /** + * Indicates that operations on the background queue are being performed. + */ + readonly attribute boolean inQueue; + + /** + * The file that the zipwriter is writing to. + */ + readonly attribute nsIFile file; + + /** + * Opens a zip file. + * + * @param aFile the zip file to open + * @param aIoFlags the open flags for the zip file from prio.h + * + * @throws NS_ERROR_ALREADY_INITIALIZED if a zip file is already open + * @throws NS_ERROR_INVALID_ARG if aFile is null + * @throws NS_ERROR_FILE_NOT_FOUND if aFile does not exist and flags did + * not allow for creation + * @throws NS_ERROR_FILE_CORRUPTED if the file does not contain zip markers + * @throws on failure to open zip file (most likely corrupt + * or unsupported form) + */ + void open(in nsIFile aFile, in PRInt32 aIoFlags); + + /** + * Returns a nsIZipEntry describing a specified zip entry or null if there + * is no such entry in the zip file + * + * @param aZipEntry the path of the entry + */ + nsIZipEntry getEntry(in AUTF8String aZipEntry); + + /** + * Checks whether the zipfile contains an entry specified by zipEntry. + * + * @param aZipEntry the path of the entry + */ + boolean hasEntry(in AUTF8String aZipEntry); + + /** + * Adds a new directory entry to the zip file. If aZipEntry does not end with + * "/" then it will be added. + * + * @param aZipEntry the path of the directory entry + * @param aModTime the modification time of the entry in microseconds + * @param aQueue adds the operation to the background queue. Will be + * performed when processQueue is called. + * + * @throws NS_ERROR_NOT_INITIALIZED if no zip file has been opened + * @throws NS_ERROR_FILE_ALREADY_EXISTS if the path already exists in the + * file + * @throws NS_ERROR_IN_PROGRESS if another operation is currently in progress + */ + void addEntryDirectory(in AUTF8String aZipEntry, in PRTime aModTime, + in boolean aQueue); + + /** + * Adds a new file or directory to the zip file. If the specified file is + * a directory then this will be equivalent to a call to + * addEntryDirectory(aZipEntry, aFile.lastModifiedTime, aQueue) + * + * @param aZipEntry the path of the file entry + * @param aCompression the compression level, 0 is no compression, 9 is best + * @param aFile the file to get the data and modification time from + * @param aQueue adds the operation to the background queue. Will be + * performed when processQueue is called. + * + * @throws NS_ERROR_NOT_INITIALIZED if no zip file has been opened + * @throws NS_ERROR_FILE_ALREADY_EXISTS if the path already exists in the zip + * @throws NS_ERROR_IN_PROGRESS if another operation is currently in progress + * @throws NS_ERROR_FILE_NOT_FOUND if file does not exist + */ + void addEntryFile(in AUTF8String aZipEntry, + in PRInt32 aCompression, in nsIFile aFile, + in boolean aQueue); + + /** + * Adds data from a channel to the zip file. If the operation is performed + * on the queue then the channel will be opened asynchronously, otherwise + * the channel must support being opened synchronously. + * + * @param aZipEntry the path of the file entry + * @param aModTime the modification time of the entry in microseconds + * @param aCompression the compression level, 0 is no compression, 9 is best + * @param aChannel the channel to get the data from + * @param aQueue adds the operation to the background queue. Will be + * performed when processQueue is called. + * + * @throws NS_ERROR_NOT_INITIALIZED if no zip file has been opened + * @throws NS_ERROR_FILE_ALREADY_EXISTS if the path already exists in the zip + * @throws NS_ERROR_IN_PROGRESS if another operation is currently in progress + */ + void addEntryChannel(in AUTF8String aZipEntry, in PRTime aModTime, + in PRInt32 aCompression, in nsIChannel aChannel, + in boolean aQueue); + + /** + * Adds data from an input stream to the zip file. + * + * @param aZipEntry the path of the file entry + * @param aModTime the modification time of the entry in microseconds + * @param aCompression the compression level, 0 is no compression, 9 is best + * @param aStream the input stream to get the data from + * @param aQueue adds the operation to the background queue. Will be + * performed when processQueue is called. + * + * @throws NS_ERROR_NOT_INITIALIZED if no zip file has been opened + * @throws NS_ERROR_FILE_ALREADY_EXISTS if the path already exists in the zip + * @throws NS_ERROR_IN_PROGRESS if another operation is currently in progress + */ + void addEntryStream(in AUTF8String aZipEntry, in PRTime aModTime, + in PRInt32 aCompression, in nsIInputStream aStream, + in boolean aQueue); + + /** + * Removes an existing entry from the zip file. + * + * @param aZipEntry the path of the entry to be removed + * @param aQueue adds the operation to the background queue. Will be + * performed when processQueue is called. + * + * @throws NS_ERROR_NOT_INITIALIZED if no zip file has been opened + * @throws NS_ERROR_IN_PROGRESS if another operation is currently in progress + * @throws NS_ERROR_FILE_NOT_FOUND if no entry with the given path exists + * @throws on failure to update the zip file + */ + void removeEntry(in AUTF8String aZipEntry, in boolean aQueue); + + /** + * Processes all queued items until complete or some error occurs. The + * observer will be notified when the first operation starts and when the + * last operation completes. Any failures will be passed to the observer. + * The zip writer will be busy until the queue is complete or some error + * halted processing of the queue early. In the event of an early failure, + * remaining items will stay in the queue and calling processQueue will + * continue. + * + * @throws NS_ERROR_NOT_INITIALIZED if no zip file has been opened + * @throws NS_ERROR_IN_PROGRESS if the queue is already in progress + */ + void processQueue(in nsIRequestObserver aObserver, in nsISupports aContext); + + /** + * Closes the zip file. + * + * @throws NS_ERROR_NOT_INITIALIZED if no zip file has been opened + * @throws NS_ERROR_IN_PROGRESS if another operation is currently in progress + * @throws on failure to complete the zip file + */ + void close(); +}; diff --git a/modules/libjar/zipwriter/src/Makefile.in b/modules/libjar/zipwriter/src/Makefile.in new file mode 100644 index 000000000000..0ab79a6b3c03 --- /dev/null +++ b/modules/libjar/zipwriter/src/Makefile.in @@ -0,0 +1,74 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Zip Writer Component. +# +# The Initial Developer of the Original Code is +# Dave Townsend . +# +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = zipwriter +LIBRARY_NAME = zipwriter +MODULE_NAME = ZipWriterModule +EXPORT_LIBRARY = 1 +LIBXUL_LIBRARY = 1 +IS_COMPONENT = 1 + +REQUIRES = \ + xpcom \ + string \ + necko \ + jar \ + $(ZLIB_REQUIRES) \ + $(NULL) + +CPPSRCS = \ + StreamFunctions.cpp \ + nsDeflateConverter.cpp \ + nsZipHeader.cpp \ + nsZipDataStream.cpp \ + nsZipWriter.cpp \ + ZipWriterModule.cpp \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +EXTRA_DSO_LDOPTS += \ + $(MOZ_COMPONENT_LIBS) \ + $(ZLIB_LIBS) \ + $(NULL) diff --git a/modules/libjar/zipwriter/src/StreamFunctions.cpp b/modules/libjar/zipwriter/src/StreamFunctions.cpp new file mode 100644 index 000000000000..ad0456b65bf1 --- /dev/null +++ b/modules/libjar/zipwriter/src/StreamFunctions.cpp @@ -0,0 +1,82 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mook + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include "nscore.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" + +/* + * Fully reads the required amount of data. Keeps reading until all the + * data is retrieved or an error is hit. + */ +NS_HIDDEN_(nsresult) ZW_ReadData(nsIInputStream *aStream, char *aBuffer, PRUint32 aCount) +{ + while (aCount > 0) { + PRUint32 read; + nsresult rv = aStream->Read(aBuffer, aCount, &read); + NS_ENSURE_SUCCESS(rv, rv); + aCount -= read; + aBuffer += read; + // If we hit EOF before reading the data we need then throw. + if (read == 0 && aCount > 0) + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +/* + * Fully writes the required amount of data. Keeps writing untill all the + * data is written or an error is hit. + */ +NS_HIDDEN_(nsresult) ZW_WriteData(nsIOutputStream *aStream, const char *aBuffer, + PRUint32 aCount) +{ + while (aCount > 0) { + PRUint32 written; + nsresult rv = aStream->Write(aBuffer, aCount, &written); + NS_ENSURE_SUCCESS(rv, rv); + if (written <= 0) + return NS_ERROR_FAILURE; + aCount -= written; + aBuffer += written; + } + + return NS_OK; +} diff --git a/modules/libjar/zipwriter/src/StreamFunctions.h b/modules/libjar/zipwriter/src/StreamFunctions.h new file mode 100644 index 000000000000..b1f7d2bf7859 --- /dev/null +++ b/modules/libjar/zipwriter/src/StreamFunctions.h @@ -0,0 +1,98 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mook + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#ifndef _nsStreamFunctions_h_ +#define _nsStreamFunctions_h_ + +#include "nscore.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" + +/* + * ZIP file data is stored little-endian. These are helper functions to read and + * write little endian data to/from a char buffer. + * The off argument is incremented according to the number of bytes consumed + * from the buffer. + */ +inline NS_HIDDEN_(void) WRITE8(char* buf, PRUint32* off, PRUint8 val) +{ + buf[(*off)++] = val & 0xff; +} + +inline NS_HIDDEN_(void) WRITE16(char* buf, PRUint32* off, PRUint16 val) +{ + buf[(*off)++] = val & 0xff; + buf[(*off)++] = (val >> 8) & 0xff; +} + +inline NS_HIDDEN_(void) WRITE32(char* buf, PRUint32* off, PRUint32 val) +{ + buf[(*off)++] = val & 0xff; + buf[(*off)++] = (val >> 8) & 0xff; + buf[(*off)++] = (val >> 16) & 0xff; + buf[(*off)++] = (val >> 24) & 0xff; +} + +inline NS_HIDDEN_(PRUint8) READ8(char* buf, PRUint32* off) +{ + return (PRUint8)buf[(*off)++]; +} + +inline NS_HIDDEN_(PRUint16) READ16(char* buf, PRUint32* off) +{ + PRUint16 val = (PRUint16)buf[(*off)++] & 0xff; + val |= ((PRUint16)buf[(*off)++] & 0xff) << 8; + return val; +} + +inline NS_HIDDEN_(PRUint32) READ32(char* 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; + return val; +} + +NS_HIDDEN_(nsresult) ZW_ReadData(nsIInputStream *aStream, char *aBuffer, PRUint32 aCount); + +NS_HIDDEN_(nsresult) ZW_WriteData(nsIOutputStream *aStream, const char *aBuffer, + PRUint32 aCount); + +#endif diff --git a/modules/libjar/zipwriter/src/ZipWriterModule.cpp b/modules/libjar/zipwriter/src/ZipWriterModule.cpp new file mode 100644 index 000000000000..9d666587f97c --- /dev/null +++ b/modules/libjar/zipwriter/src/ZipWriterModule.cpp @@ -0,0 +1,62 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include "nsIGenericFactory.h" +#include "nsDeflateConverter.h" +#include "nsZipWriter.h" + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeflateConverter) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsZipWriter) + +static nsModuleComponentInfo components[] = +{ + { + DEFLATECONVERTER_CLASSNAME, + DEFLATECONVERTER_CID, + DEFLATECONVERTER_CONTRACTID, + nsDeflateConverterConstructor, + }, + { + ZIPWRITER_CLASSNAME, + ZIPWRITER_CID, + ZIPWRITER_CONTRACTID, + nsZipWriterConstructor, + } +}; + +NS_IMPL_NSGETMODULE(ZipWriterModule, components) diff --git a/modules/libjar/zipwriter/src/nsDeflateConverter.cpp b/modules/libjar/zipwriter/src/nsDeflateConverter.cpp new file mode 100644 index 000000000000..f57f56c503ed --- /dev/null +++ b/modules/libjar/zipwriter/src/nsDeflateConverter.cpp @@ -0,0 +1,198 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Lan Qiang + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include "StreamFunctions.h" +#include "nsDeflateConverter.h" +#include "nsIStringStream.h" +#include "nsIInputStreamPump.h" +#include "nsComponentManagerUtils.h" +#include "nsMemory.h" +#include "nsAutoPtr.h" + +/** + * nsDeflateConverter is a stream converter applies the deflate compression + * method to the data. + */ +NS_IMPL_ISUPPORTS3(nsDeflateConverter, nsIStreamConverter, + nsIStreamListener, + nsIRequestObserver) + +nsresult nsDeflateConverter::Init() +{ + int zerr; + + mOffset = 0; + + mZstream.zalloc = Z_NULL; + mZstream.zfree = Z_NULL; + mZstream.opaque = Z_NULL; + + zerr = deflateInit2(&mZstream, mLevel, Z_DEFLATED, -MAX_WBITS, 8, + Z_DEFAULT_STRATEGY); + if (zerr != Z_OK) return NS_ERROR_OUT_OF_MEMORY; + + mZstream.next_out = mWriteBuffer; + mZstream.avail_out = sizeof(mWriteBuffer); + + return NS_OK; +} + +/* nsIInputStream convert (in nsIInputStream aFromStream, in string aFromType + * in string aToType, in nsISupports aCtxt); */ +NS_IMETHODIMP nsDeflateConverter::Convert(nsIInputStream *aFromStream, + const char *aFromType, + const char *aToType, + nsISupports *aCtxt, + nsIInputStream **_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void asyncConvertData (in string aFromType, in string aToType, + * in nsIStreamListener aListener, + * in nsISupports aCtxt); */ +NS_IMETHODIMP nsDeflateConverter::AsyncConvertData(const char *aFromType, + const char *aToType, + nsIStreamListener *aListener, + nsISupports *aCtxt) +{ + if (mListener) + return NS_ERROR_ALREADY_INITIALIZED; + + NS_ENSURE_ARG_POINTER(aListener); + + nsresult rv = Init(); + NS_ENSURE_SUCCESS(rv, rv); + + mListener = aListener; + mContext = aCtxt; + return rv; +} + +/* void onDataAvailable (in nsIRequest aRequest, in nsISupports aContext, + * in nsIInputStream aInputStream, + * in unsigned long aOffset, in unsigned long aCount); */ +NS_IMETHODIMP nsDeflateConverter::OnDataAvailable(nsIRequest *aRequest, + nsISupports *aContext, + nsIInputStream *aInputStream, + PRUint32 aOffset, + PRUint32 aCount) +{ + if (!mListener) + return NS_ERROR_NOT_INITIALIZED; + + nsAutoArrayPtr buffer(new char[aCount]); + NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = ZW_ReadData(aInputStream, buffer.get(), aCount); + NS_ENSURE_SUCCESS(rv, rv); + + // make sure we aren't reading too much + mZstream.avail_in = aCount; + mZstream.next_in = (unsigned char*)buffer.get(); + + int zerr = Z_OK; + // deflate loop + while (mZstream.avail_in > 0 && zerr == Z_OK) { + zerr = deflate(&mZstream, Z_NO_FLUSH); + + while (mZstream.avail_out == 0) { + // buffer is full, push the data out to the listener + rv = PushAvailableData(aRequest, aContext); + NS_ENSURE_SUCCESS(rv, rv); + zerr = deflate(&mZstream, Z_NO_FLUSH); + } + } + + return NS_OK; +} + +/* void onStartRequest (in nsIRequest aRequest, in nsISupports aContext); */ +NS_IMETHODIMP nsDeflateConverter::OnStartRequest(nsIRequest *aRequest, + nsISupports *aContext) +{ + if (!mListener) + return NS_ERROR_NOT_INITIALIZED; + + return mListener->OnStartRequest(aRequest, mContext); +} + +/* void onStopRequest (in nsIRequest aRequest, in nsISupports aContext, + * in nsresult aStatusCode); */ +NS_IMETHODIMP nsDeflateConverter::OnStopRequest(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aStatusCode) +{ + if (!mListener) + return NS_ERROR_NOT_INITIALIZED; + + nsresult rv; + + int zerr; + do { + zerr = deflate(&mZstream, Z_FINISH); + rv = PushAvailableData(aRequest, aContext); + NS_ENSURE_SUCCESS(rv, rv); + } while (zerr == Z_OK); + + deflateEnd(&mZstream); + + return mListener->OnStopRequest(aRequest, mContext, aStatusCode); +} + +nsresult nsDeflateConverter::PushAvailableData(nsIRequest *aRequest, + nsISupports *aContext) +{ + nsresult rv; + nsCOMPtr stream = + do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint32 bytesToWrite = ZIP_BUFLEN - mZstream.avail_out; + stream->ShareData((char*)mWriteBuffer, bytesToWrite); + rv = mListener->OnDataAvailable(aRequest, mContext, stream, mOffset, + bytesToWrite); + + // now set the state for 'deflate' + mZstream.next_out = mWriteBuffer; + mZstream.avail_out = sizeof(mWriteBuffer); + + mOffset += bytesToWrite; + return rv; +} diff --git a/modules/libjar/zipwriter/src/nsDeflateConverter.h b/modules/libjar/zipwriter/src/nsDeflateConverter.h new file mode 100644 index 000000000000..8079ac2fb37b --- /dev/null +++ b/modules/libjar/zipwriter/src/nsDeflateConverter.h @@ -0,0 +1,91 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Lan Qiang + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#ifndef _nsDeflateConverter_h_ +#define _nsDeflateConverter_h_ + +#include "nsIStreamConverter.h" +#include "nsCOMPtr.h" +#include "nsIPipe.h" +#include "zlib.h" + +#define DEFLATECONVERTER_CONTRACTID \ + "@mozilla.org/streamconv;1?from=uncompressed&to=deflate" +#define DEFLATECONVERTER_CLASSNAME "Deflate converter" +#define DEFLATECONVERTER_CID { 0x461cd5dd, 0x73c6, 0x47a4, \ + { 0x8c, 0xc3, 0x60, 0x3b, 0x37, 0xd8, 0x4a, 0x61 } } + +#define ZIP_BUFLEN (4 * 1024 - 1) + +class nsDeflateConverter : public nsIStreamConverter +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSISTREAMCONVERTER + + nsDeflateConverter() + { + mLevel = Z_DEFAULT_COMPRESSION; + } + + nsDeflateConverter(PRInt32 level) + { + mLevel = level; + } + +private: + + ~nsDeflateConverter() + { + } + + PRUint32 mOffset; + PRInt32 mLevel; + nsCOMPtr mListener; + nsCOMPtr mContext; + z_stream mZstream; + unsigned char mWriteBuffer[ZIP_BUFLEN]; + + nsresult Init(); + nsresult PushAvailableData(nsIRequest *aRequest, nsISupports *aContext); +}; + +#endif diff --git a/modules/libjar/zipwriter/src/nsZipDataStream.cpp b/modules/libjar/zipwriter/src/nsZipDataStream.cpp new file mode 100644 index 000000000000..65097bbb2dfc --- /dev/null +++ b/modules/libjar/zipwriter/src/nsZipDataStream.cpp @@ -0,0 +1,230 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mook + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include "StreamFunctions.h" +#include "nsZipDataStream.h" +#include "nsIStringStream.h" +#include "nsISeekableStream.h" +#include "nsDeflateConverter.h" +#include "nsNetUtil.h" +#include "nsComponentManagerUtils.h" +#include "nsMemory.h" + +#define ZIP_METHOD_STORE 0 +#define ZIP_METHOD_DEFLATE 8 + +/** + * nsZipDataStream handles the writing an entry's into the zip file. + * It is set up to wither write the data as is, or in the event that compression + * has been requested to pass it through a stream converter. + * Currently only the deflate compression method is supported. + * The CRC checksum for the entry's data is also generated here. + */ +NS_IMPL_THREADSAFE_ISUPPORTS2(nsZipDataStream, nsIStreamListener, + nsIRequestObserver) + +nsresult nsZipDataStream::Init(nsZipWriter *aWriter, + nsIOutputStream *aStream, + nsZipHeader *aHeader, + PRInt32 aCompression) +{ + mWriter = aWriter; + mHeader = aHeader; + mStream = aStream; + mHeader->mCRC = crc32(0L, Z_NULL, 0); + + nsresult rv = NS_NewSimpleStreamListener(getter_AddRefs(mOutput), aStream, + nsnull); + NS_ENSURE_SUCCESS(rv, rv); + + if (aCompression > 0) { + mHeader->mMethod = ZIP_METHOD_DEFLATE; + nsCOMPtr converter = + new nsDeflateConverter(aCompression); + NS_ENSURE_TRUE(converter, NS_ERROR_OUT_OF_MEMORY); + + rv = converter->AsyncConvertData("uncompressed", "deflate", mOutput, + nsnull); + NS_ENSURE_SUCCESS(rv, rv); + + mOutput = do_QueryInterface(converter, &rv); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + mHeader->mMethod = ZIP_METHOD_STORE; + } + + return NS_OK; +} + +/* void onDataAvailable (in nsIRequest aRequest, in nsISupports aContext, + * in nsIInputStream aInputStream, + * in unsigned long aOffset, in unsigned long aCount); */ +NS_IMETHODIMP nsZipDataStream::OnDataAvailable(nsIRequest *aRequest, + nsISupports *aContext, + nsIInputStream *aInputStream, + PRUint32 aOffset, + PRUint32 aCount) +{ + if (!mOutput) + return NS_ERROR_NOT_INITIALIZED; + + nsAutoArrayPtr buffer(new char[aCount]); + NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = ZW_ReadData(aInputStream, buffer.get(), aCount); + NS_ENSURE_SUCCESS(rv, rv); + + return ProcessData(aRequest, aContext, buffer.get(), aOffset, aCount); +} + +/* void onStartRequest (in nsIRequest aRequest, in nsISupports aContext); */ +NS_IMETHODIMP nsZipDataStream::OnStartRequest(nsIRequest *aRequest, + nsISupports *aContext) +{ + if (!mOutput) + return NS_ERROR_NOT_INITIALIZED; + + return mOutput->OnStartRequest(aRequest, aContext); +} + +/* void onStopRequest (in nsIRequest aRequest, in nsISupports aContext, + * in nsresult aStatusCode); */ +NS_IMETHODIMP nsZipDataStream::OnStopRequest(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aStatusCode) +{ + if (!mOutput) + return NS_ERROR_NOT_INITIALIZED; + + nsresult rv = mOutput->OnStopRequest(aRequest, aContext, aStatusCode); + mOutput = nsnull; + if (NS_FAILED(rv)) { + mWriter->EntryCompleteCallback(mHeader, rv); + } + else { + rv = CompleteEntry(); + rv = mWriter->EntryCompleteCallback(mHeader, rv); + } + + mStream = nsnull; + mWriter = nsnull; + mHeader = nsnull; + + return rv; +} + +inline nsresult nsZipDataStream::CompleteEntry() +{ + nsresult rv = mStream->Flush(); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr seekable = do_QueryInterface(mStream, &rv); + NS_ENSURE_SUCCESS(rv, rv); + PRInt64 pos; + rv = seekable->Tell(&pos); + NS_ENSURE_SUCCESS(rv, rv); + + mHeader->mCSize = pos - mHeader->mOffset - mHeader->GetFileHeaderLength(); + + // Go back and rewrite the file header + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, mHeader->mOffset); + NS_ENSURE_SUCCESS(rv, rv); + rv = mHeader->WriteFileHeader(mStream); + NS_ENSURE_SUCCESS(rv, rv); + rv = mStream->Flush(); + NS_ENSURE_SUCCESS(rv, rv); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, pos); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +nsresult nsZipDataStream::ProcessData(nsIRequest *aRequest, + nsISupports *aContext, char *aBuffer, + PRUint32 aOffset, PRUint32 aCount) +{ + mHeader->mCRC = crc32(mHeader->mCRC, + reinterpret_cast(aBuffer), + aCount); + + nsresult rv; + nsCOMPtr stream = + do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + stream->ShareData(aBuffer, aCount); + rv = mOutput->OnDataAvailable(aRequest, aContext, stream, aOffset, aCount); + mHeader->mUSize += aCount; + + return rv; +} + +nsresult nsZipDataStream::ReadStream(nsIInputStream *aStream) +{ + if (!mOutput) + return NS_ERROR_NOT_INITIALIZED; + + nsresult rv = OnStartRequest(nsnull, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoArrayPtr buffer(new char[4096]); + NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY); + + PRUint32 read = 0; + PRUint32 offset = 0; + do + { + rv = aStream->Read(buffer.get(), 4096, &read); + if (NS_FAILED(rv)) { + OnStopRequest(nsnull, nsnull, rv); + return rv; + } + + if (read > 0) { + rv = ProcessData(nsnull, nsnull, buffer.get(), offset, read); + if (NS_FAILED(rv)) { + OnStopRequest(nsnull, nsnull, rv); + return rv; + } + offset += read; + } + } while (read > 0); + + return OnStopRequest(nsnull, nsnull, NS_OK); +} diff --git a/modules/libjar/zipwriter/src/nsZipDataStream.h b/modules/libjar/zipwriter/src/nsZipDataStream.h new file mode 100644 index 000000000000..7f3723a79988 --- /dev/null +++ b/modules/libjar/zipwriter/src/nsZipDataStream.h @@ -0,0 +1,76 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mook + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#ifndef _nsZipDataStream_h_ +#define _nsZipDataStream_h_ + +#include "nsZipWriter.h" +#include "nsIOutputStream.h" +#include "nsIStreamListener.h" +#include "nsAutoPtr.h" + +class nsZipDataStream : public nsIStreamListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + + nsZipDataStream() + { + } + + nsresult Init(nsZipWriter *aWriter, nsIOutputStream *aStream, + nsZipHeader *aHeader, PRInt32 aCompression); + + nsresult ReadStream(nsIInputStream *aStream); + +private: + + nsCOMPtr mOutput; + nsCOMPtr mStream; + nsRefPtr mWriter; + nsRefPtr mHeader; + + nsresult CompleteEntry(); + nsresult ProcessData(nsIRequest *aRequest, nsISupports *aContext, + char *aBuffer, PRUint32 aOffset, PRUint32 aCount); +}; + +#endif diff --git a/modules/libjar/zipwriter/src/nsZipHeader.cpp b/modules/libjar/zipwriter/src/nsZipHeader.cpp new file mode 100644 index 000000000000..0a59089ee4e5 --- /dev/null +++ b/modules/libjar/zipwriter/src/nsZipHeader.cpp @@ -0,0 +1,292 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include "StreamFunctions.h" +#include "nsZipHeader.h" +#include "nsMemory.h" + +#define ZIP_FILE_HEADER_SIGNATURE 0x04034b50 +#define ZIP_FILE_HEADER_SIZE 30 +#define ZIP_CDS_HEADER_SIGNATURE 0x02014b50 +#define ZIP_CDS_HEADER_SIZE 46 + +#define FLAGS_IS_UTF8 0x800 + +/** + * nsZipHeader represents an entry from a zip file. + */ +NS_IMPL_ISUPPORTS1(nsZipHeader, nsIZipEntry) + +/* readonly attribute unsigned short compression; */ +NS_IMETHODIMP nsZipHeader::GetCompression(PRUint16 *aCompression) +{ + NS_ASSERTION(mInited, "Not initalised"); + + *aCompression = mMethod; + return NS_OK; +} + +/* readonly attribute unsigned long size; */ +NS_IMETHODIMP nsZipHeader::GetSize(PRUint32 *aSize) +{ + NS_ASSERTION(mInited, "Not initalised"); + + *aSize = mCSize; + return NS_OK; +} + +/* readonly attribute unsigned long realSize; */ +NS_IMETHODIMP nsZipHeader::GetRealSize(PRUint32 *aRealSize) +{ + NS_ASSERTION(mInited, "Not initalised"); + + *aRealSize = mUSize; + return NS_OK; +} + +/* readonly attribute unsigned long CRC32; */ +NS_IMETHODIMP nsZipHeader::GetCRC32(PRUint32 *aCRC32) +{ + NS_ASSERTION(mInited, "Not initalised"); + + *aCRC32 = mCRC; + return NS_OK; +} + +/* readonly attribute boolean isDirectory; */ +NS_IMETHODIMP nsZipHeader::GetIsDirectory(PRBool *aIsDirectory) +{ + NS_ASSERTION(mInited, "Not initalised"); + + if (mName.Last() == '/') + *aIsDirectory = PR_TRUE; + else + *aIsDirectory = PR_FALSE; + return NS_OK; +} + +/* readonly attribute PRTime lastModifiedTime; */ +NS_IMETHODIMP nsZipHeader::GetLastModifiedTime(PRTime *aLastModifiedTime) +{ + NS_ASSERTION(mInited, "Not initalised"); + + PRExplodedTime time; + + time.tm_usec = 0; + + time.tm_hour = mTime >> 11; + time.tm_min = (mTime >> 5) & 0x3F; + time.tm_sec = (mTime & 0x1F) * 2; + + time.tm_year = (mDate >> 9) + 1980; + time.tm_month = ((mDate >> 5) & 0x0F) - 1; + time.tm_mday = mDate & 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); + + *aLastModifiedTime = PR_ImplodeTime(&time); + + return NS_OK; +} + +/* readonly attribute boolean isSynthetic; */ +NS_IMETHODIMP nsZipHeader::GetIsSynthetic(PRBool *aIsSynthetic) +{ + NS_ASSERTION(mInited, "Not initalised"); + + *aIsSynthetic = PR_FALSE; + return NS_OK; +} + +void nsZipHeader::Init(const nsACString & aPath, PRTime aDate, PRUint32 aAttr, + PRUint32 aOffset) +{ + NS_ASSERTION(!mInited, "Already initalised"); + + PRExplodedTime time; + PR_ExplodeTime(aDate, PR_LocalTimeParameters, &time); + + mTime = time.tm_sec / 2 + (time.tm_min << 5) + (time.tm_hour << 11); + mDate = time.tm_mday + ((time.tm_month + 1) << 5) + + ((time.tm_year - 1980) << 9); + + mEAttr = aAttr; + mOffset = aOffset; + mName = aPath; + mComment = NS_LITERAL_CSTRING(""); + // Claim a UTF-8 path in case it needs it. + mFlags |= FLAGS_IS_UTF8; + mInited = PR_TRUE; +} + +PRUint32 nsZipHeader::GetFileHeaderLength() +{ + return ZIP_FILE_HEADER_SIZE + mName.Length(); +} + +nsresult nsZipHeader::WriteFileHeader(nsIOutputStream *aStream) +{ + NS_ASSERTION(mInited, "Not initalised"); + + char buf[ZIP_FILE_HEADER_SIZE]; + PRUint32 pos = 0; + WRITE32(buf, &pos, ZIP_FILE_HEADER_SIGNATURE); + WRITE16(buf, &pos, mVersionNeeded); + WRITE16(buf, &pos, mFlags); + WRITE16(buf, &pos, mMethod); + WRITE16(buf, &pos, mTime); + WRITE16(buf, &pos, mDate); + WRITE32(buf, &pos, mCRC); + WRITE32(buf, &pos, mCSize); + WRITE32(buf, &pos, mUSize); + WRITE16(buf, &pos, mName.Length()); + WRITE16(buf, &pos, 0); + + nsresult rv = ZW_WriteData(aStream, buf, pos); + NS_ENSURE_SUCCESS(rv, rv); + + return ZW_WriteData(aStream, mName.get(), mName.Length()); +} + +PRUint32 nsZipHeader::GetCDSHeaderLength() +{ + return ZIP_CDS_HEADER_SIZE + mName.Length() + mComment.Length() + + mFieldLength; +} + +nsresult nsZipHeader::WriteCDSHeader(nsIOutputStream *aStream) +{ + NS_ASSERTION(mInited, "Not initalised"); + + char buf[ZIP_CDS_HEADER_SIZE]; + PRUint32 pos = 0; + WRITE32(buf, &pos, ZIP_CDS_HEADER_SIGNATURE); + WRITE16(buf, &pos, mVersionMade); + WRITE16(buf, &pos, mVersionNeeded); + WRITE16(buf, &pos, mFlags); + WRITE16(buf, &pos, mMethod); + WRITE16(buf, &pos, mTime); + WRITE16(buf, &pos, mDate); + WRITE32(buf, &pos, mCRC); + WRITE32(buf, &pos, mCSize); + WRITE32(buf, &pos, mUSize); + WRITE16(buf, &pos, mName.Length()); + WRITE16(buf, &pos, mFieldLength); + WRITE16(buf, &pos, mComment.Length()); + WRITE16(buf, &pos, mDisk); + WRITE16(buf, &pos, mIAttr); + WRITE32(buf, &pos, mEAttr); + WRITE32(buf, &pos, mOffset); + + nsresult rv = ZW_WriteData(aStream, 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, sizeof(mExtraField)); + NS_ENSURE_SUCCESS(rv, rv); + } + return ZW_WriteData(aStream, mComment.get(), mComment.Length()); +} + +nsresult nsZipHeader::ReadCDSHeader(nsIInputStream *stream) +{ + NS_ASSERTION(!mInited, "Already initalised"); + + char buf[ZIP_CDS_HEADER_SIZE]; + + nsresult rv = ZW_ReadData(stream, buf, ZIP_CDS_HEADER_SIZE); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint32 pos = 0; + PRUint32 signature = READ32(buf, &pos); + if (signature != ZIP_CDS_HEADER_SIGNATURE) + return NS_ERROR_FILE_CORRUPTED; + + mVersionMade = READ16(buf, &pos); + mVersionNeeded = READ16(buf, &pos); + mFlags = READ16(buf, &pos); + mMethod = READ16(buf, &pos); + mTime = READ16(buf, &pos); + mDate = READ16(buf, &pos); + mCRC = READ32(buf, &pos); + mCSize = READ32(buf, &pos); + mUSize = READ32(buf, &pos); + PRUint16 namelength = READ16(buf, &pos); + PRUint16 fieldlength = READ16(buf, &pos); + PRUint16 commentlength = READ16(buf, &pos); + mDisk = READ16(buf, &pos); + mIAttr = READ16(buf, &pos); + mEAttr = READ32(buf, &pos); + mOffset = READ32(buf, &pos); + + if (namelength > 0) { + nsAutoArrayPtr field(new char[namelength]); + NS_ENSURE_TRUE(field, NS_ERROR_OUT_OF_MEMORY); + rv = ZW_ReadData(stream, field.get(), namelength); + NS_ENSURE_SUCCESS(rv, rv); + mName.Assign(field, namelength); + } + else + mName = NS_LITERAL_CSTRING(""); + + if (fieldlength > 0) { + mExtraField = new char[fieldlength]; + NS_ENSURE_TRUE(mExtraField, NS_ERROR_OUT_OF_MEMORY); + rv = ZW_ReadData(stream, mExtraField.get(), fieldlength); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (commentlength > 0) { + nsAutoArrayPtr field(new char[commentlength]); + NS_ENSURE_TRUE(field, NS_ERROR_OUT_OF_MEMORY); + rv = ZW_ReadData(stream, field.get(), commentlength); + NS_ENSURE_SUCCESS(rv, rv); + mComment.Assign(field, commentlength); + } + else + mComment = NS_LITERAL_CSTRING(""); + + mInited = PR_TRUE; + return NS_OK; +} diff --git a/modules/libjar/zipwriter/src/nsZipHeader.h b/modules/libjar/zipwriter/src/nsZipHeader.h new file mode 100644 index 000000000000..78b5c34cb6ed --- /dev/null +++ b/modules/libjar/zipwriter/src/nsZipHeader.h @@ -0,0 +1,110 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#ifndef _nsZipHeader_h_ +#define _nsZipHeader_h_ + +#include "nsString.h" +#include "nsIOutputStream.h" +#include "nsIInputStream.h" +#include "nsIZipReader.h" +#include "nsAutoPtr.h" + +#define ZIP_ATTRS_FILE 0 +#define ZIP_ATTRS_DIRECTORY 16 + +class nsZipHeader : public nsIZipEntry +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIZIPENTRY + + nsZipHeader() : + mCRC(0), + mCSize(0), + mUSize(0), + mEAttr(0), + mOffset(0), + mFieldLength(0), + mVersionMade(20), + mVersionNeeded(20), + mFlags(0), + mMethod(0), + mTime(0), + mDate(0), + mDisk(0), + mIAttr(0), + mInited(PR_FALSE), + mExtraField(NULL) + { + } + + ~nsZipHeader() + { + mExtraField = NULL; + } + + PRUint32 mCRC; + PRUint32 mCSize; + PRUint32 mUSize; + PRUint32 mEAttr; + PRUint32 mOffset; + PRUint32 mFieldLength; + PRUint16 mVersionMade; + PRUint16 mVersionNeeded; + PRUint16 mFlags; + PRUint16 mMethod; + PRUint16 mTime; + PRUint16 mDate; + PRUint16 mDisk; + PRUint16 mIAttr; + PRPackedBool mInited; + nsCString mName; + nsCString mComment; + nsAutoArrayPtr mExtraField; + + void Init(const nsACString & aPath, PRTime aDate, PRUint32 aAttr, + PRUint32 aOffset); + PRUint32 GetFileHeaderLength(); + nsresult WriteFileHeader(nsIOutputStream *aStream); + PRUint32 GetCDSHeaderLength(); + nsresult WriteCDSHeader(nsIOutputStream *aStream); + nsresult ReadCDSHeader(nsIInputStream *aStream); +}; + +#endif diff --git a/modules/libjar/zipwriter/src/nsZipWriter.cpp b/modules/libjar/zipwriter/src/nsZipWriter.cpp new file mode 100644 index 000000000000..10300449ec46 --- /dev/null +++ b/modules/libjar/zipwriter/src/nsZipWriter.cpp @@ -0,0 +1,1033 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mook + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include "StreamFunctions.h" +#include "nsZipWriter.h" +#include "nsZipDataStream.h" +#include "nsISeekableStream.h" +#include "nsIAsyncStreamCopier.h" +#include "nsIStreamListener.h" +#include "nsIInputStreamPump.h" +#include "nsComponentManagerUtils.h" +#include "nsMemory.h" +#include "nsNetError.h" +#include "nsStreamUtils.h" +#include "nsThreadUtils.h" +#include "nsNetUtil.h" +#include "prio.h" + +#define ZIP_EOCDR_HEADER_SIZE 22 +#define ZIP_EOCDR_HEADER_SIGNATURE 0x06054b50 + +/** + * nsZipWriter is used to create and add to zip files. + * It is based on the spec available at + * http://www.pkware.com/documents/casestudies/APPNOTE.TXT. + * + * The basic structure of a zip file created is slightly simpler than that + * illustrated in the spec because certain features of the zip format are + * unsupported: + * + * [local file header 1] + * [file data 1] + * . + * . + * . + * [local file header n] + * [file data n] + * [central directory] + * [end of central directory record] + */ +NS_IMPL_ISUPPORTS2(nsZipWriter, nsIZipWriter, + nsIRequestObserver) + +nsZipWriter::nsZipWriter() +{ + mEntryHash.Init(); + mInQueue = PR_FALSE; +} + +nsZipWriter::~nsZipWriter() +{ + if (mStream && !mInQueue) + Close(); +} + +/* attribute AString comment; */ +NS_IMETHODIMP nsZipWriter::GetComment(nsACString & aComment) +{ + if (!mStream) + return NS_ERROR_NOT_INITIALIZED; + + aComment = mComment; + return NS_OK; +} + +NS_IMETHODIMP nsZipWriter::SetComment(const nsACString & aComment) +{ + if (!mStream) + return NS_ERROR_NOT_INITIALIZED; + + mComment = aComment; + mCDSDirty = PR_TRUE; + return NS_OK; +} + +/* readonly attribute boolean inQueue; */ +NS_IMETHODIMP nsZipWriter::GetInQueue(PRBool *aInQueue) +{ + *aInQueue = mInQueue; + return NS_OK; +} + +/* readonly attribute nsIFile file; */ +NS_IMETHODIMP nsZipWriter::GetFile(nsIFile **aFile) +{ + nsCOMPtr file; + nsresult rv = mFile->Clone(getter_AddRefs(file)); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ADDREF(*aFile = file); + return NS_OK; +} + +/* + * Reads file entries out of an existing zip file. + */ +nsresult nsZipWriter::ReadFile(nsIFile *aFile) +{ + PRInt64 size; + nsresult rv = aFile->GetFileSize(&size); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr inputStream; + rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), aFile); + NS_ENSURE_SUCCESS(rv, rv); + + char buf[1024]; + PRInt64 seek = size - 1024; + PRUint32 length = 1024; + + if (seek < 0) { + length += seek; + seek = 0; + } + + PRUint32 pos; + PRUint32 sig = 0; + nsCOMPtr seekable = do_QueryInterface(inputStream); + + while (true) { + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, seek); + if (NS_FAILED(rv)) { + inputStream->Close(); + return rv; + } + rv = ZW_ReadData(inputStream, buf, length); + if (NS_FAILED(rv)) { + inputStream->Close(); + return rv; + } + + /* + * We have to backtrack from the end of the file until we find the + * CDS signature + */ + // We know it's at least this far from the end + pos = length - ZIP_EOCDR_HEADER_SIZE; + sig = READ32(buf, &pos); + pos -= 4; + while (pos >=0) { + if (sig == ZIP_EOCDR_HEADER_SIGNATURE) { + // Skip down to entry count + pos += 10; + PRUint32 entries = READ16(buf, &pos); + // Skip past CDS size + pos += 4; + mCDSOffset = READ32(buf, &pos); + PRUint32 commentlen = READ16(buf, &pos); + + if (commentlen == 0) + mComment.Truncate(); + else if (pos + commentlen <= length) + mComment.Assign(buf + pos, commentlen); + else { + if ((seek + pos + commentlen) > size) { + inputStream->Close(); + return NS_ERROR_FILE_CORRUPTED; + } + nsAutoArrayPtr field(new char[commentlen]); + NS_ENSURE_TRUE(field, NS_ERROR_OUT_OF_MEMORY); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + seek + pos); + if (NS_FAILED(rv)) { + inputStream->Close(); + return rv; + } + rv = ZW_ReadData(inputStream, field.get(), length); + if (NS_FAILED(rv)) { + inputStream->Close(); + return rv; + } + mComment.Assign(field.get(), commentlen); + } + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + mCDSOffset); + if (NS_FAILED(rv)) { + inputStream->Close(); + return rv; + } + + for (PRUint32 entry = 0; entry < entries; entry++) { + nsZipHeader* header = new nsZipHeader(); + if (!header) { + inputStream->Close(); + mEntryHash.Clear(); + mHeaders.Clear(); + return NS_ERROR_OUT_OF_MEMORY; + } + rv = header->ReadCDSHeader(inputStream); + if (NS_FAILED(rv)) { + inputStream->Close(); + mEntryHash.Clear(); + mHeaders.Clear(); + return rv; + } + if (!mEntryHash.Put(header->mName, mHeaders.Count())) + return NS_ERROR_OUT_OF_MEMORY; + if (!mHeaders.AppendObject(header)) + return NS_ERROR_OUT_OF_MEMORY; + } + + return inputStream->Close(); + } + sig = sig << 8; + sig += buf[--pos]; + } + + if (seek == 0) { + // We've reached the start with no signature found. Corrupt. + inputStream->Close(); + return NS_ERROR_FILE_CORRUPTED; + } + + // Overlap by the size of the end of cdr + seek -= (1024 - ZIP_EOCDR_HEADER_SIZE); + if (seek < 0) { + length += seek; + seek = 0; + } + } + // Will never reach here in reality + NS_NOTREACHED("Loop should never complete"); + return NS_ERROR_UNEXPECTED; +} + +/* void open (in nsIFile aFile, in PRInt32 aIoFlags); */ +NS_IMETHODIMP nsZipWriter::Open(nsIFile *aFile, PRInt32 aIoFlags) +{ + if (mStream) + return NS_ERROR_ALREADY_INITIALIZED; + + NS_ENSURE_ARG_POINTER(aFile); + + // Need to be able to write to the file + if (aIoFlags & PR_RDONLY) + return NS_ERROR_FAILURE; + + PRBool exists; + nsresult rv = aFile->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + if (!exists && !(aIoFlags & PR_CREATE_FILE)) + return NS_ERROR_FILE_NOT_FOUND; + + if (exists && !(aIoFlags & (PR_TRUNCATE | PR_WRONLY))) { + rv = ReadFile(aFile); + NS_ENSURE_SUCCESS(rv, rv); + mCDSDirty = PR_FALSE; + } + else { + mCDSOffset = 0; + mCDSDirty = PR_TRUE; + mComment.Truncate(); + } + + // Silently drop PR_APPEND + aIoFlags &= 0xef; + + nsCOMPtr stream; + rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), aFile, aIoFlags); + if (NS_FAILED(rv)) { + mHeaders.Clear(); + mEntryHash.Clear(); + return rv; + } + + rv = NS_NewBufferedOutputStream(getter_AddRefs(mStream), stream, 0x800); + if (NS_FAILED(rv)) { + stream->Close(); + mHeaders.Clear(); + mEntryHash.Clear(); + return rv; + } + + if (mCDSOffset > 0) { + rv = SeekCDS(); + NS_ENSURE_SUCCESS(rv, rv); + } + + mFile = aFile; + + return NS_OK; +} + +/* nsIZipEntry getEntry (in AString aZipEntry); */ +NS_IMETHODIMP nsZipWriter::GetEntry(const nsACString & aZipEntry, + nsIZipEntry **_retval) +{ + PRInt32 pos; + if (mEntryHash.Get(aZipEntry, &pos)) + NS_ADDREF(*_retval = mHeaders[pos]); + else + *_retval = nsnull; + + return NS_OK; +} + +/* boolean hasEntry (in AString aZipEntry); */ +NS_IMETHODIMP nsZipWriter::HasEntry(const nsACString & aZipEntry, + PRBool *_retval) +{ + *_retval = mEntryHash.Get(aZipEntry, nsnull); + + return NS_OK; +} + +/* void addEntryDirectory (in AUTF8String aZipEntry, in PRTime aModTime, + * in boolean aQueue); */ +NS_IMETHODIMP nsZipWriter::AddEntryDirectory(const nsACString & aZipEntry, + PRTime aModTime, PRBool aQueue) +{ + if (!mStream) + return NS_ERROR_NOT_INITIALIZED; + + if (aQueue) { + nsZipQueueItem item; + item.mOperation = OPERATION_ADD; + item.mZipEntry = aZipEntry; + item.mModTime = aModTime; + if (!mQueue.AppendElement(item)) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; + } + + if (mInQueue) + return NS_ERROR_IN_PROGRESS; + return InternalAddEntryDirectory(aZipEntry, aModTime); +} + +/* void addEntryFile (in AUTF8String aZipEntry, in PRInt32 aCompression, + * in nsIFile aFile, in boolean aQueue); */ +NS_IMETHODIMP nsZipWriter::AddEntryFile(const nsACString & aZipEntry, + PRInt32 aCompression, nsIFile *aFile, + PRBool aQueue) +{ + NS_ENSURE_ARG_POINTER(aFile); + if (!mStream) + return NS_ERROR_NOT_INITIALIZED; + + if (aQueue) { + nsZipQueueItem item; + item.mOperation = OPERATION_ADD; + item.mZipEntry = aZipEntry; + item.mCompression = aCompression; + item.mFile = aFile; + if (!mQueue.AppendElement(item)) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; + } + + if (mInQueue) + return NS_ERROR_IN_PROGRESS; + + PRBool exists; + nsresult rv = aFile->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + if (!exists) + return NS_ERROR_FILE_NOT_FOUND; + + PRBool isdir; + rv = aFile->IsDirectory(&isdir); + NS_ENSURE_SUCCESS(rv, rv); + + PRInt64 modtime; + rv = aFile->GetLastModifiedTime(&modtime); + NS_ENSURE_SUCCESS(rv, rv); + modtime *= PR_USEC_PER_MSEC; + + if (isdir) + return InternalAddEntryDirectory(aZipEntry, modtime); + + if (mEntryHash.Get(aZipEntry, nsnull)) + return NS_ERROR_FILE_ALREADY_EXISTS; + + nsCOMPtr inputStream; + rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), + aFile); + NS_ENSURE_SUCCESS(rv, rv); + + rv = AddEntryStream(aZipEntry, modtime, aCompression, inputStream, + PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); + + return inputStream->Close(); +} + +/* void addEntryChannel (in AUTF8String aZipEntry, in PRTime aModTime, + * in PRInt32 aCompression, in nsIChannel aChannel, + * in boolean aQueue); */ +NS_IMETHODIMP nsZipWriter::AddEntryChannel(const nsACString & aZipEntry, + PRTime aModTime, + PRInt32 aCompression, + nsIChannel *aChannel, + PRBool aQueue) +{ + NS_ENSURE_ARG_POINTER(aChannel); + if (!mStream) + return NS_ERROR_NOT_INITIALIZED; + + if (aQueue) { + nsZipQueueItem item; + item.mOperation = OPERATION_ADD; + item.mZipEntry = aZipEntry; + item.mModTime = aModTime; + item.mCompression = aCompression; + item.mChannel = aChannel; + if (!mQueue.AppendElement(item)) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; + } + + if (mInQueue) + return NS_ERROR_IN_PROGRESS; + if (mEntryHash.Get(aZipEntry, nsnull)) + return NS_ERROR_FILE_ALREADY_EXISTS; + + nsCOMPtr inputStream; + nsresult rv = aChannel->Open(getter_AddRefs(inputStream)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = AddEntryStream(aZipEntry, aModTime, aCompression, inputStream, + PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); + + return inputStream->Close(); +} + +/* void addEntryStream (in AUTF8String aZipEntry, in PRTime aModTime, + * in PRInt32 aCompression, in nsIInputStream aStream, + * in boolean aQueue); */ +NS_IMETHODIMP nsZipWriter::AddEntryStream(const nsACString & aZipEntry, + PRTime aModTime, + PRInt32 aCompression, + nsIInputStream *aStream, + PRBool aQueue) +{ + NS_ENSURE_ARG_POINTER(aStream); + if (!mStream) + return NS_ERROR_NOT_INITIALIZED; + + if (aQueue) { + nsZipQueueItem item; + item.mOperation = OPERATION_ADD; + item.mZipEntry = aZipEntry; + item.mModTime = aModTime; + item.mCompression = aCompression; + item.mStream = aStream; + if (!mQueue.AppendElement(item)) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; + } + + if (mInQueue) + return NS_ERROR_IN_PROGRESS; + if (mEntryHash.Get(aZipEntry, nsnull)) + return NS_ERROR_FILE_ALREADY_EXISTS; + + nsRefPtr header = new nsZipHeader(); + NS_ENSURE_TRUE(header, NS_ERROR_OUT_OF_MEMORY); + header->Init(aZipEntry, aModTime, ZIP_ATTRS_FILE, mCDSOffset); + nsresult rv = header->WriteFileHeader(mStream); + if (NS_FAILED(rv)) { + SeekCDS(); + return rv; + } + + nsRefPtr stream = new nsZipDataStream(); + if (!stream) { + SeekCDS(); + return NS_ERROR_OUT_OF_MEMORY; + } + rv = stream->Init(this, mStream, header, aCompression); + if (NS_FAILED(rv)) { + SeekCDS(); + return rv; + } + + rv = stream->ReadStream(aStream); + if (NS_FAILED(rv)) + SeekCDS(); + return rv; +} + +/* void removeEntry (in AUTF8String aZipEntry, in boolean aQueue); */ +NS_IMETHODIMP nsZipWriter::RemoveEntry(const nsACString & aZipEntry, + PRBool aQueue) +{ + if (!mStream) + return NS_ERROR_NOT_INITIALIZED; + + if (aQueue) { + nsZipQueueItem item; + item.mOperation = OPERATION_REMOVE; + item.mZipEntry = aZipEntry; + if (!mQueue.AppendElement(item)) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; + } + + if (mInQueue) + return NS_ERROR_IN_PROGRESS; + + PRInt32 pos; + if (mEntryHash.Get(aZipEntry, &pos)) { + // Flush any remaining data before we seek. + nsresult rv = mStream->Flush(); + NS_ENSURE_SUCCESS(rv, rv); + if (pos < mHeaders.Count() - 1) { + // This is not the last entry, pull back the data. + nsCOMPtr seekable = do_QueryInterface(mStream); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + mHeaders[pos]->mOffset); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr inputStream; + rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), + mFile); + NS_ENSURE_SUCCESS(rv, rv); + seekable = do_QueryInterface(inputStream); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + mHeaders[pos + 1]->mOffset); + if (NS_FAILED(rv)) { + inputStream->Close(); + return rv; + } + + PRUint32 count = mCDSOffset - mHeaders[pos + 1]->mOffset; + PRUint32 read = 0; + char buf[4096]; + while (count > 0) { + if (count < sizeof(buf)) + read = count; + else + read = sizeof(buf); + + rv = inputStream->Read(buf, read, &read); + if (NS_FAILED(rv)) { + inputStream->Close(); + Cleanup(); + return rv; + } + + rv = ZW_WriteData(mStream, buf, read); + if (NS_FAILED(rv)) { + inputStream->Close(); + Cleanup(); + return rv; + } + + count -= read; + } + inputStream->Close(); + + // Rewrite header offsets and update hash + PRUint32 shift = (mHeaders[pos + 1]->mOffset - + mHeaders[pos]->mOffset); + mCDSOffset -= shift; + PRInt32 pos2 = pos + 1; + while (pos2 < mHeaders.Count()) { + if (!mEntryHash.Put(mHeaders[pos2]->mName, pos2-1)) { + Cleanup(); + return NS_ERROR_OUT_OF_MEMORY; + } + mHeaders[pos2]->mOffset -= shift; + pos2++; + } + } + else { + // Remove the last entry is just a case of moving the CDS + mCDSOffset = mHeaders[pos]->mOffset; + rv = SeekCDS(); + NS_ENSURE_SUCCESS(rv, rv); + } + + mEntryHash.Remove(mHeaders[pos]->mName); + mHeaders.RemoveObjectAt(pos); + mCDSDirty = PR_TRUE; + + return NS_OK; + } + + return NS_ERROR_FILE_NOT_FOUND; +} + +/* void processQueue (in nsIRequestObserver aObserver, + * in nsISupports aContext); */ +NS_IMETHODIMP nsZipWriter::ProcessQueue(nsIRequestObserver *aObserver, + nsISupports *aContext) +{ + if (!mStream) + return NS_ERROR_NOT_INITIALIZED; + if (mInQueue) + return NS_ERROR_IN_PROGRESS; + + mProcessObserver = aObserver; + mProcessContext = aContext; + mInQueue = PR_TRUE; + + if (mProcessObserver) + mProcessObserver->OnStartRequest(nsnull, mProcessContext); + + BeginProcessingNextItem(); + + return NS_OK; +} + +/* void close (); */ +NS_IMETHODIMP nsZipWriter::Close() +{ + if (!mStream) + return NS_ERROR_NOT_INITIALIZED; + if (mInQueue) + return NS_ERROR_IN_PROGRESS; + + if (mCDSDirty) { + PRUint32 size = 0; + for (PRInt32 i = 0; i < mHeaders.Count(); i++) { + nsresult rv = mHeaders[i]->WriteCDSHeader(mStream); + if (NS_FAILED(rv)) { + Cleanup(); + return rv; + } + size += mHeaders[i]->GetCDSHeaderLength(); + } + + char buf[ZIP_EOCDR_HEADER_SIZE]; + PRUint32 pos = 0; + WRITE32(buf, &pos, ZIP_EOCDR_HEADER_SIGNATURE); + WRITE16(buf, &pos, 0); + WRITE16(buf, &pos, 0); + WRITE16(buf, &pos, mHeaders.Count()); + WRITE16(buf, &pos, mHeaders.Count()); + WRITE32(buf, &pos, size); + WRITE32(buf, &pos, mCDSOffset); + WRITE16(buf, &pos, mComment.Length()); + + nsresult rv = ZW_WriteData(mStream, buf, pos); + if (NS_FAILED(rv)) { + Cleanup(); + return rv; + } + + rv = ZW_WriteData(mStream, mComment.get(), mComment.Length()); + if (NS_FAILED(rv)) { + Cleanup(); + return rv; + } + + nsCOMPtr seekable = do_QueryInterface(mStream); + rv = seekable->SetEOF(); + if (NS_FAILED(rv)) { + Cleanup(); + return rv; + } + } + + nsresult rv = mStream->Close(); + mStream = nsnull; + mHeaders.Clear(); + mEntryHash.Clear(); + mQueue.Clear(); + + return rv; +} + +// Our nsIRequestObserver monitors removal operations performed on the queue +/* void onStartRequest (in nsIRequest aRequest, in nsISupports aContext); */ +NS_IMETHODIMP nsZipWriter::OnStartRequest(nsIRequest *aRequest, + nsISupports *aContext) +{ + return NS_OK; +} + +/* void onStopRequest (in nsIRequest aRequest, in nsISupports aContext, + * in nsresult aStatusCode); */ +NS_IMETHODIMP nsZipWriter::OnStopRequest(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aStatusCode) +{ + if (NS_FAILED(aStatusCode)) { + FinishQueue(aStatusCode); + Cleanup(); + } + + nsresult rv = mStream->Flush(); + if (NS_FAILED(rv)) { + FinishQueue(rv); + Cleanup(); + return rv; + } + rv = SeekCDS(); + if (NS_FAILED(rv)) { + FinishQueue(rv); + return rv; + } + + BeginProcessingNextItem(); + + return NS_OK; +} + +nsresult nsZipWriter::InternalAddEntryDirectory(const nsACString & aZipEntry, + PRTime aModTime) +{ + nsRefPtr header = new nsZipHeader(); + NS_ENSURE_TRUE(header, NS_ERROR_OUT_OF_MEMORY); + + if (aZipEntry.Last() != '/') { + nsCString dirPath; + dirPath.Assign(aZipEntry + NS_LITERAL_CSTRING("/")); + header->Init(dirPath, aModTime, ZIP_ATTRS_DIRECTORY, mCDSOffset); + } + else + header->Init(aZipEntry, aModTime, ZIP_ATTRS_DIRECTORY, mCDSOffset); + + if (mEntryHash.Get(header->mName, nsnull)) + return NS_ERROR_FILE_ALREADY_EXISTS; + + nsresult rv = header->WriteFileHeader(mStream); + if (NS_FAILED(rv)) { + Cleanup(); + return rv; + } + + mCDSDirty = PR_TRUE; + mCDSOffset += header->GetFileHeaderLength(); + if (!mEntryHash.Put(header->mName, mHeaders.Count())) { + Cleanup(); + return NS_ERROR_OUT_OF_MEMORY; + } + if (!mHeaders.AppendObject(header)) { + Cleanup(); + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; +} + +/* + * Recovering from an error while adding a new entry is simply a case of + * seeking back to the CDS. If we fail trying to do that though then cleanup + * and bail out. + */ +nsresult nsZipWriter::SeekCDS() +{ + nsresult rv; + nsCOMPtr seekable = do_QueryInterface(mStream, &rv); + if (NS_FAILED(rv)) { + Cleanup(); + return rv; + } + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, mCDSOffset); + if (NS_FAILED(rv)) + Cleanup(); + return rv; +} + +/* + * In a bad error condition this essentially closes down the component as best + * it can. + */ +void nsZipWriter::Cleanup() +{ + mHeaders.Clear(); + mEntryHash.Clear(); + if (mStream) + mStream->Close(); + mStream = nsnull; + mFile = nsnull; +} + +/* + * Called when writing a file to the zip is complete. + */ +nsresult nsZipWriter::EntryCompleteCallback(nsZipHeader* aHeader, + nsresult aStatus) +{ + if (NS_SUCCEEDED(aStatus)) { + if (!mEntryHash.Put(aHeader->mName, mHeaders.Count())) { + SeekCDS(); + return NS_ERROR_OUT_OF_MEMORY; + } + if (!mHeaders.AppendObject(aHeader)) { + mEntryHash.Remove(aHeader->mName); + SeekCDS(); + return NS_ERROR_OUT_OF_MEMORY; + } + mCDSDirty = PR_TRUE; + mCDSOffset += aHeader->mCSize + aHeader->GetFileHeaderLength(); + + if (mInQueue) + BeginProcessingNextItem(); + + return NS_OK; + } + + nsresult rv = SeekCDS(); + if (mInQueue) + FinishQueue(aStatus); + return rv; +} + +inline nsresult nsZipWriter::BeginProcessingAddition(nsZipQueueItem* aItem, + PRBool* complete) +{ + if (aItem->mFile) { + PRBool exists; + nsresult rv = aItem->mFile->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + + if (!exists) return NS_ERROR_FILE_NOT_FOUND; + + PRBool isdir; + rv = aItem->mFile->IsDirectory(&isdir); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aItem->mFile->GetLastModifiedTime(&aItem->mModTime); + NS_ENSURE_SUCCESS(rv, rv); + aItem->mModTime *= PR_USEC_PER_MSEC; + + if (!isdir) { + // Set up for fall through to stream reader + rv = NS_NewLocalFileInputStream(getter_AddRefs(aItem->mStream), + aItem->mFile); + NS_ENSURE_SUCCESS(rv, rv); + } + // If a dir then this will fall through to the plain dir addition + } + + if (aItem->mStream) { + nsRefPtr header = new nsZipHeader(); + NS_ENSURE_TRUE(header, NS_ERROR_OUT_OF_MEMORY); + + header->Init(aItem->mZipEntry, aItem->mModTime, ZIP_ATTRS_FILE, + mCDSOffset); + nsresult rv = header->WriteFileHeader(mStream); + NS_ENSURE_SUCCESS(rv, rv); + + nsRefPtr stream = new nsZipDataStream(); + rv = stream->Init(this, mStream, header, aItem->mCompression); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), aItem->mStream, -1, + -1, 0, 0, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + + rv = pump->AsyncRead(stream, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } + + if (aItem->mChannel) { + nsRefPtr header = new nsZipHeader(); + NS_ENSURE_TRUE(header, NS_ERROR_OUT_OF_MEMORY); + + header->Init(aItem->mZipEntry, aItem->mModTime, ZIP_ATTRS_FILE, + mCDSOffset); + + nsRefPtr stream = new nsZipDataStream(); + NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY); + nsresult rv = stream->Init(this, mStream, header, aItem->mCompression); + NS_ENSURE_SUCCESS(rv, rv); + rv = aItem->mChannel->AsyncOpen(stream, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } + + // Must be plain directory addition + *complete = PR_TRUE; + return InternalAddEntryDirectory(aItem->mZipEntry, aItem->mModTime); +} + +inline nsresult nsZipWriter::BeginProcessingRemoval(PRInt32 aPos) +{ + // Open the zip file for reading + nsCOMPtr inputStream; + nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), + mFile); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr pump; + rv = NS_NewInputStreamPump(getter_AddRefs(pump), inputStream, -1, -1, 0, + 0, PR_TRUE); + if (NS_FAILED(rv)) { + inputStream->Close(); + return rv; + } + nsCOMPtr listener; + rv = NS_NewSimpleStreamListener(getter_AddRefs(listener), mStream, this); + if (NS_FAILED(rv)) { + inputStream->Close(); + return rv; + } + + nsCOMPtr seekable = do_QueryInterface(mStream); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + mHeaders[aPos]->mOffset); + if (NS_FAILED(rv)) { + inputStream->Close(); + return rv; + } + + PRUint32 shift = (mHeaders[aPos + 1]->mOffset - + mHeaders[aPos]->mOffset); + mCDSOffset -= shift; + PRInt32 pos2 = aPos + 1; + while (pos2 < mHeaders.Count()) { + mEntryHash.Put(mHeaders[pos2]->mName, pos2 - 1); + mHeaders[pos2]->mOffset -= shift; + pos2++; + } + + mEntryHash.Remove(mHeaders[aPos]->mName); + mHeaders.RemoveObjectAt(aPos); + mCDSDirty = PR_TRUE; + + rv = pump->AsyncRead(listener, nsnull); + if (NS_FAILED(rv)) { + inputStream->Close(); + Cleanup(); + return rv; + } + return NS_OK; +} + +/* + * Starts processing on the next item in the queue. + */ +void nsZipWriter::BeginProcessingNextItem() +{ + while (!mQueue.IsEmpty()) { + + nsZipQueueItem next = mQueue[0]; + mQueue.RemoveElementAt(0); + + if (next.mOperation == OPERATION_REMOVE) { + PRInt32 pos = -1; + if (mEntryHash.Get(next.mZipEntry, &pos)) { + if (pos < mHeaders.Count() - 1) { + nsresult rv = BeginProcessingRemoval(pos); + if (NS_FAILED(rv)) FinishQueue(rv); + return; + } + + mCDSOffset = mHeaders[pos]->mOffset; + nsresult rv = SeekCDS(); + if (NS_FAILED(rv)) { + FinishQueue(rv); + return; + } + mEntryHash.Remove(mHeaders[pos]->mName); + mHeaders.RemoveObjectAt(pos); + } + else { + FinishQueue(NS_ERROR_FILE_NOT_FOUND); + return; + } + } + else if (next.mOperation == OPERATION_ADD) { + if (mEntryHash.Get(next.mZipEntry, nsnull)) { + FinishQueue(NS_ERROR_FILE_ALREADY_EXISTS); + return; + } + + PRBool complete = PR_FALSE; + nsresult rv = BeginProcessingAddition(&next, &complete); + if (NS_FAILED(rv)) { + SeekCDS(); + FinishQueue(rv); + return; + } + if (!complete) + return; + } + } + + FinishQueue(NS_OK); +} + +/* + * Ends processing with the given status. + */ +void nsZipWriter::FinishQueue(nsresult aStatus) +{ + nsCOMPtr observer = mProcessObserver; + nsCOMPtr context = mProcessContext; + // Clean up everything first in case the observer decides to queue more + // things + mProcessObserver = nsnull; + mProcessContext = nsnull; + mInQueue = PR_FALSE; + + if (observer) + observer->OnStopRequest(nsnull, context, aStatus); +} diff --git a/modules/libjar/zipwriter/src/nsZipWriter.h b/modules/libjar/zipwriter/src/nsZipWriter.h new file mode 100644 index 000000000000..dc60fad810d0 --- /dev/null +++ b/modules/libjar/zipwriter/src/nsZipWriter.h @@ -0,0 +1,110 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mook + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#ifndef _nsZipWriter_h_ +#define _nsZipWriter_h_ + +#include "nsIZipWriter.h" +#include "nsIFileStreams.h" +#include "nsIBufferedStreams.h" +#include "nsIRequestObserver.h" +#include "nsZipHeader.h" +#include "nsCOMPtr.h" +#include "nsCOMArray.h" +#include "nsTArray.h" +#include "nsDataHashtable.h" + +#define ZIPWRITER_CONTRACTID "@mozilla.org/zipwriter;1" +#define ZIPWRITER_CLASSNAME "Zip Writer" +#define ZIPWRITER_CID { 0x430d416c, 0xa722, 0x4ad1, \ + { 0xbe, 0x98, 0xd9, 0xa4, 0x45, 0xf8, 0x5e, 0x3f } } + +#define OPERATION_ADD 0 +#define OPERATION_REMOVE 1 +struct nsZipQueueItem +{ +public: + PRUint32 mOperation; + nsCString mZipEntry; + nsCOMPtr mFile; + nsCOMPtr mChannel; + nsCOMPtr mStream; + PRTime mModTime; + PRInt32 mCompression; +}; + +class nsZipWriter : public nsIZipWriter, + public nsIRequestObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIZIPWRITER + NS_DECL_NSIREQUESTOBSERVER + + nsZipWriter(); + nsresult EntryCompleteCallback(nsZipHeader *aHeader, nsresult aStatus); + +private: + ~nsZipWriter(); + + PRUint32 mCDSOffset; + PRPackedBool mCDSDirty; + PRPackedBool mInQueue; + + nsCOMPtr mFile; + nsCOMPtr mProcessObserver; + nsCOMPtr mProcessContext; + nsCOMPtr mStream; + nsCOMArray mHeaders; + nsTArray mQueue; + nsDataHashtable mEntryHash; + nsCString mComment; + + nsresult SeekCDS(); + void Cleanup(); + nsresult ReadFile(nsIFile *aFile); + nsresult InternalAddEntryDirectory(const nsACString & aZipEntry, + PRTime aModTime); + nsresult BeginProcessingAddition(nsZipQueueItem* aItem, PRBool* complete); + nsresult BeginProcessingRemoval(PRInt32 aPos); + void BeginProcessingNextItem(); + void FinishQueue(nsresult aStatus); +}; + +#endif diff --git a/modules/libjar/zipwriter/test/Makefile.in b/modules/libjar/zipwriter/test/Makefile.in new file mode 100644 index 000000000000..6afead1d5111 --- /dev/null +++ b/modules/libjar/zipwriter/test/Makefile.in @@ -0,0 +1,51 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Zip Writer Component. +# +# The Initial Developer of the Original Code is +# Dave Townsend . +# +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = test_zipwriter + +XPCSHELL_TESTS = \ + unit \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/modules/libjar/zipwriter/test/unit/data/test.png b/modules/libjar/zipwriter/test/unit/data/test.png new file mode 100644 index 000000000000..c648f7299ddb Binary files /dev/null and b/modules/libjar/zipwriter/test/unit/data/test.png differ diff --git a/modules/libjar/zipwriter/test/unit/data/test.txt b/modules/libjar/zipwriter/test/unit/data/test.txt new file mode 100644 index 000000000000..1040981a30c0 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/data/test.txt @@ -0,0 +1,5 @@ +This is a test text file for the zipwriter component. +It will be made available in the unit test directory. +It will also be compressed into a testcase zip file +made by a 3rd party zip tool to test the opening of +existing zip files. diff --git a/modules/libjar/zipwriter/test/unit/data/test.zip b/modules/libjar/zipwriter/test/unit/data/test.zip new file mode 100644 index 000000000000..96581fe8b598 Binary files /dev/null and b/modules/libjar/zipwriter/test/unit/data/test.zip differ diff --git a/modules/libjar/zipwriter/test/unit/head_zipwriter.js b/modules/libjar/zipwriter/test/unit/head_zipwriter.js new file mode 100644 index 000000000000..ada082380d78 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/head_zipwriter.js @@ -0,0 +1,79 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +const NS_OS_TEMP_DIR = "TmpD"; +const Ci = Components.interfaces; +const Cc = Components.classes; +const NS_ERROR_IN_PROGRESS = 2152398863; + +const PR_RDONLY = 0x01 +const PR_WRONLY = 0x02 +const PR_RDWR = 0x04 +const PR_CREATE_FILE = 0x08 +const PR_APPEND = 0x10 +const PR_TRUNCATE = 0x20 +const PR_SYNC = 0x40 +const PR_EXCL = 0x80 + +const ZIP_EOCDR_HEADER_SIZE = 22; +const ZIP_FILE_HEADER_SIZE = 30; +const ZIP_CDS_HEADER_SIZE = 46; +const ZIP_METHOD_STORE = 0 +const ZIP_METHOD_DEFLATE = 8 + +const PR_USEC_PER_MSEC = 1000; + +// ZIP times are stored at a 2 second resolution. +const TIME_RESOLUTION = 2000; + +const DATA_DIR = "modules/libjar/zipwriter/test/unit/data/"; + +var ZipWriter = Components.Constructor("@mozilla.org/zipwriter;1", + "nsIZipWriter"); +var ZipReader = Components.Constructor("@mozilla.org/libjar/zip-reader;1", + "nsIZipReader", "open"); + +var dirSvc = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties); +var tmpDir = dirSvc.get(NS_OS_TEMP_DIR, Ci.nsIFile); +var tmpFile = tmpDir.clone(); +tmpFile.append("zipwriter-test.zip"); +if (tmpFile.exists()) + tmpFile.remove(true); + +var zipW = new ZipWriter(); diff --git a/modules/libjar/zipwriter/test/unit/tail_zipwriter.js b/modules/libjar/zipwriter/test/unit/tail_zipwriter.js new file mode 100644 index 000000000000..1d54268a8342 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/tail_zipwriter.js @@ -0,0 +1,47 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +try { + zipW.close(); +} +catch (e) { + // Just ignore a failure here and attempt to delete the file anyway. +} + +if (tmpFile.exists()) + tmpFile.remove(true); diff --git a/modules/libjar/zipwriter/test/unit/test_asyncadd.js b/modules/libjar/zipwriter/test/unit/test_asyncadd.js new file mode 100644 index 000000000000..c6792d408091 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_asyncadd.js @@ -0,0 +1,108 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +// Values taken from using zipinfo to list the test.zip contents +var TESTS = [ + { + name: "test.txt", + size: 232, + crc: 0x0373ac26 + }, + { + name: "test.png", + size: 3402, + crc: 0x504a5c30 + } +]; + +var size = 0; + +var observer = { + onStartRequest: function(request, context) + { + }, + + onStopRequest: function(request, context, status) + { + do_check_eq(status, Components.results.NS_OK); + + zipW.close(); + size += ZIP_EOCDR_HEADER_SIZE; + + do_check_eq(size, tmpFile.fileSize); + + // Test the stored data with the zipreader + var zipR = new ZipReader(tmpFile); + + for (var i = 0; i < TESTS.length; i++) { + do_check_true(zipR.hasEntry(TESTS[i].name)); + + var source = do_get_file(DATA_DIR + TESTS[i].name); + var entry = zipR.getEntry(TESTS[i].name); + 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); + + zipR.test(TESTS[i].name); + } + + zipR.close(); + do_test_finished(); + } +}; + +function run_test() +{ + zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + + for (var i = 0; i < TESTS.length; i++) { + var source = do_get_file(DATA_DIR+TESTS[i].name); + zipW.addEntryFile(TESTS[i].name, Ci.nsIZipWriter.COMPRESSION_NONE, source, + true); + size += ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + + (TESTS[i].name.length*2) + TESTS[i].size; + } + do_test_pending(); + zipW.processQueue(observer, null); + do_check_true(zipW.inQueue); +} diff --git a/modules/libjar/zipwriter/test/unit/test_asyncbadadd.js b/modules/libjar/zipwriter/test/unit/test_asyncbadadd.js new file mode 100644 index 000000000000..8634e32827c3 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_asyncbadadd.js @@ -0,0 +1,68 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +const FILENAME = "missing.txt"; + +var observer = { + onStartRequest: function(request, context) + { + }, + + onStopRequest: function(request, context, status) + { + do_check_eq(status, Components.results.NS_ERROR_FILE_NOT_FOUND); + zipW.close(); + do_check_eq(ZIP_EOCDR_HEADER_SIZE, tmpFile.fileSize); + do_test_finished(); + } +}; + +function run_test() +{ + zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + + var source = tmpDir.clone(); + source.append(FILENAME); + zipW.addEntryFile(FILENAME, Ci.nsIZipWriter.COMPRESSION_NONE, source, true); + + do_test_pending(); + zipW.processQueue(observer, null); + + // With nothing to actually do the queue would have completed immediately + do_check_false(zipW.inQueue); +} diff --git a/modules/libjar/zipwriter/test/unit/test_asyncbadremove.js b/modules/libjar/zipwriter/test/unit/test_asyncbadremove.js new file mode 100644 index 000000000000..90f00af8d706 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_asyncbadremove.js @@ -0,0 +1,64 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +const FILENAME = "missing.txt"; + +var observer = { + onStartRequest: function(request, context) + { + }, + + onStopRequest: function(request, context, status) + { + do_check_eq(status, Components.results.NS_ERROR_FILE_NOT_FOUND); + zipW.close(); + do_check_eq(ZIP_EOCDR_HEADER_SIZE, tmpFile.fileSize); + do_test_finished(); + } +}; + +function run_test() +{ + zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + zipW.removeEntry(FILENAME, true); + do_test_pending(); + zipW.processQueue(observer, null); + + // With nothing to actually do the queue would have completed immediately + do_check_false(zipW.inQueue); +} diff --git a/modules/libjar/zipwriter/test/unit/test_asyncremove.js b/modules/libjar/zipwriter/test/unit/test_asyncremove.js new file mode 100644 index 000000000000..89bfc2ee5331 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_asyncremove.js @@ -0,0 +1,79 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +var TESTS = [ + "test.txt", + "test.png" +]; + +var observer = { + onStartRequest: function(request, context) + { + }, + + onStopRequest: function(request, context, status) + { + do_check_eq(status, Components.results.NS_OK); + + zipW.close(); + + // Empty zip file should just be the end of central directory marker + do_check_eq(tmpFile.fileSize, ZIP_EOCDR_HEADER_SIZE); + do_test_finished(); + } +}; + +function run_test() +{ + // Copy our test zip to the tmp dir so we can modify it + var testzip = do_get_file(DATA_DIR + "test.zip"); + testzip.copyTo(tmpDir, tmpFile.leafName); + + do_check_true(tmpFile.exists()); + + zipW.open(tmpFile, PR_RDWR); + + for (var i = 0; i < TESTS.length; i++) { + do_check_true(zipW.hasEntry(TESTS[i])); + zipW.removeEntry(TESTS[i], true); + } + + do_test_pending(); + zipW.processQueue(observer, null); + do_check_true(zipW.inQueue); +} diff --git a/modules/libjar/zipwriter/test/unit/test_createempty.js b/modules/libjar/zipwriter/test/unit/test_createempty.js new file mode 100644 index 000000000000..9c4f63daf1d4 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_createempty.js @@ -0,0 +1,49 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +function run_test() +{ + zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + zipW.close(); + + // Should have created a zip file + do_check_true(tmpFile.exists()); + + // Empty zip file should just be the end of central directory marker + do_check_eq(tmpFile.fileSize, ZIP_EOCDR_HEADER_SIZE); +} diff --git a/modules/libjar/zipwriter/test/unit/test_deflatedata.js b/modules/libjar/zipwriter/test/unit/test_deflatedata.js new file mode 100644 index 000000000000..8f87acbd4917 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_deflatedata.js @@ -0,0 +1,87 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +const DATA = "ZIP WRITER TEST DATA"; +const FILENAME = "test.txt"; +const CRC = 0xe6164331; +const time = Date.now(); + +function run_test() +{ + zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + + // Shouldn't be there to start with. + do_check_false(zipW.hasEntry(FILENAME)); + + do_check_false(zipW.inQueue); + + var stream = Cc["@mozilla.org/io/string-input-stream;1"] + .createInstance(Ci.nsIStringInputStream); + stream.setData(DATA, DATA.length); + zipW.addEntryStream(FILENAME, time * PR_USEC_PER_MSEC, + Ci.nsIZipWriter.COMPRESSION_BEST, stream, false); + + var entry = zipW.getEntry(FILENAME); + + do_check_true(entry != null); + + // Check entry seems right. + 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); + + zipW.close(); + + // Test the stored data with the zipreader + var zipR = new ZipReader(tmpFile); + do_check_true(zipR.hasEntry(FILENAME)); + + zipR.test(FILENAME); + + var stream = Cc["@mozilla.org/scriptableinputstream;1"] + .createInstance(Ci.nsIScriptableInputStream); + stream.init(zipR.getInputStream(FILENAME)); + var result = stream.read(DATA.length); + stream.close(); + zipR.close(); + + do_check_eq(result, DATA); +} diff --git a/modules/libjar/zipwriter/test/unit/test_directory.js b/modules/libjar/zipwriter/test/unit/test_directory.js new file mode 100644 index 000000000000..78560ba01543 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_directory.js @@ -0,0 +1,60 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +const DIRNAME1 = "test"; +const DIRNAME1_CORRECT = "test/"; +const DIRNAME2 = "test2/"; +const time = Date.now(); + +function run_test() +{ + zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + + zipW.addEntryDirectory(DIRNAME1, time * PR_USEC_PER_MSEC, false); + do_check_false(zipW.hasEntry(DIRNAME1)); + do_check_true(zipW.hasEntry(DIRNAME1_CORRECT)); + var entry = zipW.getEntry(DIRNAME1_CORRECT); + do_check_true(entry.isDirectory); + + zipW.addEntryDirectory(DIRNAME2, time * PR_USEC_PER_MSEC, false); + do_check_true(zipW.hasEntry(DIRNAME2)); + entry = zipW.getEntry(DIRNAME2); + do_check_true(entry.isDirectory); + + zipW.close(); +} diff --git a/modules/libjar/zipwriter/test/unit/test_editexisting.js b/modules/libjar/zipwriter/test/unit/test_editexisting.js new file mode 100644 index 000000000000..23e1d1ef844d --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_editexisting.js @@ -0,0 +1,98 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +// Values taken from using zipinfo to list the test.zip contents +var TESTS = [ + { + name: "test.txt", + size: 232, + crc: 0x0373ac26, + time: new Date(2007, 4, 1, 21, 44, 56) + }, + { + name: "test.png", + size: 3402, + crc: 0x504a5c30, + time: new Date(2007, 4, 1, 21, 49, 40) + } +]; +var BADENTRY = "unknown.txt"; + +function run_test() +{ + // Copy our test zip to the tmp dir so we can modify it + var testzip = do_get_file(DATA_DIR + "test.zip"); + testzip.copyTo(tmpDir, tmpFile.leafName); + + do_check_true(tmpFile.exists()); + + zipW.open(tmpFile, PR_RDWR); + + for (var i = 0; i < TESTS.length; i++) { + do_check_true(zipW.hasEntry(TESTS[i].name)); + var entry = zipW.getEntry(TESTS[i].name); + do_check_true(entry != null); + + 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); + } + + try { + zipW.removeEntry(BADENTRY, false); + do_throw("shouldn't be able to remove an entry that doesn't exist"); + } + catch (e) { + do_check_eq(e.result, Components.results.NS_ERROR_FILE_NOT_FOUND); + } + + for (var i = 0; i < TESTS.length; i++) { + zipW.removeEntry(TESTS[i].name, false); + } + + zipW.close(); + + // Certain platforms cache the file size so get a fresh file to check. + tmpFile = tmpFile.clone(); + + // Empty zip file should just be the end of central directory marker + do_check_eq(tmpFile.fileSize, ZIP_EOCDR_HEADER_SIZE); +} diff --git a/modules/libjar/zipwriter/test/unit/test_storedata.js b/modules/libjar/zipwriter/test/unit/test_storedata.js new file mode 100644 index 000000000000..1c84a9f813b3 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_storedata.js @@ -0,0 +1,111 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +const DATA = "ZIP WRITER TEST DATA"; +const FILENAME = "test.txt"; +const FILENAME2 = "test2.txt"; +const CRC = 0xe6164331; +const time = Date.now(); + +function testpass(source) +{ + // Should exist. + do_check_true(source.hasEntry(FILENAME)); + + var entry = source.getEntry(FILENAME); + do_check_neq(entry, null); + + do_check_false(entry.isDirectory); + + // 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); + + // File size should match our data size. + do_check_eq(entry.realSize, DATA.length); + // When stored sizes should match. + do_check_eq(entry.size, entry.realSize); + + // Check that the CRC is accurate + do_check_eq(entry.CRC32, CRC); +} + +function run_test() +{ + zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + + // Shouldn't be there to start with. + do_check_false(zipW.hasEntry(FILENAME)); + + do_check_false(zipW.inQueue); + + var stream = Cc["@mozilla.org/io/string-input-stream;1"] + .createInstance(Ci.nsIStringInputStream); + stream.setData(DATA, DATA.length); + zipW.addEntryStream(FILENAME, time * PR_USEC_PER_MSEC, + Ci.nsIZipWriter.COMPRESSION_NONE, stream, false); + + // Check that zip state is right at this stage. + testpass(zipW); + zipW.close(); + + do_check_eq(tmpFile.fileSize, + DATA.length + ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + + (FILENAME.length * 2) + ZIP_EOCDR_HEADER_SIZE); + + // Check to see if we get the same results loading afresh. + zipW.open(tmpFile, PR_RDWR); + testpass(zipW); + zipW.close(); + + // Test the stored data with the zipreader + var zipR = new ZipReader(tmpFile); + testpass(zipR); + zipR.test(FILENAME); + var stream = Cc["@mozilla.org/scriptableinputstream;1"] + .createInstance(Ci.nsIScriptableInputStream); + stream.init(zipR.getInputStream(FILENAME)); + var result = stream.read(DATA.length); + stream.close(); + zipR.close(); + + do_check_eq(result, DATA); +} diff --git a/modules/libjar/zipwriter/test/unit/test_sync.js b/modules/libjar/zipwriter/test/unit/test_sync.js new file mode 100644 index 000000000000..4a6862e89baa --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_sync.js @@ -0,0 +1,92 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +// Values taken from using zipinfo to list the test.zip contents +var TESTS = [ + { + name: "test.txt", + size: 232, + crc: 0x0373ac26 + }, + { + name: "test.png", + size: 3402, + crc: 0x504a5c30 + } +]; + +function run_test() +{ + zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + + var size = 0; + for (var i = 0; i < TESTS.length; i++) { + var source = do_get_file(DATA_DIR + TESTS[i].name); + zipW.addEntryFile(TESTS[i].name, Ci.nsIZipWriter.COMPRESSION_NONE, source, + false); + size += ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE + + (TESTS[i].name.length*2) + TESTS[i].size; + } + + zipW.close(); + size += ZIP_EOCDR_HEADER_SIZE; + + do_check_eq(size, tmpFile.fileSize); + + // Test the stored data with the zipreader + var zipR = new ZipReader(tmpFile); + + for (var i = 0; i < TESTS.length; i++) { + var source = do_get_file(DATA_DIR + TESTS[i].name); + do_check_true(zipR.hasEntry(TESTS[i].name)); + + var entry = zipR.getEntry(TESTS[i].name); + 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); + + zipR.test(TESTS[i].name); + } + + zipR.close(); +} diff --git a/modules/libjar/zipwriter/test/unit/test_undochange.js b/modules/libjar/zipwriter/test/unit/test_undochange.js new file mode 100644 index 000000000000..9d18db0dd2a8 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_undochange.js @@ -0,0 +1,74 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +// Values taken from using zipinfo to list the test.zip contents +var TESTS = [ + "test.txt", + "test.png" +]; + +function run_test() +{ + zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + + for (var i = 0; i < TESTS.length; i++) { + var source = do_get_file(DATA_DIR + TESTS[i]); + zipW.addEntryFile(TESTS[i], Ci.nsIZipWriter.COMPRESSION_NONE, source, + false); + } + + try { + var source = do_get_file(DATA_DIR + TESTS[0]); + zipW.addEntryFile(TESTS[0], Ci.nsIZipWriter.COMPRESSION_NONE, source, + false); + do_throw("Should not be able to add the same file twice"); + } + catch (e) { + do_check_eq(e.result, Components.results.NS_ERROR_FILE_ALREADY_EXISTS); + } + + // Remove all the tests and see if we are left with an empty zip + for (var i = 0; i < TESTS.length; i++) { + zipW.removeEntry(TESTS[i], false); + } + + zipW.close(); + + // Empty zip file should just be the end of central directory marker + do_check_eq(tmpFile.fileSize, ZIP_EOCDR_HEADER_SIZE); +} diff --git a/modules/libjar/zipwriter/test/unit/test_zipcomment.js b/modules/libjar/zipwriter/test/unit/test_zipcomment.js new file mode 100644 index 000000000000..3b05ea1fdb28 --- /dev/null +++ b/modules/libjar/zipwriter/test/unit/test_zipcomment.js @@ -0,0 +1,67 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Zip Writer Component. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +const DATA = "ZIP WRITER TEST COMMENT"; +const DATA2 = "ANOTHER ONE"; + +function run_test() +{ + zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + zipW.comment = DATA; + zipW.close(); + + // Should have created a zip file + do_check_true(tmpFile.exists()); + + // Empty zip file should just be the end of central directory marker + // and comment + do_check_eq(tmpFile.fileSize, ZIP_EOCDR_HEADER_SIZE + DATA.length); + + zipW.open(tmpFile, PR_RDWR); + // Should have the set comment + do_check_eq(zipW.comment, DATA); + zipW.comment = DATA2; + zipW.close(); + + // Certain platforms cache the file size so get a fresh file to check. + tmpFile = tmpFile.clone(); + + // Empty zip file should just be the end of central directory marker + // and comment. This should now be shorter + do_check_eq(tmpFile.fileSize, ZIP_EOCDR_HEADER_SIZE + DATA2.length); +} diff --git a/toolkit/library/libxul-config.mk b/toolkit/library/libxul-config.mk index e409e307d6f0..09d441181708 100644 --- a/toolkit/library/libxul-config.mk +++ b/toolkit/library/libxul-config.mk @@ -339,6 +339,11 @@ DEFINES += -DMOZ_SPELLCHECK COMPONENT_LIBS += spellchecker endif +ifdef MOZ_ZIPWRITER +DEFINES += -DMOZ_ZIPWRITER +COMPONENT_LIBS += zipwriter +endif + ifneq (,$(filter layout-debug,$(MOZ_EXTENSIONS))) COMPONENT_LIBS += gkdebug endif diff --git a/toolkit/library/nsStaticXULComponents.cpp b/toolkit/library/nsStaticXULComponents.cpp index bf5aa94af897..d5255419173a 100644 --- a/toolkit/library/nsStaticXULComponents.cpp +++ b/toolkit/library/nsStaticXULComponents.cpp @@ -222,6 +222,12 @@ #define STORAGE_MODULE #endif +#ifdef MOZ_ZIPWRITER +#define ZIPWRITER_MODULE MODULE(ZipWriterModule) +#else +#define ZIPWRITER_MODULE +#endif + #ifdef MOZ_PLACES #define PLACES_MODULES \ MODULE(nsPlacesModule) @@ -268,6 +274,7 @@ AUTH_MODULE \ IPC_MODULE \ MODULE(nsJarModule) \ + ZIPWRITER_MODULE \ MODULE(nsPrefModule) \ MODULE(nsSecurityManagerModule) \ RDF_MODULE \ diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index 1b6d720e8aa0..e5215f58fd7c 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -840,6 +840,15 @@ if [ "$MOZ_COMPOSER" ]; then " fi +if [ "$MOZ_ZIPWRITER" ]; then + add_makefiles " + modules/libjar/zipwriter/Makefile + modules/libjar/zipwriter/public/Makefile + modules/libjar/zipwriter/src/Makefile + modules/libjar/zipwriter/test/Makefile + " +fi + if [ "$MOZ_STORAGE" ]; then add_makefiles " db/sqlite3/src/Makefile