mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-01 04:47:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
1192
modules/libjar/appnote.txt
Normal file
1192
modules/libjar/appnote.txt
Normal file
File diff suppressed because it is too large
Load diff
47
modules/libjar/moz.build
Normal file
47
modules/libjar/moz.build
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG['MOZ_ZIPWRITER']:
|
||||
DIRS += ['zipwriter']
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/chrome/chrome.ini']
|
||||
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIJARChannel.idl',
|
||||
'nsIJARProtocolHandler.idl',
|
||||
'nsIJARURI.idl',
|
||||
'nsIZipReader.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'jar'
|
||||
|
||||
EXPORTS += [
|
||||
'nsJARURI.h',
|
||||
'nsZipArchive.h',
|
||||
'zipstruct.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'nsJARProtocolHandler.cpp',
|
||||
'nsJARURI.cpp',
|
||||
]
|
||||
|
||||
# These files cannot be built in unified mode because they rely on plarena.h.
|
||||
SOURCES += [
|
||||
'nsJAR.cpp',
|
||||
'nsJARChannel.cpp',
|
||||
'nsJARFactory.cpp',
|
||||
'nsJARInputStream.cpp',
|
||||
'nsZipArchive.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
32
modules/libjar/nsIJARChannel.idl
Normal file
32
modules/libjar/nsIJARChannel.idl
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIChannel.idl"
|
||||
|
||||
interface nsIFile;
|
||||
interface nsIZipEntry;
|
||||
|
||||
[scriptable, builtinclass, uuid(e72b179b-d5df-4d87-b5de-fd73a65c60f6)]
|
||||
interface nsIJARChannel : nsIChannel
|
||||
{
|
||||
/**
|
||||
* Returns TRUE if the JAR file is not safe (if the content type reported
|
||||
* by the server for a remote JAR is not of an expected type). Scripting,
|
||||
* redirects, and plugins should be disabled when loading from this
|
||||
* channel.
|
||||
*/
|
||||
[infallible] readonly attribute boolean isUnsafe;
|
||||
|
||||
/**
|
||||
* Returns the JAR file. May be null if the jar is remote.
|
||||
*/
|
||||
readonly attribute nsIFile jarFile;
|
||||
|
||||
/**
|
||||
* Returns the zip entry if the file is synchronously accessible.
|
||||
* This will work even without opening the channel.
|
||||
*/
|
||||
readonly attribute nsIZipEntry zipEntry;
|
||||
};
|
||||
10
modules/libjar/nsIJARFactory.h
Normal file
10
modules/libjar/nsIJARFactory.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
#ifndef nsIJARFactory_h__
|
||||
#define nsIJARFactory_h__
|
||||
|
||||
#endif // nsIJARFactory_h__
|
||||
17
modules/libjar/nsIJARProtocolHandler.idl
Normal file
17
modules/libjar/nsIJARProtocolHandler.idl
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIProtocolHandler.idl"
|
||||
|
||||
interface nsIZipReaderCache;
|
||||
|
||||
[scriptable, uuid(92c3b42c-98c4-11d3-8cd9-0060b0fc14a3)]
|
||||
interface nsIJARProtocolHandler : nsIProtocolHandler {
|
||||
|
||||
/**
|
||||
* JARCache contains the collection of open jar files.
|
||||
*/
|
||||
readonly attribute nsIZipReaderCache JARCache;
|
||||
};
|
||||
38
modules/libjar/nsIJARURI.idl
Normal file
38
modules/libjar/nsIJARURI.idl
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIURL.idl"
|
||||
|
||||
/**
|
||||
* JAR URLs have the following syntax
|
||||
*
|
||||
* jar:<jar-file-uri>!/<jar-entry>
|
||||
*
|
||||
* EXAMPLE: jar:http://www.big.com/blue.jar!/ocean.html
|
||||
*
|
||||
* The nsIURL methods operate on the <jar-entry> part of the spec.
|
||||
*/
|
||||
[scriptable, uuid(646a508c-f786-4e14-be6d-8dda2a633c60)]
|
||||
interface nsIJARURI : nsIURL {
|
||||
|
||||
/**
|
||||
* Returns the root URI (the one for the actual JAR file) for this JAR
|
||||
* (e.g., http://www.big.com/blue.jar).
|
||||
*/
|
||||
readonly attribute nsIURI JARFile;
|
||||
|
||||
/**
|
||||
* Returns the entry specified for this JAR URI (e.g., "ocean.html"). This
|
||||
* value may contain %-escaped byte sequences.
|
||||
*/
|
||||
attribute AUTF8String JAREntry;
|
||||
|
||||
/**
|
||||
* Create a clone of the JAR URI with a new root URI (the URI for the
|
||||
* actual JAR file).
|
||||
*/
|
||||
nsIJARURI cloneWithJARFile(in nsIURI jarFile);
|
||||
};
|
||||
273
modules/libjar/nsIZipReader.idl
Normal file
273
modules/libjar/nsIZipReader.idl
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
%{C++
|
||||
struct PRFileDesc;
|
||||
%}
|
||||
|
||||
[ptr] native PRFileDescStar(PRFileDesc);
|
||||
|
||||
interface nsIUTF8StringEnumerator;
|
||||
interface nsIInputStream;
|
||||
interface nsIFile;
|
||||
interface nsIX509Cert;
|
||||
|
||||
[scriptable, uuid(fad6f72f-13d8-4e26-9173-53007a4afe71)]
|
||||
interface nsIZipEntry : nsISupports
|
||||
{
|
||||
/**
|
||||
* The type of compression used for the item. The possible values and
|
||||
* their meanings are defined in the zip file specification at
|
||||
* http://www.pkware.com/business_and_developers/developer/appnote/
|
||||
*/
|
||||
readonly attribute unsigned short compression;
|
||||
/**
|
||||
* The compressed size of the data in the item.
|
||||
*/
|
||||
readonly attribute unsigned long size;
|
||||
/**
|
||||
* The uncompressed size of the data in the item.
|
||||
*/
|
||||
readonly attribute unsigned long realSize;
|
||||
/**
|
||||
* The CRC-32 hash of the file in the entry.
|
||||
*/
|
||||
readonly attribute unsigned long CRC32;
|
||||
/**
|
||||
* True if the name of the entry ends with '/' and false otherwise.
|
||||
*/
|
||||
readonly attribute boolean isDirectory;
|
||||
/**
|
||||
* The time at which this item was last modified.
|
||||
*/
|
||||
readonly attribute PRTime lastModifiedTime;
|
||||
/**
|
||||
* Use this attribute to determine whether this item is an actual zip entry
|
||||
* or is one synthesized for part of a real entry's path. A synthesized
|
||||
* entry represents a directory within the zip file which has no
|
||||
* corresponding entry within the zip file. For example, the entry for the
|
||||
* directory foo/ in a zip containing exactly one entry for foo/bar.txt
|
||||
* is synthetic. If the zip file contains an actual entry for a directory,
|
||||
* this attribute will be false for the nsIZipEntry for that directory.
|
||||
* It is impossible for a file to be synthetic.
|
||||
*/
|
||||
readonly attribute boolean isSynthetic;
|
||||
/**
|
||||
* The UNIX style file permissions of this item.
|
||||
*/
|
||||
readonly attribute unsigned long permissions;
|
||||
};
|
||||
|
||||
[scriptable, uuid(9ba4ef54-e0a0-4f65-9d23-128482448885)]
|
||||
interface nsIZipReader : nsISupports
|
||||
{
|
||||
/**
|
||||
* Opens a zip file for reading.
|
||||
* It is allowed to open with another file,
|
||||
* but it needs to be closed first with close().
|
||||
*/
|
||||
void open(in nsIFile zipFile);
|
||||
|
||||
/**
|
||||
* Opens a zip file inside a zip file for reading.
|
||||
*/
|
||||
void openInner(in nsIZipReader zipReader, in AUTF8String zipEntry);
|
||||
|
||||
/**
|
||||
* Opens a zip file stored in memory; the file attribute will be null.
|
||||
*
|
||||
* The ZipReader does not copy or take ownership of this memory; the
|
||||
* caller must ensure that it is valid and unmodified until the
|
||||
* ZipReader is closed or destroyed, and must free the memory as
|
||||
* appropriate afterwards.
|
||||
*/
|
||||
void openMemory(in voidPtr aData, in unsigned long aLength);
|
||||
|
||||
/**
|
||||
* The file that represents the zip with which this zip reader was
|
||||
* initialized. This will be null if there is no underlying file.
|
||||
*/
|
||||
readonly attribute nsIFile file;
|
||||
|
||||
/**
|
||||
* Closes a zip reader. Subsequent attempts to extract files or read from
|
||||
* its input stream will result in an error.
|
||||
*
|
||||
* Subsequent attempts to access a nsIZipEntry obtained from this zip
|
||||
* reader will cause unspecified behavior.
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Tests the integrity of the archive by performing a CRC check
|
||||
* on each item expanded into memory. If an entry is specified
|
||||
* the integrity of only that item is tested. If null (javascript)
|
||||
* or EmptyCString() (c++) is passed in the integrity of all items
|
||||
* in the archive are tested.
|
||||
*/
|
||||
void test(in AUTF8String aEntryName);
|
||||
|
||||
/**
|
||||
* Extracts a zip entry into a local file specified by outFile.
|
||||
* The entry must be stored in the zip in either uncompressed or
|
||||
* DEFLATE-compressed format for the extraction to be successful.
|
||||
* If the entry is a directory, the directory will be extracted
|
||||
* non-recursively.
|
||||
*/
|
||||
void extract(in AUTF8String zipEntry, in nsIFile outFile);
|
||||
|
||||
/**
|
||||
* Returns a nsIZipEntry describing a specified zip entry.
|
||||
*/
|
||||
nsIZipEntry getEntry(in AUTF8String zipEntry);
|
||||
|
||||
/**
|
||||
* Checks whether the zipfile contains an entry specified by entryName.
|
||||
*/
|
||||
boolean hasEntry(in AUTF8String zipEntry);
|
||||
|
||||
/**
|
||||
* Returns a string enumerator containing the matching entry names.
|
||||
*
|
||||
* @param aPattern
|
||||
* A regular expression used to find matching entries in the zip file.
|
||||
* Set this parameter to null (javascript) or EmptyCString() (c++) or "*"
|
||||
* to get all entries; otherwise, use the
|
||||
* following syntax:
|
||||
*
|
||||
* o * matches anything
|
||||
* o ? matches one character
|
||||
* o $ matches the end of the string
|
||||
* o [abc] matches one occurrence of a, b, or c. The only character that
|
||||
* must be escaped inside the brackets is ]. ^ and - must never
|
||||
* appear in the first and second positions within the brackets,
|
||||
* respectively. (In the former case, the behavior specified for
|
||||
* '[^az]' will happen.)
|
||||
* o [a-z] matches any character between a and z. The characters a and z
|
||||
* must either both be letters or both be numbers, with the
|
||||
* character represented by 'a' having a lower ASCII value than
|
||||
* the character represented by 'z'.
|
||||
* o [^az] matches any character except a or z. If ] is to appear inside
|
||||
* the brackets as a character to not match, it must be escaped.
|
||||
* o pat~pat2 returns matches to the pattern 'pat' which do not also match
|
||||
* the pattern 'pat2'. This may be used to perform filtering
|
||||
* upon the results of one pattern to remove all matches which
|
||||
* also match another pattern. For example, because '*'
|
||||
* matches any string and '*z*' matches any string containing a
|
||||
* 'z', '*~*z*' will match all strings except those containing
|
||||
* a 'z'. Note that a pattern may not use '~' multiple times,
|
||||
* so a string such as '*~*z*~*y*' is not a valid pattern.
|
||||
* o (foo|bar) will match either the pattern foo or the pattern bar.
|
||||
* Neither of the patterns foo or bar may use the 'pat~pat2'
|
||||
* syntax described immediately above.
|
||||
* o \ will escape a special character. Escaping is required for all
|
||||
* special characters unless otherwise specified.
|
||||
* o All other characters match case-sensitively.
|
||||
*
|
||||
* An aPattern not conforming to this syntax has undefined behavior.
|
||||
*
|
||||
* @throws NS_ERROR_ILLEGAL_VALUE on many but not all invalid aPattern
|
||||
* values.
|
||||
*/
|
||||
nsIUTF8StringEnumerator findEntries(in AUTF8String aPattern);
|
||||
|
||||
/**
|
||||
* Returns an input stream containing the contents of the specified zip
|
||||
* entry.
|
||||
* @param zipEntry the name of the entry to open the stream from
|
||||
*/
|
||||
nsIInputStream getInputStream(in AUTF8String zipEntry);
|
||||
|
||||
/**
|
||||
* Returns an input stream containing the contents of the specified zip
|
||||
* entry. If the entry refers to a directory (ends with '/'), a directory stream
|
||||
* is opened, otherwise the contents of the file entry is returned.
|
||||
* @param aJarSpec the Spec of the URI for the JAR (only used for directory streams)
|
||||
* @param zipEntry the name of the entry to open the stream from
|
||||
*/
|
||||
nsIInputStream getInputStreamWithSpec(in AUTF8String aJarSpec, in AUTF8String zipEntry);
|
||||
|
||||
/**
|
||||
* Returns an object describing the entity which signed
|
||||
* an entry. parseManifest must be called first. If aEntryName is an
|
||||
* entry in the jar, getInputStream must be called after parseManifest.
|
||||
* If aEntryName is an external file which has meta-information
|
||||
* stored in the jar, verifyExternalFile (not yet implemented) must
|
||||
* be called before getPrincipal.
|
||||
*/
|
||||
nsIX509Cert getSigningCert(in AUTF8String aEntryName);
|
||||
|
||||
readonly attribute uint32_t manifestEntriesCount;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIZipReaderCache
|
||||
|
||||
[scriptable, uuid(31179807-9fcd-46c4-befa-2ade209a394b)]
|
||||
interface nsIZipReaderCache : nsISupports
|
||||
{
|
||||
/**
|
||||
* Initializes a new zip reader cache.
|
||||
* @param cacheSize - the number of released entries to maintain before
|
||||
* beginning to throw some out (note that the number of outstanding
|
||||
* entries can be much greater than this number -- this is the count
|
||||
* for those otherwise unused entries)
|
||||
*/
|
||||
void init(in unsigned long cacheSize);
|
||||
|
||||
/**
|
||||
* Returns a (possibly shared) nsIZipReader for an nsIFile.
|
||||
*
|
||||
* If the zip reader for given file is not in the cache, a new zip reader
|
||||
* is created, initialized, and opened (see nsIZipReader::init and
|
||||
* nsIZipReader::open). Otherwise the previously created zip reader is
|
||||
* returned.
|
||||
*
|
||||
* @note If someone called close() on the shared nsIZipReader, this method
|
||||
* will return the closed zip reader.
|
||||
*/
|
||||
nsIZipReader getZip(in nsIFile zipFile);
|
||||
|
||||
/**
|
||||
* returns true if this zipreader already has this file cached
|
||||
*/
|
||||
bool isCached(in nsIFile zipFile);
|
||||
|
||||
/**
|
||||
* Returns a (possibly shared) nsIZipReader for a zip inside another zip
|
||||
*
|
||||
* See getZip
|
||||
*/
|
||||
nsIZipReader getInnerZip(in nsIFile zipFile, in AUTF8String zipEntry);
|
||||
|
||||
/**
|
||||
* Returns the cached NSPR file descriptor of the file.
|
||||
* Note: currently not supported on Windows platform.
|
||||
*/
|
||||
PRFileDescStar getFd(in nsIFile zipFile);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
%{C++
|
||||
|
||||
#define NS_ZIPREADER_CID \
|
||||
{ /* 88e2fd0b-f7f4-480c-9483-7846b00e8dad */ \
|
||||
0x88e2fd0b, 0xf7f4, 0x480c, \
|
||||
{ 0x94, 0x83, 0x78, 0x46, 0xb0, 0x0e, 0x8d, 0xad } \
|
||||
}
|
||||
|
||||
#define NS_ZIPREADERCACHE_CID \
|
||||
{ /* 608b7f6f-4b60-40d6-87ed-d933bf53d8c1 */ \
|
||||
0x608b7f6f, 0x4b60, 0x40d6, \
|
||||
{ 0x87, 0xed, 0xd9, 0x33, 0xbf, 0x53, 0xd8, 0xc1 } \
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
1401
modules/libjar/nsJAR.cpp
Normal file
1401
modules/libjar/nsJAR.cpp
Normal file
File diff suppressed because it is too large
Load diff
224
modules/libjar/nsJAR.h
Normal file
224
modules/libjar/nsJAR.h
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsJAR_h_
|
||||
#define nsJAR_h_
|
||||
|
||||
#include "nscore.h"
|
||||
#include "prio.h"
|
||||
#include "plstr.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "prinrval.h"
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsStringEnumerator.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsIZipReader.h"
|
||||
#include "nsZipArchive.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsIX509Cert;
|
||||
class nsJARManifestItem;
|
||||
class nsZipReaderCache;
|
||||
|
||||
/* For mManifestStatus */
|
||||
typedef enum
|
||||
{
|
||||
JAR_MANIFEST_NOT_PARSED = 0,
|
||||
JAR_VALID_MANIFEST = 1,
|
||||
JAR_INVALID_SIG = 2,
|
||||
JAR_INVALID_UNKNOWN_CA = 3,
|
||||
JAR_INVALID_MANIFEST = 4,
|
||||
JAR_INVALID_ENTRY = 5,
|
||||
JAR_NO_MANIFEST = 6,
|
||||
JAR_NOT_SIGNED = 7
|
||||
} JARManifestStatusType;
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Class nsJAR declaration.
|
||||
* nsJAR serves as an XPCOM wrapper for nsZipArchive with the addition of
|
||||
* JAR manifest file parsing.
|
||||
*------------------------------------------------------------------------*/
|
||||
class nsJAR final : public nsIZipReader
|
||||
{
|
||||
// Allows nsJARInputStream to call the verification functions
|
||||
friend class nsJARInputStream;
|
||||
// Allows nsZipReaderCache to access mOuterZipEntry
|
||||
friend class nsZipReaderCache;
|
||||
|
||||
private:
|
||||
|
||||
virtual ~nsJAR();
|
||||
|
||||
public:
|
||||
|
||||
nsJAR();
|
||||
|
||||
NS_DEFINE_STATIC_CID_ACCESSOR( NS_ZIPREADER_CID )
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
NS_DECL_NSIZIPREADER
|
||||
|
||||
nsresult GetJarPath(nsACString& aResult);
|
||||
|
||||
PRIntervalTime GetReleaseTime() {
|
||||
return mReleaseTime;
|
||||
}
|
||||
|
||||
bool IsReleased() {
|
||||
return mReleaseTime != PR_INTERVAL_NO_TIMEOUT;
|
||||
}
|
||||
|
||||
void SetReleaseTime() {
|
||||
mReleaseTime = PR_IntervalNow();
|
||||
}
|
||||
|
||||
void ClearReleaseTime() {
|
||||
mReleaseTime = PR_INTERVAL_NO_TIMEOUT;
|
||||
}
|
||||
|
||||
void SetZipReaderCache(nsZipReaderCache* aCache) {
|
||||
mozilla::MutexAutoLock lock(mLock);
|
||||
mCache = aCache;
|
||||
}
|
||||
|
||||
nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc);
|
||||
|
||||
protected:
|
||||
typedef nsClassHashtable<nsCStringHashKey, nsJARManifestItem> ManifestDataHashtable;
|
||||
|
||||
//-- Private data members
|
||||
nsCOMPtr<nsIFile> mZipFile; // The zip/jar file on disk
|
||||
nsCString mOuterZipEntry; // The entry in the zip this zip is reading from
|
||||
RefPtr<nsZipArchive> mZip; // The underlying zip archive
|
||||
ManifestDataHashtable mManifestData; // Stores metadata for each entry
|
||||
bool mParsedManifest; // True if manifest has been parsed
|
||||
nsCOMPtr<nsIX509Cert> mSigningCert; // The entity which signed this file
|
||||
int16_t mGlobalStatus; // Global signature verification status
|
||||
PRIntervalTime mReleaseTime; // used by nsZipReaderCache for flushing entries
|
||||
nsZipReaderCache* mCache; // if cached, this points to the cache it's contained in
|
||||
mozilla::Mutex mLock; // protect mCache and mZip
|
||||
int64_t mMtime;
|
||||
int32_t mTotalItemsInManifest;
|
||||
bool mOpened;
|
||||
bool mIsOmnijar;
|
||||
|
||||
nsresult ParseManifest();
|
||||
void ReportError(const nsACString &aFilename, int16_t errorCode);
|
||||
nsresult LoadEntry(const nsACString &aFilename, char** aBuf,
|
||||
uint32_t* aBufLen = nullptr);
|
||||
int32_t ReadLine(const char** src);
|
||||
nsresult ParseOneFile(const char* filebuf, int16_t aFileType);
|
||||
nsresult VerifyEntry(nsJARManifestItem* aEntry, const char* aEntryData,
|
||||
uint32_t aLen);
|
||||
|
||||
nsresult CalculateDigest(const char* aInBuf, uint32_t aInBufLen,
|
||||
nsCString& digest);
|
||||
};
|
||||
|
||||
/**
|
||||
* nsJARItem
|
||||
*
|
||||
* An individual JAR entry. A set of nsJARItems matching a
|
||||
* supplied pattern are returned in a nsJAREnumerator.
|
||||
*/
|
||||
class nsJARItem : public nsIZipEntry
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIZIPENTRY
|
||||
|
||||
explicit nsJARItem(nsZipItem* aZipItem);
|
||||
|
||||
private:
|
||||
virtual ~nsJARItem() {}
|
||||
|
||||
uint32_t mSize; /* size in original file */
|
||||
uint32_t mRealsize; /* inflated size */
|
||||
uint32_t mCrc32;
|
||||
PRTime mLastModTime;
|
||||
uint16_t mCompression;
|
||||
uint32_t mPermissions;
|
||||
bool mIsDirectory;
|
||||
bool mIsSynthetic;
|
||||
};
|
||||
|
||||
/**
|
||||
* nsJAREnumerator
|
||||
*
|
||||
* Enumerates a list of files in a zip archive
|
||||
* (based on a pattern match in its member nsZipFind).
|
||||
*/
|
||||
class nsJAREnumerator final : public nsIUTF8StringEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIUTF8STRINGENUMERATOR
|
||||
|
||||
explicit nsJAREnumerator(nsZipFind *aFind)
|
||||
: mFind(aFind), mName(nullptr), mNameLen(0) {
|
||||
NS_ASSERTION(mFind, "nsJAREnumerator: Missing zipFind.");
|
||||
}
|
||||
|
||||
private:
|
||||
nsZipFind *mFind;
|
||||
const char* mName; // pointer to an name owned by mArchive -- DON'T delete
|
||||
uint16_t mNameLen;
|
||||
|
||||
~nsJAREnumerator() { delete mFind; }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(DEBUG_warren) || defined(DEBUG_jband)
|
||||
#define ZIP_CACHE_HIT_RATE
|
||||
#endif
|
||||
|
||||
class nsZipReaderCache : public nsIZipReaderCache, public nsIObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIZIPREADERCACHE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsZipReaderCache();
|
||||
|
||||
nsresult ReleaseZip(nsJAR* reader);
|
||||
|
||||
typedef nsRefPtrHashtable<nsCStringHashKey, nsJAR> ZipsHashtable;
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~nsZipReaderCache();
|
||||
|
||||
mozilla::Mutex mLock;
|
||||
uint32_t mCacheSize;
|
||||
ZipsHashtable mZips;
|
||||
|
||||
#ifdef ZIP_CACHE_HIT_RATE
|
||||
uint32_t mZipCacheLookups;
|
||||
uint32_t mZipCacheHits;
|
||||
uint32_t mZipCacheFlushes;
|
||||
uint32_t mZipSyncMisses;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* nsJAR_h_ */
|
||||
1096
modules/libjar/nsJARChannel.cpp
Normal file
1096
modules/libjar/nsJARChannel.cpp
Normal file
File diff suppressed because it is too large
Load diff
109
modules/libjar/nsJARChannel.h
Normal file
109
modules/libjar/nsJARChannel.h
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsJARChannel_h__
|
||||
#define nsJARChannel_h__
|
||||
|
||||
#include "mozilla/net/MemoryDownloader.h"
|
||||
#include "nsIJARChannel.h"
|
||||
#include "nsIJARURI.h"
|
||||
#include "nsIInputStreamPump.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIProgressEventSink.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIZipReader.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsILoadInfo.h"
|
||||
#include "nsIThreadRetargetableRequest.h"
|
||||
#include "nsIThreadRetargetableStreamListener.h"
|
||||
#include "nsHashPropertyBag.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
class nsJARInputThunk;
|
||||
class nsInputStreamPump;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsJARChannel final : public nsIJARChannel
|
||||
, public mozilla::net::MemoryDownloader::IObserver
|
||||
, public nsIStreamListener
|
||||
, public nsIThreadRetargetableRequest
|
||||
, public nsIThreadRetargetableStreamListener
|
||||
, public nsHashPropertyBag
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIREQUEST
|
||||
NS_DECL_NSICHANNEL
|
||||
NS_DECL_NSIJARCHANNEL
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSITHREADRETARGETABLEREQUEST
|
||||
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
|
||||
|
||||
nsJARChannel();
|
||||
|
||||
nsresult Init(nsIURI *uri);
|
||||
|
||||
private:
|
||||
virtual ~nsJARChannel();
|
||||
|
||||
nsresult CreateJarInput(nsIZipReaderCache *, nsJARInputThunk **);
|
||||
nsresult LookupFile(bool aAllowAsync);
|
||||
nsresult OpenLocalFile();
|
||||
void NotifyError(nsresult aError);
|
||||
void FireOnProgress(uint64_t aProgress);
|
||||
virtual void OnDownloadComplete(mozilla::net::MemoryDownloader* aDownloader,
|
||||
nsIRequest* aRequest,
|
||||
nsISupports* aCtxt,
|
||||
nsresult aStatus,
|
||||
mozilla::net::MemoryDownloader::Data aData)
|
||||
override;
|
||||
|
||||
nsCString mSpec;
|
||||
|
||||
bool mOpened;
|
||||
|
||||
nsCOMPtr<nsIJARURI> mJarURI;
|
||||
nsCOMPtr<nsIURI> mOriginalURI;
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
nsCOMPtr<nsILoadInfo> mLoadInfo;
|
||||
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||
nsCOMPtr<nsISupports> mSecurityInfo;
|
||||
nsCOMPtr<nsIProgressEventSink> mProgressSink;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsISupports> mListenerContext;
|
||||
nsCString mContentType;
|
||||
nsCString mContentCharset;
|
||||
nsCString mContentDispositionHeader;
|
||||
/* mContentDisposition is uninitialized if mContentDispositionHeader is
|
||||
* empty */
|
||||
uint32_t mContentDisposition;
|
||||
int64_t mContentLength;
|
||||
uint32_t mLoadFlags;
|
||||
nsresult mStatus;
|
||||
bool mIsPending;
|
||||
bool mIsUnsafe;
|
||||
|
||||
mozilla::net::MemoryDownloader::Data mTempMem;
|
||||
nsCOMPtr<nsIInputStreamPump> mPump;
|
||||
// mRequest is only non-null during OnStartRequest, so we'll have a pointer
|
||||
// to the request if we get called back via RetargetDeliveryTo.
|
||||
nsCOMPtr<nsIRequest> mRequest;
|
||||
nsCOMPtr<nsIFile> mJarFile;
|
||||
nsCOMPtr<nsIURI> mJarBaseURI;
|
||||
nsCString mJarEntry;
|
||||
nsCString mInnerJarEntry;
|
||||
|
||||
// True if this channel should not download any remote files.
|
||||
bool mBlockRemoteFiles;
|
||||
};
|
||||
|
||||
#endif // nsJARChannel_h__
|
||||
64
modules/libjar/nsJARFactory.cpp
Normal file
64
modules/libjar/nsJARFactory.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "nscore.h"
|
||||
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsIJARFactory.h"
|
||||
#include "nsJARProtocolHandler.h"
|
||||
#include "nsJARURI.h"
|
||||
#include "nsJAR.h"
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsJAR)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsZipReaderCache)
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsJARProtocolHandler,
|
||||
nsJARProtocolHandler::GetSingleton)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsJARURI)
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_ZIPREADER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ZIPREADERCACHE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_JARPROTOCOLHANDLER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_JARURI_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kJARCIDs[] = {
|
||||
{ &kNS_ZIPREADER_CID, false, nullptr, nsJARConstructor },
|
||||
{ &kNS_ZIPREADERCACHE_CID, false, nullptr, nsZipReaderCacheConstructor },
|
||||
{ &kNS_JARPROTOCOLHANDLER_CID, false, nullptr, nsJARProtocolHandlerConstructor },
|
||||
{ &kNS_JARURI_CID, false, nullptr, nsJARURIConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kJARContracts[] = {
|
||||
{ "@mozilla.org/libjar/zip-reader;1", &kNS_ZIPREADER_CID },
|
||||
{ "@mozilla.org/libjar/zip-reader-cache;1", &kNS_ZIPREADERCACHE_CID },
|
||||
{ NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "jar", &kNS_JARPROTOCOLHANDLER_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
// Jar module shutdown hook
|
||||
static void nsJarShutdown()
|
||||
{
|
||||
// Make sure to not null out gJarHandler here, because we may have
|
||||
// still-live nsJARChannels that will want to release it.
|
||||
nsJARProtocolHandler *handler = gJarHandler;
|
||||
NS_IF_RELEASE(handler);
|
||||
}
|
||||
|
||||
static const mozilla::Module kJARModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kJARCIDs,
|
||||
kJARContracts,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nsJarShutdown
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(nsJarModule) = &kJARModule;
|
||||
375
modules/libjar/nsJARInputStream.cpp
Normal file
375
modules/libjar/nsJARInputStream.cpp
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* nsJARInputStream.cpp
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsJARInputStream.h"
|
||||
#include "zipstruct.h" // defines ZIP compression codes
|
||||
#include "nsZipArchive.h"
|
||||
|
||||
#include "nsEscape.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsDebug.h"
|
||||
#include <algorithm>
|
||||
#if defined(XP_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------
|
||||
* nsISupports implementation
|
||||
*--------------------------------------------*/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsJARInputStream, nsIInputStream)
|
||||
|
||||
/*----------------------------------------------------------
|
||||
* nsJARInputStream implementation
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
nsresult
|
||||
nsJARInputStream::InitFile(nsJAR *aJar, nsZipItem *item)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
MOZ_ASSERT(aJar, "Argument may not be null");
|
||||
MOZ_ASSERT(item, "Argument may not be null");
|
||||
|
||||
// Mark it as closed, in case something fails in initialisation
|
||||
mMode = MODE_CLOSED;
|
||||
//-- prepare for the compression type
|
||||
switch (item->Compression()) {
|
||||
case STORED:
|
||||
mMode = MODE_COPY;
|
||||
break;
|
||||
|
||||
case DEFLATED:
|
||||
rv = gZlibInit(&mZs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mMode = MODE_INFLATE;
|
||||
mInCrc = item->CRC32();
|
||||
mOutCrc = crc32(0L, Z_NULL, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Must keep handle to filepointer and mmap structure as long as we need access to the mmapped data
|
||||
mFd = aJar->mZip->GetFD();
|
||||
mZs.next_in = (Bytef *)aJar->mZip->GetData(item);
|
||||
if (!mZs.next_in) {
|
||||
nsZipArchive::sFileCorruptedReason = "nsJARInputStream: !mZs.next_in";
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
mZs.avail_in = item->Size();
|
||||
mOutSize = item->RealSize();
|
||||
mZs.total_out = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJARInputStream::InitDirectory(nsJAR* aJar,
|
||||
const nsACString& aJarDirSpec,
|
||||
const char* aDir)
|
||||
{
|
||||
MOZ_ASSERT(aJar, "Argument may not be null");
|
||||
MOZ_ASSERT(aDir, "Argument may not be null");
|
||||
|
||||
// Mark it as closed, in case something fails in initialisation
|
||||
mMode = MODE_CLOSED;
|
||||
|
||||
// Keep the zipReader for getting the actual zipItems
|
||||
mJar = aJar;
|
||||
nsZipFind *find;
|
||||
nsresult rv;
|
||||
// We can get aDir's contents as strings via FindEntries
|
||||
// with the following pattern (see nsIZipReader.findEntries docs)
|
||||
// assuming dirName is properly escaped:
|
||||
//
|
||||
// dirName + "?*~" + dirName + "?*/?*"
|
||||
nsDependentCString dirName(aDir);
|
||||
mNameLen = dirName.Length();
|
||||
|
||||
// iterate through dirName and copy it to escDirName, escaping chars
|
||||
// which are special at the "top" level of the regexp so FindEntries
|
||||
// works correctly
|
||||
nsAutoCString escDirName;
|
||||
const char* curr = dirName.BeginReading();
|
||||
const char* end = dirName.EndReading();
|
||||
while (curr != end) {
|
||||
switch (*curr) {
|
||||
case '*':
|
||||
case '?':
|
||||
case '$':
|
||||
case '[':
|
||||
case ']':
|
||||
case '^':
|
||||
case '~':
|
||||
case '(':
|
||||
case ')':
|
||||
case '\\':
|
||||
escDirName.Append('\\');
|
||||
MOZ_FALLTHROUGH;
|
||||
default:
|
||||
escDirName.Append(*curr);
|
||||
}
|
||||
++curr;
|
||||
}
|
||||
nsAutoCString pattern = escDirName + NS_LITERAL_CSTRING("?*~") +
|
||||
escDirName + NS_LITERAL_CSTRING("?*/?*");
|
||||
rv = mJar->mZip->FindInit(pattern.get(), &find);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
const char *name;
|
||||
uint16_t nameLen;
|
||||
while ((rv = find->FindNext( &name, &nameLen )) == NS_OK) {
|
||||
// Must copy, to make it zero-terminated
|
||||
mArray.AppendElement(nsCString(name,nameLen));
|
||||
}
|
||||
delete find;
|
||||
|
||||
if (rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST && NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE; // no error translation
|
||||
}
|
||||
|
||||
// Sort it
|
||||
mArray.Sort();
|
||||
|
||||
mBuffer.AssignLiteral("300: ");
|
||||
mBuffer.Append(aJarDirSpec);
|
||||
mBuffer.AppendLiteral("\n200: filename content-length last-modified file-type\n");
|
||||
|
||||
// Open for reading
|
||||
mMode = MODE_DIRECTORY;
|
||||
mZs.total_out = 0;
|
||||
mArrPos = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARInputStream::Available(uint64_t *_retval)
|
||||
{
|
||||
// A lot of callers don't check the error code.
|
||||
// They just use the _retval value.
|
||||
*_retval = 0;
|
||||
|
||||
switch (mMode) {
|
||||
case MODE_NOTINITED:
|
||||
break;
|
||||
|
||||
case MODE_CLOSED:
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
case MODE_DIRECTORY:
|
||||
*_retval = mBuffer.Length();
|
||||
break;
|
||||
|
||||
case MODE_INFLATE:
|
||||
case MODE_COPY:
|
||||
*_retval = mOutSize - mZs.total_out;
|
||||
break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t *aBytesRead)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aBuffer);
|
||||
NS_ENSURE_ARG_POINTER(aBytesRead);
|
||||
|
||||
*aBytesRead = 0;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
MOZ_WIN_MEM_TRY_BEGIN
|
||||
switch (mMode) {
|
||||
case MODE_NOTINITED:
|
||||
return NS_OK;
|
||||
|
||||
case MODE_CLOSED:
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
case MODE_DIRECTORY:
|
||||
return ReadDirectory(aBuffer, aCount, aBytesRead);
|
||||
|
||||
case MODE_INFLATE:
|
||||
if (mFd) {
|
||||
rv = ContinueInflate(aBuffer, aCount, aBytesRead);
|
||||
}
|
||||
// be aggressive about releasing the file!
|
||||
// note that sometimes, we will release mFd before we've finished
|
||||
// deflating - this is because zlib buffers the input
|
||||
if (mZs.avail_in == 0) {
|
||||
mFd = nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_COPY:
|
||||
if (mFd) {
|
||||
uint32_t count = std::min(aCount, mOutSize - uint32_t(mZs.total_out));
|
||||
if (count) {
|
||||
memcpy(aBuffer, mZs.next_in + mZs.total_out, count);
|
||||
mZs.total_out += count;
|
||||
}
|
||||
*aBytesRead = count;
|
||||
}
|
||||
// be aggressive about releasing the file!
|
||||
// note that sometimes, we will release mFd before we've finished copying.
|
||||
if (mZs.total_out >= mOutSize) {
|
||||
mFd = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
MOZ_WIN_MEM_TRY_CATCH(rv = NS_ERROR_FAILURE)
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, uint32_t count, uint32_t *_retval)
|
||||
{
|
||||
// don't have a buffer to read from, so this better not be called!
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARInputStream::IsNonBlocking(bool *aNonBlocking)
|
||||
{
|
||||
*aNonBlocking = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARInputStream::Close()
|
||||
{
|
||||
if (mMode == MODE_INFLATE) {
|
||||
inflateEnd(&mZs);
|
||||
}
|
||||
mMode = MODE_CLOSED;
|
||||
mFd = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJARInputStream::ContinueInflate(char* aBuffer, uint32_t aCount,
|
||||
uint32_t* aBytesRead)
|
||||
{
|
||||
// No need to check the args, ::Read did that, but assert them at least
|
||||
NS_ASSERTION(aBuffer,"aBuffer parameter must not be null");
|
||||
NS_ASSERTION(aBytesRead,"aBytesRead parameter must not be null");
|
||||
|
||||
// Keep old total_out count
|
||||
const uint32_t oldTotalOut = mZs.total_out;
|
||||
|
||||
// make sure we aren't reading too much
|
||||
mZs.avail_out = std::min(aCount, (mOutSize-oldTotalOut));
|
||||
mZs.next_out = (unsigned char*)aBuffer;
|
||||
|
||||
// now inflate
|
||||
int zerr = inflate(&mZs, Z_SYNC_FLUSH);
|
||||
if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) {
|
||||
nsZipArchive::sFileCorruptedReason = "nsJARInputStream: error while inflating";
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
|
||||
*aBytesRead = (mZs.total_out - oldTotalOut);
|
||||
|
||||
// Calculate the CRC on the output
|
||||
mOutCrc = crc32(mOutCrc, (unsigned char*)aBuffer, *aBytesRead);
|
||||
|
||||
// be aggressive about ending the inflation
|
||||
// for some reason we don't always get Z_STREAM_END
|
||||
if (zerr == Z_STREAM_END || mZs.total_out == mOutSize) {
|
||||
inflateEnd(&mZs);
|
||||
|
||||
// stop returning valid data as soon as we know we have a bad CRC
|
||||
if (mOutCrc != mInCrc) {
|
||||
nsZipArchive::sFileCorruptedReason = "nsJARInputStream: crc mismatch";
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJARInputStream::ReadDirectory(char* aBuffer, uint32_t aCount, uint32_t *aBytesRead)
|
||||
{
|
||||
// No need to check the args, ::Read did that, but assert them at least
|
||||
NS_ASSERTION(aBuffer,"aBuffer parameter must not be null");
|
||||
NS_ASSERTION(aBytesRead,"aBytesRead parameter must not be null");
|
||||
|
||||
// If the buffer contains data, copy what's there up to the desired amount
|
||||
uint32_t numRead = CopyDataToBuffer(aBuffer, aCount);
|
||||
|
||||
if (aCount > 0) {
|
||||
// empty the buffer and start writing directory entry lines to it
|
||||
mBuffer.Truncate();
|
||||
mCurPos = 0;
|
||||
const uint32_t arrayLen = mArray.Length();
|
||||
|
||||
for ( ;aCount > mBuffer.Length(); mArrPos++) {
|
||||
// have we consumed all the directory contents?
|
||||
if (arrayLen <= mArrPos)
|
||||
break;
|
||||
|
||||
const char * entryName = mArray[mArrPos].get();
|
||||
uint32_t entryNameLen = mArray[mArrPos].Length();
|
||||
nsZipItem* ze = mJar->mZip->GetItem(entryName);
|
||||
NS_ENSURE_TRUE(ze, NS_ERROR_FILE_TARGET_DOES_NOT_EXIST);
|
||||
|
||||
// Last Modified Time
|
||||
PRExplodedTime tm;
|
||||
PR_ExplodeTime(ze->LastModTime(), PR_GMTParameters, &tm);
|
||||
char itemLastModTime[65];
|
||||
PR_FormatTimeUSEnglish(itemLastModTime,
|
||||
sizeof(itemLastModTime),
|
||||
" %a,%%20%d%%20%b%%20%Y%%20%H:%M:%S%%20GMT ",
|
||||
&tm);
|
||||
|
||||
// write a 201: line to the buffer for this item
|
||||
// 200: filename content-length last-modified file-type
|
||||
mBuffer.AppendLiteral("201: ");
|
||||
|
||||
// Names must be escaped and relative, so use the pre-calculated length
|
||||
// of the directory name as the offset into the string
|
||||
// NS_EscapeURL adds the escaped URL to the give string buffer
|
||||
NS_EscapeURL(entryName + mNameLen,
|
||||
entryNameLen - mNameLen,
|
||||
esc_Minimal | esc_AlwaysCopy,
|
||||
mBuffer);
|
||||
|
||||
mBuffer.Append(' ');
|
||||
mBuffer.AppendInt(ze->RealSize(), 10);
|
||||
mBuffer.Append(itemLastModTime); // starts/ends with ' '
|
||||
if (ze->IsDirectory())
|
||||
mBuffer.AppendLiteral("DIRECTORY\n");
|
||||
else
|
||||
mBuffer.AppendLiteral("FILE\n");
|
||||
}
|
||||
|
||||
// Copy up to the desired amount of data to buffer
|
||||
numRead += CopyDataToBuffer(aBuffer, aCount);
|
||||
}
|
||||
|
||||
*aBytesRead = numRead;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsJARInputStream::CopyDataToBuffer(char* &aBuffer, uint32_t &aCount)
|
||||
{
|
||||
const uint32_t writeLength = std::min(aCount, mBuffer.Length() - mCurPos);
|
||||
|
||||
if (writeLength > 0) {
|
||||
memcpy(aBuffer, mBuffer.get() + mCurPos, writeLength);
|
||||
mCurPos += writeLength;
|
||||
aCount -= writeLength;
|
||||
aBuffer += writeLength;
|
||||
}
|
||||
|
||||
// return number of bytes copied to the buffer so the
|
||||
// Read method can return the number of bytes copied
|
||||
return writeLength;
|
||||
}
|
||||
73
modules/libjar/nsJARInputStream.h
Normal file
73
modules/libjar/nsJARInputStream.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/* nsJARInputStream.h
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsJARINPUTSTREAM_h__
|
||||
#define nsJARINPUTSTREAM_h__
|
||||
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsJAR.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Class nsJARInputStream declaration. This class defines the type of the
|
||||
* object returned by calls to nsJAR::GetInputStream(filename) for the
|
||||
* purpose of reading a file item out of a JAR file.
|
||||
*------------------------------------------------------------------------*/
|
||||
class nsJARInputStream final : public nsIInputStream
|
||||
{
|
||||
public:
|
||||
nsJARInputStream() :
|
||||
mOutSize(0), mInCrc(0), mOutCrc(0), mNameLen(0),
|
||||
mCurPos(0), mArrPos(0), mMode(MODE_NOTINITED)
|
||||
{
|
||||
memset(&mZs, 0, sizeof(z_stream));
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
|
||||
// takes ownership of |fd|, even on failure
|
||||
nsresult InitFile(nsJAR *aJar, nsZipItem *item);
|
||||
|
||||
nsresult InitDirectory(nsJAR *aJar,
|
||||
const nsACString& aJarDirSpec,
|
||||
const char* aDir);
|
||||
|
||||
private:
|
||||
~nsJARInputStream() { Close(); }
|
||||
|
||||
RefPtr<nsZipHandle> mFd; // handle for reading
|
||||
uint32_t mOutSize; // inflated size
|
||||
uint32_t mInCrc; // CRC as provided by the zipentry
|
||||
uint32_t mOutCrc; // CRC as calculated by me
|
||||
z_stream mZs; // zip data structure
|
||||
|
||||
/* For directory reading */
|
||||
RefPtr<nsJAR> mJar; // string reference to zipreader
|
||||
uint32_t mNameLen; // length of dirname
|
||||
nsCString mBuffer; // storage for generated text of stream
|
||||
uint32_t mCurPos; // Current position in buffer
|
||||
uint32_t mArrPos; // current position within mArray
|
||||
nsTArray<nsCString> mArray; // array of names in (zip) directory
|
||||
|
||||
typedef enum {
|
||||
MODE_NOTINITED,
|
||||
MODE_CLOSED,
|
||||
MODE_DIRECTORY,
|
||||
MODE_INFLATE,
|
||||
MODE_COPY
|
||||
} JISMode;
|
||||
|
||||
JISMode mMode; // Modus of the stream
|
||||
|
||||
nsresult ContinueInflate(char* aBuf, uint32_t aCount, uint32_t* aBytesRead);
|
||||
nsresult ReadDirectory(char* aBuf, uint32_t aCount, uint32_t* aBytesRead);
|
||||
uint32_t CopyDataToBuffer(char* &aBuffer, uint32_t &aCount);
|
||||
};
|
||||
|
||||
#endif /* nsJARINPUTSTREAM_h__ */
|
||||
|
||||
188
modules/libjar/nsJARProtocolHandler.cpp
Normal file
188
modules/libjar/nsJARProtocolHandler.cpp
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsJARProtocolHandler.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsJARURI.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsJARChannel.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsString.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
static NS_DEFINE_CID(kZipReaderCacheCID, NS_ZIPREADERCACHE_CID);
|
||||
|
||||
#define NS_JAR_CACHE_SIZE 32
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsJARProtocolHandler *gJarHandler = nullptr;
|
||||
|
||||
nsJARProtocolHandler::nsJARProtocolHandler()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
nsJARProtocolHandler::~nsJARProtocolHandler()
|
||||
{
|
||||
MOZ_ASSERT(gJarHandler == this);
|
||||
gJarHandler = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJARProtocolHandler::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
mJARCache = do_CreateInstance(kZipReaderCacheCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mJARCache->Init(NS_JAR_CACHE_SIZE);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsIMIMEService *
|
||||
nsJARProtocolHandler::MimeService()
|
||||
{
|
||||
if (!mMimeService)
|
||||
mMimeService = do_GetService("@mozilla.org/mime;1");
|
||||
|
||||
return mMimeService.get();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsJARProtocolHandler,
|
||||
nsIJARProtocolHandler,
|
||||
nsIProtocolHandler,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
nsJARProtocolHandler*
|
||||
nsJARProtocolHandler::GetSingleton()
|
||||
{
|
||||
if (!gJarHandler) {
|
||||
gJarHandler = new nsJARProtocolHandler();
|
||||
if (!gJarHandler)
|
||||
return nullptr;
|
||||
|
||||
NS_ADDREF(gJarHandler);
|
||||
nsresult rv = gJarHandler->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(gJarHandler);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
NS_ADDREF(gJarHandler);
|
||||
return gJarHandler;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARProtocolHandler::GetJARCache(nsIZipReaderCache* *result)
|
||||
{
|
||||
*result = mJARCache;
|
||||
NS_ADDREF(*result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIProtocolHandler methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARProtocolHandler::GetScheme(nsACString &result)
|
||||
{
|
||||
result.AssignLiteral("jar");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARProtocolHandler::GetDefaultPort(int32_t *result)
|
||||
{
|
||||
*result = -1; // no port for JAR: URLs
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARProtocolHandler::GetProtocolFlags(uint32_t *result)
|
||||
{
|
||||
// URI_LOADABLE_BY_ANYONE, since it's our inner URI that will matter
|
||||
// anyway.
|
||||
*result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE;
|
||||
/* Although jar uris have their own concept of relative urls
|
||||
it is very different from the standard behaviour, so we
|
||||
have to say norelative here! */
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARProtocolHandler::NewURI(const nsACString &aSpec,
|
||||
const char *aCharset,
|
||||
nsIURI *aBaseURI,
|
||||
nsIURI **result)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
RefPtr<nsJARURI> jarURI = new nsJARURI();
|
||||
if (!jarURI)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = jarURI->Init(aCharset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = jarURI->SetSpecWithBase(aSpec, aBaseURI);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
NS_ADDREF(*result = jarURI);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARProtocolHandler::NewChannel2(nsIURI* uri,
|
||||
nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** result)
|
||||
{
|
||||
nsJARChannel *chan = new nsJARChannel();
|
||||
if (!chan)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(chan);
|
||||
|
||||
nsresult rv = chan->Init(uri);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(chan);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// set the loadInfo on the new channel
|
||||
rv = chan->SetLoadInfo(aLoadInfo);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(chan);
|
||||
return rv;
|
||||
}
|
||||
|
||||
*result = chan;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARProtocolHandler::NewChannel(nsIURI *uri, nsIChannel **result)
|
||||
{
|
||||
return NewChannel2(uri, nullptr, result);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
|
||||
{
|
||||
// don't override anything.
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
52
modules/libjar/nsJARProtocolHandler.h
Normal file
52
modules/libjar/nsJARProtocolHandler.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsJARProtocolHandler_h__
|
||||
#define nsJARProtocolHandler_h__
|
||||
|
||||
#include "nsIJARProtocolHandler.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIJARURI.h"
|
||||
#include "nsIZipReader.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsJARProtocolHandler final : public nsIJARProtocolHandler
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIPROTOCOLHANDLER
|
||||
NS_DECL_NSIJARPROTOCOLHANDLER
|
||||
|
||||
// nsJARProtocolHandler methods:
|
||||
nsJARProtocolHandler();
|
||||
|
||||
static nsJARProtocolHandler *GetSingleton();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
// returns non addref'ed pointer.
|
||||
nsIMIMEService *MimeService();
|
||||
nsIZipReaderCache *JarCache() { return mJARCache; }
|
||||
protected:
|
||||
virtual ~nsJARProtocolHandler();
|
||||
|
||||
nsCOMPtr<nsIZipReaderCache> mJARCache;
|
||||
nsCOMPtr<nsIMIMEService> mMimeService;
|
||||
};
|
||||
|
||||
extern nsJARProtocolHandler *gJarHandler;
|
||||
|
||||
#define NS_JARPROTOCOLHANDLER_CID \
|
||||
{ /* 0xc7e410d4-0x85f2-11d3-9f63-006008a6efe9 */ \
|
||||
0xc7e410d4, \
|
||||
0x85f2, \
|
||||
0x11d3, \
|
||||
{0x9f, 0x63, 0x00, 0x60, 0x08, 0xa6, 0xef, 0xe9} \
|
||||
}
|
||||
|
||||
#endif // !nsJARProtocolHandler_h__
|
||||
913
modules/libjar/nsJARURI.cpp
Normal file
913
modules/libjar/nsJARURI.cpp
Normal file
|
|
@ -0,0 +1,913 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "nsJARURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIStandardURL.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIZipReader.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
static NS_DEFINE_CID(kJARURICID, NS_JARURI_CID);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsJARURI::nsJARURI()
|
||||
{
|
||||
}
|
||||
|
||||
nsJARURI::~nsJARURI()
|
||||
{
|
||||
}
|
||||
|
||||
// XXX Why is this threadsafe?
|
||||
NS_IMPL_ADDREF(nsJARURI)
|
||||
NS_IMPL_RELEASE(nsJARURI)
|
||||
NS_INTERFACE_MAP_BEGIN(nsJARURI)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJARURI)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIURI)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIURIWithQuery)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIURL)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIJARURI)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISerializable)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
|
||||
NS_INTERFACE_MAP_ENTRY(nsINestedURI)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableURI)
|
||||
// see nsJARURI::Equals
|
||||
if (aIID.Equals(NS_GET_IID(nsJARURI)))
|
||||
foundInterface = reinterpret_cast<nsISupports*>(this);
|
||||
else
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsresult
|
||||
nsJARURI::Init(const char *charsetHint)
|
||||
{
|
||||
mCharsetHint = charsetHint;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#define NS_JAR_SCHEME NS_LITERAL_CSTRING("jar:")
|
||||
#define NS_JAR_DELIMITER NS_LITERAL_CSTRING("!/")
|
||||
#define NS_BOGUS_ENTRY_SCHEME NS_LITERAL_CSTRING("x:///")
|
||||
|
||||
// FormatSpec takes the entry spec (including the "x:///" at the
|
||||
// beginning) and gives us a full JAR spec.
|
||||
nsresult
|
||||
nsJARURI::FormatSpec(const nsACString &entrySpec, nsACString &result,
|
||||
bool aIncludeScheme)
|
||||
{
|
||||
// The entrySpec MUST start with "x:///"
|
||||
NS_ASSERTION(StringBeginsWith(entrySpec, NS_BOGUS_ENTRY_SCHEME),
|
||||
"bogus entry spec");
|
||||
|
||||
nsAutoCString fileSpec;
|
||||
nsresult rv = mJARFile->GetSpec(fileSpec);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (aIncludeScheme)
|
||||
result = NS_JAR_SCHEME;
|
||||
else
|
||||
result.Truncate();
|
||||
|
||||
result.Append(fileSpec + NS_JAR_DELIMITER +
|
||||
Substring(entrySpec, 5, entrySpec.Length() - 5));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJARURI::CreateEntryURL(const nsACString& entryFilename,
|
||||
const char* charset,
|
||||
nsIURL** url)
|
||||
{
|
||||
*url = nullptr;
|
||||
|
||||
nsCOMPtr<nsIStandardURL> stdURL(do_CreateInstance(NS_STANDARDURL_CONTRACTID));
|
||||
if (!stdURL) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Flatten the concatenation, just in case. See bug 128288
|
||||
nsAutoCString spec(NS_BOGUS_ENTRY_SCHEME + entryFilename);
|
||||
nsresult rv = stdURL->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
|
||||
spec, charset, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return CallQueryInterface(stdURL, url);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsISerializable methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::Read(nsIObjectInputStream* aInputStream)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISupports> supports;
|
||||
rv = aInputStream->ReadObject(true, getter_AddRefs(supports));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mJARFile = do_QueryInterface(supports, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aInputStream->ReadObject(true, getter_AddRefs(supports));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mJAREntry = do_QueryInterface(supports);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aInputStream->ReadCString(mCharsetHint);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::Write(nsIObjectOutputStream* aOutputStream)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = aOutputStream->WriteCompoundObject(mJARFile, NS_GET_IID(nsIURI),
|
||||
true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aOutputStream->WriteCompoundObject(mJAREntry, NS_GET_IID(nsIURL),
|
||||
true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aOutputStream->WriteStringZ(mCharsetHint.get());
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIClassInfo methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetInterfaces(uint32_t *count, nsIID * **array)
|
||||
{
|
||||
*count = 0;
|
||||
*array = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetScriptableHelper(nsIXPCScriptable **_retval)
|
||||
{
|
||||
*_retval = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetContractID(char * *aContractID)
|
||||
{
|
||||
*aContractID = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetClassDescription(char * *aClassDescription)
|
||||
{
|
||||
*aClassDescription = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetClassID(nsCID * *aClassID)
|
||||
{
|
||||
*aClassID = (nsCID*) moz_xmalloc(sizeof(nsCID));
|
||||
if (!*aClassID)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return GetClassIDNoAlloc(*aClassID);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetFlags(uint32_t *aFlags)
|
||||
{
|
||||
// XXX We implement THREADSAFE addref/release, but probably shouldn't.
|
||||
*aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
|
||||
{
|
||||
*aClassIDNoAlloc = kJARURICID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIURI methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetSpec(nsACString &aSpec)
|
||||
{
|
||||
nsAutoCString entrySpec;
|
||||
mJAREntry->GetSpec(entrySpec);
|
||||
return FormatSpec(entrySpec, aSpec);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetSpecIgnoringRef(nsACString &aSpec)
|
||||
{
|
||||
nsAutoCString entrySpec;
|
||||
mJAREntry->GetSpecIgnoringRef(entrySpec);
|
||||
return FormatSpec(entrySpec, aSpec);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetHasRef(bool *result)
|
||||
{
|
||||
return mJAREntry->GetHasRef(result);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetSpec(const nsACString& aSpec)
|
||||
{
|
||||
return SetSpecWithBase(aSpec, nullptr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJARURI::SetSpecWithBase(const nsACString &aSpec, nsIURI* aBaseURL)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString scheme;
|
||||
rv = ioServ->ExtractScheme(aSpec, scheme);
|
||||
if (NS_FAILED(rv)) {
|
||||
// not an absolute URI
|
||||
if (!aBaseURL)
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
|
||||
RefPtr<nsJARURI> otherJAR;
|
||||
aBaseURL->QueryInterface(NS_GET_IID(nsJARURI), getter_AddRefs(otherJAR));
|
||||
NS_ENSURE_TRUE(otherJAR, NS_NOINTERFACE);
|
||||
|
||||
mJARFile = otherJAR->mJARFile;
|
||||
|
||||
nsCOMPtr<nsIStandardURL> entry(do_CreateInstance(NS_STANDARDURL_CONTRACTID));
|
||||
if (!entry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = entry->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
|
||||
aSpec, mCharsetHint.get(), otherJAR->mJAREntry);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
mJAREntry = do_QueryInterface(entry);
|
||||
if (!mJAREntry)
|
||||
return NS_NOINTERFACE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(scheme.EqualsLiteral("jar"), NS_ERROR_MALFORMED_URI);
|
||||
|
||||
nsACString::const_iterator begin, end;
|
||||
aSpec.BeginReading(begin);
|
||||
aSpec.EndReading(end);
|
||||
|
||||
while (begin != end && *begin != ':')
|
||||
++begin;
|
||||
|
||||
++begin; // now we're past the "jar:"
|
||||
|
||||
// Search backward from the end for the "!/" delimiter. Remember, jar URLs
|
||||
// can nest, e.g.:
|
||||
// jar:jar:http://www.foo.com/bar.jar!/a.jar!/b.html
|
||||
// This gets the b.html document from out of the a.jar file, that's
|
||||
// contained within the bar.jar file.
|
||||
// Also, the outermost "inner" URI may be a relative URI:
|
||||
// jar:../relative.jar!/a.html
|
||||
|
||||
nsACString::const_iterator delim_begin (begin),
|
||||
delim_end (end);
|
||||
|
||||
if (!RFindInReadable(NS_JAR_DELIMITER, delim_begin, delim_end))
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
|
||||
rv = ioServ->NewURI(Substring(begin, delim_begin), mCharsetHint.get(),
|
||||
aBaseURL, getter_AddRefs(mJARFile));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_TryToSetImmutable(mJARFile);
|
||||
|
||||
// skip over any extra '/' chars
|
||||
while (*delim_end == '/')
|
||||
++delim_end;
|
||||
|
||||
return SetJAREntry(Substring(delim_end, end));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetPrePath(nsACString &prePath)
|
||||
{
|
||||
prePath = NS_JAR_SCHEME;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetScheme(nsACString &aScheme)
|
||||
{
|
||||
aScheme = "jar";
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetScheme(const nsACString &aScheme)
|
||||
{
|
||||
// doesn't make sense to set the scheme of a jar: URL
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetUserPass(nsACString &aUserPass)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetUserPass(const nsACString &aUserPass)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetUsername(nsACString &aUsername)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetUsername(const nsACString &aUsername)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetPassword(nsACString &aPassword)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetPassword(const nsACString &aPassword)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetHostPort(nsACString &aHostPort)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetHostPort(const nsACString &aHostPort)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetHostAndPort(const nsACString &aHostPort)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetHost(nsACString &aHost)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetHost(const nsACString &aHost)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetPort(int32_t *aPort)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetPort(int32_t aPort)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetPath(nsACString &aPath)
|
||||
{
|
||||
nsAutoCString entrySpec;
|
||||
mJAREntry->GetSpec(entrySpec);
|
||||
return FormatSpec(entrySpec, aPath, false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetPath(const nsACString &aPath)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetAsciiSpec(nsACString &aSpec)
|
||||
{
|
||||
// XXX Shouldn't this like... make sure it returns ASCII or something?
|
||||
return GetSpec(aSpec);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetAsciiHostPort(nsACString &aHostPort)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetAsciiHost(nsACString &aHost)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetOriginCharset(nsACString &aOriginCharset)
|
||||
{
|
||||
aOriginCharset = mCharsetHint;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::Equals(nsIURI *other, bool *result)
|
||||
{
|
||||
return EqualsInternal(other, eHonorRef, result);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::EqualsExceptRef(nsIURI *other, bool *result)
|
||||
{
|
||||
return EqualsInternal(other, eIgnoreRef, result);
|
||||
}
|
||||
|
||||
// Helper method:
|
||||
/* virtual */ nsresult
|
||||
nsJARURI::EqualsInternal(nsIURI *other,
|
||||
nsJARURI::RefHandlingEnum refHandlingMode,
|
||||
bool *result)
|
||||
{
|
||||
*result = false;
|
||||
|
||||
if (!other)
|
||||
return NS_OK; // not equal
|
||||
|
||||
RefPtr<nsJARURI> otherJAR;
|
||||
other->QueryInterface(NS_GET_IID(nsJARURI), getter_AddRefs(otherJAR));
|
||||
if (!otherJAR)
|
||||
return NS_OK; // not equal
|
||||
|
||||
bool equal;
|
||||
nsresult rv = mJARFile->Equals(otherJAR->mJARFile, &equal);
|
||||
if (NS_FAILED(rv) || !equal) {
|
||||
return rv; // not equal
|
||||
}
|
||||
|
||||
return refHandlingMode == eHonorRef ?
|
||||
mJAREntry->Equals(otherJAR->mJAREntry, result) :
|
||||
mJAREntry->EqualsExceptRef(otherJAR->mJAREntry, result);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SchemeIs(const char *i_Scheme, bool *o_Equals)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(o_Equals);
|
||||
if (!i_Scheme) return NS_ERROR_INVALID_ARG;
|
||||
|
||||
if (*i_Scheme == 'j' || *i_Scheme == 'J') {
|
||||
*o_Equals = PL_strcasecmp("jar", i_Scheme) ? false : true;
|
||||
} else {
|
||||
*o_Equals = false;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::Clone(nsIURI **result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIJARURI> uri;
|
||||
rv = CloneWithJARFileInternal(mJARFile, eHonorRef, getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
uri.forget(result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::CloneIgnoringRef(nsIURI **result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIJARURI> uri;
|
||||
rv = CloneWithJARFileInternal(mJARFile, eIgnoreRef, getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
uri.forget(result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::CloneWithNewRef(const nsACString& newRef, nsIURI **result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIJARURI> uri;
|
||||
rv = CloneWithJARFileInternal(mJARFile, eReplaceRef, newRef,
|
||||
getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
uri.forget(result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::Resolve(const nsACString &relativePath, nsACString &result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsAutoCString scheme;
|
||||
rv = ioServ->ExtractScheme(relativePath, scheme);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// then aSpec is absolute
|
||||
result = relativePath;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString resolvedPath;
|
||||
mJAREntry->Resolve(relativePath, resolvedPath);
|
||||
|
||||
return FormatSpec(resolvedPath, result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIURL methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetFilePath(nsACString& filePath)
|
||||
{
|
||||
return mJAREntry->GetFilePath(filePath);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetFilePath(const nsACString& filePath)
|
||||
{
|
||||
return mJAREntry->SetFilePath(filePath);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetQuery(nsACString& query)
|
||||
{
|
||||
return mJAREntry->GetQuery(query);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetQuery(const nsACString& query)
|
||||
{
|
||||
return mJAREntry->SetQuery(query);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetRef(nsACString& ref)
|
||||
{
|
||||
return mJAREntry->GetRef(ref);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetRef(const nsACString& ref)
|
||||
{
|
||||
return mJAREntry->SetRef(ref);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetDirectory(nsACString& directory)
|
||||
{
|
||||
return mJAREntry->GetDirectory(directory);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetDirectory(const nsACString& directory)
|
||||
{
|
||||
return mJAREntry->SetDirectory(directory);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetFileName(nsACString& fileName)
|
||||
{
|
||||
return mJAREntry->GetFileName(fileName);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetFileName(const nsACString& fileName)
|
||||
{
|
||||
return mJAREntry->SetFileName(fileName);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetFileBaseName(nsACString& fileBaseName)
|
||||
{
|
||||
return mJAREntry->GetFileBaseName(fileBaseName);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetFileBaseName(const nsACString& fileBaseName)
|
||||
{
|
||||
return mJAREntry->SetFileBaseName(fileBaseName);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetFileExtension(nsACString& fileExtension)
|
||||
{
|
||||
return mJAREntry->GetFileExtension(fileExtension);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetFileExtension(const nsACString& fileExtension)
|
||||
{
|
||||
return mJAREntry->SetFileExtension(fileExtension);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetCommonBaseSpec(nsIURI* uriToCompare, nsACString& commonSpec)
|
||||
{
|
||||
commonSpec.Truncate();
|
||||
|
||||
NS_ENSURE_ARG_POINTER(uriToCompare);
|
||||
|
||||
commonSpec.Truncate();
|
||||
nsCOMPtr<nsIJARURI> otherJARURI(do_QueryInterface(uriToCompare));
|
||||
if (!otherJARURI) {
|
||||
// Nothing in common
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> otherJARFile;
|
||||
nsresult rv = otherJARURI->GetJARFile(getter_AddRefs(otherJARFile));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
bool equal;
|
||||
rv = mJARFile->Equals(otherJARFile, &equal);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (!equal) {
|
||||
// See what the JAR file URIs have in common
|
||||
nsCOMPtr<nsIURL> ourJARFileURL(do_QueryInterface(mJARFile));
|
||||
if (!ourJARFileURL) {
|
||||
// Not a URL, so nothing in common
|
||||
return NS_OK;
|
||||
}
|
||||
nsAutoCString common;
|
||||
rv = ourJARFileURL->GetCommonBaseSpec(otherJARFile, common);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
commonSpec = NS_JAR_SCHEME + common;
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
// At this point we have the same JAR file. Compare the JAREntrys
|
||||
nsAutoCString otherEntry;
|
||||
rv = otherJARURI->GetJAREntry(otherEntry);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsAutoCString otherCharset;
|
||||
rv = uriToCompare->GetOriginCharset(otherCharset);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIURL> url;
|
||||
rv = CreateEntryURL(otherEntry, otherCharset.get(), getter_AddRefs(url));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsAutoCString common;
|
||||
rv = mJAREntry->GetCommonBaseSpec(url, common);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = FormatSpec(common, commonSpec);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetRelativeSpec(nsIURI* uriToCompare, nsACString& relativeSpec)
|
||||
{
|
||||
GetSpec(relativeSpec);
|
||||
|
||||
NS_ENSURE_ARG_POINTER(uriToCompare);
|
||||
|
||||
nsCOMPtr<nsIJARURI> otherJARURI(do_QueryInterface(uriToCompare));
|
||||
if (!otherJARURI) {
|
||||
// Nothing in common
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> otherJARFile;
|
||||
nsresult rv = otherJARURI->GetJARFile(getter_AddRefs(otherJARFile));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
bool equal;
|
||||
rv = mJARFile->Equals(otherJARFile, &equal);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (!equal) {
|
||||
// We live in different JAR files. Nothing in common.
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Same JAR file. Compare the JAREntrys
|
||||
nsAutoCString otherEntry;
|
||||
rv = otherJARURI->GetJAREntry(otherEntry);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsAutoCString otherCharset;
|
||||
rv = uriToCompare->GetOriginCharset(otherCharset);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIURL> url;
|
||||
rv = CreateEntryURL(otherEntry, otherCharset.get(), getter_AddRefs(url));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsAutoCString relativeEntrySpec;
|
||||
rv = mJAREntry->GetRelativeSpec(url, relativeEntrySpec);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (!StringBeginsWith(relativeEntrySpec, NS_BOGUS_ENTRY_SCHEME)) {
|
||||
// An actual relative spec!
|
||||
relativeSpec = relativeEntrySpec;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIJARURI methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetJARFile(nsIURI* *jarFile)
|
||||
{
|
||||
return GetInnerURI(jarFile);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetJAREntry(nsACString &entryPath)
|
||||
{
|
||||
nsAutoCString filePath;
|
||||
mJAREntry->GetFilePath(filePath);
|
||||
NS_ASSERTION(filePath.Length() > 0, "path should never be empty!");
|
||||
// Trim off the leading '/'
|
||||
entryPath = Substring(filePath, 1, filePath.Length() - 1);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::SetJAREntry(const nsACString &entryPath)
|
||||
{
|
||||
return CreateEntryURL(entryPath, mCharsetHint.get(),
|
||||
getter_AddRefs(mJAREntry));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::CloneWithJARFile(nsIURI *jarFile, nsIJARURI **result)
|
||||
{
|
||||
return CloneWithJARFileInternal(jarFile, eHonorRef, result);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJARURI::CloneWithJARFileInternal(nsIURI *jarFile,
|
||||
nsJARURI::RefHandlingEnum refHandlingMode,
|
||||
nsIJARURI **result)
|
||||
{
|
||||
return CloneWithJARFileInternal(jarFile, refHandlingMode, EmptyCString(), result);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJARURI::CloneWithJARFileInternal(nsIURI *jarFile,
|
||||
nsJARURI::RefHandlingEnum refHandlingMode,
|
||||
const nsACString& newRef,
|
||||
nsIJARURI **result)
|
||||
{
|
||||
if (!jarFile) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIURI> newJARFile;
|
||||
rv = jarFile->Clone(getter_AddRefs(newJARFile));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_TryToSetImmutable(newJARFile);
|
||||
|
||||
nsCOMPtr<nsIURI> newJAREntryURI;
|
||||
if (refHandlingMode == eHonorRef) {
|
||||
rv = mJAREntry->Clone(getter_AddRefs(newJAREntryURI));
|
||||
} else if (refHandlingMode == eReplaceRef) {
|
||||
rv = mJAREntry->CloneWithNewRef(newRef, getter_AddRefs(newJAREntryURI));
|
||||
} else {
|
||||
rv = mJAREntry->CloneIgnoringRef(getter_AddRefs(newJAREntryURI));
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIURL> newJAREntry(do_QueryInterface(newJAREntryURI));
|
||||
NS_ASSERTION(newJAREntry, "This had better QI to nsIURL!");
|
||||
|
||||
nsJARURI* uri = new nsJARURI();
|
||||
NS_ADDREF(uri);
|
||||
uri->mJARFile = newJARFile;
|
||||
uri->mJAREntry = newJAREntry;
|
||||
*result = uri;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetInnerURI(nsIURI **uri)
|
||||
{
|
||||
return NS_EnsureSafeToReturn(mJARFile, uri);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARURI::GetInnermostURI(nsIURI** uri)
|
||||
{
|
||||
return NS_ImplGetInnermostURI(this, uri);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIIPCSerializableURI methods:
|
||||
|
||||
void
|
||||
nsJARURI::Serialize(URIParams& aParams)
|
||||
{
|
||||
JARURIParams params;
|
||||
|
||||
SerializeURI(mJARFile, params.jarFile());
|
||||
SerializeURI(mJAREntry, params.jarEntry());
|
||||
params.charset() = mCharsetHint;
|
||||
|
||||
aParams = params;
|
||||
}
|
||||
|
||||
bool
|
||||
nsJARURI::Deserialize(const URIParams& aParams)
|
||||
{
|
||||
if (aParams.type() != URIParams::TJARURIParams) {
|
||||
NS_ERROR("Received unknown parameters from the other process!");
|
||||
return false;
|
||||
}
|
||||
|
||||
const JARURIParams& params = aParams.get_JARURIParams();
|
||||
|
||||
nsCOMPtr<nsIURI> file = DeserializeURI(params.jarFile());
|
||||
if (!file) {
|
||||
NS_ERROR("Couldn't deserialize jar file URI!");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> entry = DeserializeURI(params.jarEntry());
|
||||
if (!entry) {
|
||||
NS_ERROR("Couldn't deserialize jar entry URI!");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURL> entryURL = do_QueryInterface(entry);
|
||||
if (!entryURL) {
|
||||
NS_ERROR("Couldn't QI jar entry URI to nsIURL!");
|
||||
return false;
|
||||
}
|
||||
|
||||
mJARFile.swap(file);
|
||||
mJAREntry.swap(entryURL);
|
||||
mCharsetHint = params.charset();
|
||||
|
||||
return true;
|
||||
}
|
||||
97
modules/libjar/nsJARURI.h
Normal file
97
modules/libjar/nsJARURI.h
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/* -*- Mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsJARURI_h__
|
||||
#define nsJARURI_h__
|
||||
|
||||
#include "nsIJARURI.h"
|
||||
#include "nsISerializable.h"
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsINestedURI.h"
|
||||
#include "nsIIPCSerializableURI.h"
|
||||
|
||||
#define NS_THIS_JARURI_IMPL_CID \
|
||||
{ /* 9a55f629-730b-4d08-b75b-fa7d9570a691 */ \
|
||||
0x9a55f629, \
|
||||
0x730b, \
|
||||
0x4d08, \
|
||||
{0xb7, 0x5b, 0xfa, 0x7d, 0x95, 0x70, 0xa6, 0x91} \
|
||||
}
|
||||
|
||||
#define NS_JARURI_CID \
|
||||
{ /* 245abae2-b947-4ded-a46d-9829d3cca462 */ \
|
||||
0x245abae2, \
|
||||
0xb947, \
|
||||
0x4ded, \
|
||||
{0xa4, 0x6d, 0x98, 0x29, 0xd3, 0xcc, 0xa4, 0x62} \
|
||||
}
|
||||
|
||||
|
||||
class nsJARURI final : public nsIJARURI,
|
||||
public nsISerializable,
|
||||
public nsIClassInfo,
|
||||
public nsINestedURI,
|
||||
public nsIIPCSerializableURI
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIURI
|
||||
NS_DECL_NSIURIWITHQUERY
|
||||
NS_DECL_NSIURL
|
||||
NS_DECL_NSIJARURI
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
NS_DECL_NSICLASSINFO
|
||||
NS_DECL_NSINESTEDURI
|
||||
NS_DECL_NSIIPCSERIALIZABLEURI
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_THIS_JARURI_IMPL_CID)
|
||||
|
||||
// nsJARURI
|
||||
nsJARURI();
|
||||
|
||||
nsresult Init(const char *charsetHint);
|
||||
nsresult FormatSpec(const nsACString &entryPath, nsACString &result,
|
||||
bool aIncludeScheme = true);
|
||||
nsresult CreateEntryURL(const nsACString& entryFilename,
|
||||
const char* charset,
|
||||
nsIURL** url);
|
||||
nsresult SetSpecWithBase(const nsACString& aSpec, nsIURI* aBaseURL);
|
||||
|
||||
protected:
|
||||
virtual ~nsJARURI();
|
||||
|
||||
// enum used in a few places to specify how .ref attribute should be handled
|
||||
enum RefHandlingEnum {
|
||||
eIgnoreRef,
|
||||
eHonorRef,
|
||||
eReplaceRef
|
||||
};
|
||||
|
||||
// Helper to share code between Equals methods.
|
||||
virtual nsresult EqualsInternal(nsIURI* other,
|
||||
RefHandlingEnum refHandlingMode,
|
||||
bool* result);
|
||||
|
||||
// Helpers to share code between Clone methods.
|
||||
nsresult CloneWithJARFileInternal(nsIURI *jarFile,
|
||||
RefHandlingEnum refHandlingMode,
|
||||
nsIJARURI **result);
|
||||
nsresult CloneWithJARFileInternal(nsIURI *jarFile,
|
||||
RefHandlingEnum refHandlingMode,
|
||||
const nsACString& newRef,
|
||||
nsIJARURI **result);
|
||||
nsCOMPtr<nsIURI> mJARFile;
|
||||
// mJarEntry stored as a URL so that we can easily access things
|
||||
// like extensions, refs, etc.
|
||||
nsCOMPtr<nsIURL> mJAREntry;
|
||||
nsCString mCharsetHint;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsJARURI, NS_THIS_JARURI_IMPL_CID)
|
||||
|
||||
#endif // nsJARURI_h__
|
||||
1294
modules/libjar/nsZipArchive.cpp
Normal file
1294
modules/libjar/nsZipArchive.cpp
Normal file
File diff suppressed because it is too large
Load diff
436
modules/libjar/nsZipArchive.h
Normal file
436
modules/libjar/nsZipArchive.h
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsZipArchive_h_
|
||||
#define nsZipArchive_h_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#define ZIP_TABSIZE 256
|
||||
#define ZIP_BUFLEN (4*1024) /* Used as output buffer when deflating items to a file */
|
||||
|
||||
#include "plarena.h"
|
||||
#include "zlib.h"
|
||||
#include "zipstruct.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsISupportsImpl.h" // For mozilla::ThreadSafeAutoRefCnt
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include "mozilla/FileLocation.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#ifdef HAVE_SEH_EXCEPTIONS
|
||||
#define MOZ_WIN_MEM_TRY_BEGIN __try {
|
||||
#define MOZ_WIN_MEM_TRY_CATCH(cmd) } \
|
||||
__except(GetExceptionCode()==EXCEPTION_IN_PAGE_ERROR ? \
|
||||
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) \
|
||||
{ \
|
||||
NS_WARNING("unexpected EXCEPTION_IN_PAGE_ERROR"); \
|
||||
cmd; \
|
||||
}
|
||||
#else
|
||||
#define MOZ_WIN_MEM_TRY_BEGIN {
|
||||
#define MOZ_WIN_MEM_TRY_CATCH(cmd) }
|
||||
#endif
|
||||
|
||||
class nsZipFind;
|
||||
struct PRFileDesc;
|
||||
|
||||
/**
|
||||
* This file defines some of the basic structures used by libjar to
|
||||
* read Zip files. It makes use of zlib in order to do the decompression.
|
||||
*
|
||||
* A few notes on the classes/structs:
|
||||
* nsZipArchive represents a single Zip file, and maintains an index
|
||||
* of all the items in the file.
|
||||
* nsZipItem represents a single item (file) in the Zip archive.
|
||||
* nsZipFind represents the metadata involved in doing a search,
|
||||
* and current state of the iteration of found objects.
|
||||
* 'MT''safe' reading from the zipfile is performed through JARInputStream,
|
||||
* which maintains its own file descriptor, allowing for multiple reads
|
||||
* concurrently from the same zip file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* nsZipItem -- a helper struct for nsZipArchive
|
||||
*
|
||||
* each nsZipItem represents one file in the archive and all the
|
||||
* information needed to manipulate it.
|
||||
*/
|
||||
class nsZipItem final
|
||||
{
|
||||
public:
|
||||
nsZipItem();
|
||||
|
||||
const char* Name() { return ((const char*)central) + ZIPCENTRAL_SIZE; }
|
||||
|
||||
uint32_t LocalOffset();
|
||||
uint32_t Size();
|
||||
uint32_t RealSize();
|
||||
uint32_t CRC32();
|
||||
uint16_t Date();
|
||||
uint16_t Time();
|
||||
uint16_t Compression();
|
||||
bool IsDirectory();
|
||||
uint16_t Mode();
|
||||
const uint8_t* GetExtraField(uint16_t aTag, uint16_t *aBlockSize);
|
||||
PRTime LastModTime();
|
||||
|
||||
#ifdef XP_UNIX
|
||||
bool IsSymlink();
|
||||
#endif
|
||||
|
||||
nsZipItem* next;
|
||||
const ZipCentral* central;
|
||||
uint16_t nameLength;
|
||||
bool isSynthetic;
|
||||
};
|
||||
|
||||
class nsZipHandle;
|
||||
|
||||
/**
|
||||
* nsZipArchive -- a class for reading the PKZIP file format.
|
||||
*
|
||||
*/
|
||||
class nsZipArchive final
|
||||
{
|
||||
friend class nsZipFind;
|
||||
|
||||
/** destructing the object closes the archive */
|
||||
~nsZipArchive();
|
||||
|
||||
public:
|
||||
static const char* sFileCorruptedReason;
|
||||
|
||||
/** constructing does not open the archive. See OpenArchive() */
|
||||
nsZipArchive();
|
||||
|
||||
/**
|
||||
* OpenArchive
|
||||
*
|
||||
* It's an error to call this more than once on the same nsZipArchive
|
||||
* object. If we were allowed to use exceptions this would have been
|
||||
* part of the constructor
|
||||
*
|
||||
* @param aZipHandle The nsZipHandle used to access the zip
|
||||
* @param aFd Optional PRFileDesc for Windows readahead optimization
|
||||
* @return status code
|
||||
*/
|
||||
nsresult OpenArchive(nsZipHandle *aZipHandle, PRFileDesc *aFd = nullptr);
|
||||
|
||||
/**
|
||||
* OpenArchive
|
||||
*
|
||||
* Convenience function that generates nsZipHandle
|
||||
*
|
||||
* @param aFile The file used to access the zip
|
||||
* @return status code
|
||||
*/
|
||||
nsresult OpenArchive(nsIFile *aFile);
|
||||
|
||||
/**
|
||||
* Test the integrity of items in this archive by running
|
||||
* a CRC check after extracting each item into a memory
|
||||
* buffer. If an entry name is supplied only the
|
||||
* specified item is tested. Else, if null is supplied
|
||||
* then all the items in the archive are tested.
|
||||
*
|
||||
* @return status code
|
||||
*/
|
||||
nsresult Test(const char *aEntryName);
|
||||
|
||||
/**
|
||||
* Closes an open archive.
|
||||
*/
|
||||
nsresult CloseArchive();
|
||||
|
||||
/**
|
||||
* GetItem
|
||||
* @param aEntryName Name of file in the archive
|
||||
* @return pointer to nsZipItem
|
||||
*/
|
||||
nsZipItem* GetItem(const char * aEntryName);
|
||||
|
||||
/**
|
||||
* ExtractFile
|
||||
*
|
||||
* @param zipEntry Name of file in archive to extract
|
||||
* @param outFD Filedescriptor to write contents to
|
||||
* @param outname Name of file to write to
|
||||
* @return status code
|
||||
*/
|
||||
nsresult ExtractFile(nsZipItem * zipEntry, const char *outname, PRFileDesc * outFD);
|
||||
|
||||
/**
|
||||
* FindInit
|
||||
*
|
||||
* Initializes a search for files in the archive. FindNext() returns
|
||||
* the actual matches. The nsZipFind must be deleted when you're done
|
||||
*
|
||||
* @param aPattern a string or RegExp pattern to search for
|
||||
* (may be nullptr to find all files in archive)
|
||||
* @param aFind a pointer to a pointer to a structure used
|
||||
* in FindNext. In the case of an error this
|
||||
* will be set to nullptr.
|
||||
* @return status code
|
||||
*/
|
||||
nsresult FindInit(const char * aPattern, nsZipFind** aFind);
|
||||
|
||||
/*
|
||||
* Gets an undependent handle to the mapped file.
|
||||
*/
|
||||
nsZipHandle* GetFD();
|
||||
|
||||
/**
|
||||
* Gets the data offset.
|
||||
* @param aItem Pointer to nsZipItem
|
||||
* returns 0 on failure.
|
||||
*/
|
||||
uint32_t GetDataOffset(nsZipItem* aItem);
|
||||
|
||||
/**
|
||||
* Get pointer to the data of the item.
|
||||
* @param aItem Pointer to nsZipItem
|
||||
* reutrns null when zip file is corrupt.
|
||||
*/
|
||||
const uint8_t* GetData(nsZipItem* aItem);
|
||||
|
||||
bool GetComment(nsACString &aComment);
|
||||
|
||||
/**
|
||||
* Gets the amount of memory taken up by the archive's mapping.
|
||||
* @return the size
|
||||
*/
|
||||
int64_t SizeOfMapping();
|
||||
|
||||
/*
|
||||
* Refcounting
|
||||
*/
|
||||
NS_METHOD_(MozExternalRefCountType) AddRef(void);
|
||||
NS_METHOD_(MozExternalRefCountType) Release(void);
|
||||
|
||||
private:
|
||||
//--- private members ---
|
||||
mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
nsZipItem* mFiles[ZIP_TABSIZE];
|
||||
PLArenaPool mArena;
|
||||
|
||||
const char* mCommentPtr;
|
||||
uint16_t mCommentLen;
|
||||
|
||||
// Whether we synthesized the directory entries
|
||||
bool mBuiltSynthetics;
|
||||
|
||||
// file handle
|
||||
RefPtr<nsZipHandle> mFd;
|
||||
|
||||
// file URI, for logging
|
||||
nsCString mURI;
|
||||
|
||||
private:
|
||||
//--- private methods ---
|
||||
nsZipItem* CreateZipItem();
|
||||
nsresult BuildFileList(PRFileDesc *aFd = nullptr);
|
||||
nsresult BuildSynthetics();
|
||||
|
||||
nsZipArchive& operator=(const nsZipArchive& rhs) = delete;
|
||||
nsZipArchive(const nsZipArchive& rhs) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* nsZipFind
|
||||
*
|
||||
* a helper class for nsZipArchive, representing a search
|
||||
*/
|
||||
class nsZipFind final
|
||||
{
|
||||
public:
|
||||
nsZipFind(nsZipArchive* aZip, char* aPattern, bool regExp);
|
||||
~nsZipFind();
|
||||
|
||||
nsresult FindNext(const char** aResult, uint16_t* aNameLen);
|
||||
|
||||
private:
|
||||
RefPtr<nsZipArchive> mArchive;
|
||||
char* mPattern;
|
||||
nsZipItem* mItem;
|
||||
uint16_t mSlot;
|
||||
bool mRegExp;
|
||||
|
||||
nsZipFind& operator=(const nsZipFind& rhs) = delete;
|
||||
nsZipFind(const nsZipFind& rhs) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* nsZipCursor -- a low-level class for reading the individual items in a zip.
|
||||
*/
|
||||
class nsZipCursor final
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes the cursor
|
||||
*
|
||||
* @param aItem Item of interest
|
||||
* @param aZip Archive
|
||||
* @param aBuf Buffer used for decompression.
|
||||
* This determines the maximum Read() size in the compressed case.
|
||||
* @param aBufSize Buffer size
|
||||
* @param doCRC When set to true Read() will check crc
|
||||
*/
|
||||
nsZipCursor(nsZipItem *aItem, nsZipArchive *aZip, uint8_t* aBuf = nullptr, uint32_t aBufSize = 0, bool doCRC = false);
|
||||
|
||||
~nsZipCursor();
|
||||
|
||||
/**
|
||||
* Performs reads. In the compressed case it uses aBuf(passed in constructor), for stored files
|
||||
* it returns a zero-copy buffer.
|
||||
*
|
||||
* @param aBytesRead Outparam for number of bytes read.
|
||||
* @return data read or nullptr if item is corrupted.
|
||||
*/
|
||||
uint8_t* Read(uint32_t *aBytesRead) {
|
||||
return ReadOrCopy(aBytesRead, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a copy. It always uses aBuf(passed in constructor).
|
||||
*
|
||||
* @param aBytesRead Outparam for number of bytes read.
|
||||
* @return data read or nullptr if item is corrupted.
|
||||
*/
|
||||
uint8_t* Copy(uint32_t *aBytesRead) {
|
||||
return ReadOrCopy(aBytesRead, true);
|
||||
}
|
||||
|
||||
private:
|
||||
/* Actual implementation for both Read and Copy above */
|
||||
uint8_t* ReadOrCopy(uint32_t *aBytesRead, bool aCopy);
|
||||
|
||||
nsZipItem *mItem;
|
||||
uint8_t *mBuf;
|
||||
uint32_t mBufSize;
|
||||
z_stream mZs;
|
||||
uint32_t mCRC;
|
||||
bool mDoCRC;
|
||||
};
|
||||
|
||||
/**
|
||||
* nsZipItemPtr - a RAII convenience class for reading the individual items in a zip.
|
||||
* It reads whole files and does zero-copy IO for stored files. A buffer is allocated
|
||||
* for decompression.
|
||||
* Do not use when the file may be very large.
|
||||
*/
|
||||
class nsZipItemPtr_base
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes the reader
|
||||
*
|
||||
* @param aZip Archive
|
||||
* @param aEntryName Archive membername
|
||||
* @param doCRC When set to true Read() will check crc
|
||||
*/
|
||||
nsZipItemPtr_base(nsZipArchive *aZip, const char *aEntryName, bool doCRC);
|
||||
|
||||
uint32_t Length() const {
|
||||
return mReadlen;
|
||||
}
|
||||
|
||||
protected:
|
||||
RefPtr<nsZipHandle> mZipHandle;
|
||||
mozilla::UniquePtr<uint8_t[]> mAutoBuf;
|
||||
uint8_t *mReturnBuf;
|
||||
uint32_t mReadlen;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class nsZipItemPtr final : public nsZipItemPtr_base
|
||||
{
|
||||
static_assert(sizeof(T) == sizeof(char),
|
||||
"This class cannot be used with larger T without re-examining"
|
||||
" a number of assumptions.");
|
||||
|
||||
public:
|
||||
nsZipItemPtr(nsZipArchive *aZip, const char *aEntryName, bool doCRC = false) : nsZipItemPtr_base(aZip, aEntryName, doCRC) { }
|
||||
/**
|
||||
* @return buffer containing the whole zip member or nullptr on error.
|
||||
* The returned buffer is owned by nsZipItemReader.
|
||||
*/
|
||||
const T* Buffer() const {
|
||||
return (const T*)mReturnBuf;
|
||||
}
|
||||
|
||||
operator const T*() const {
|
||||
return Buffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Relinquish ownership of zip member if compressed.
|
||||
* Copy member into a new buffer if uncompressed.
|
||||
* @return a buffer with whole zip member. It is caller's responsibility to free() it.
|
||||
*/
|
||||
mozilla::UniquePtr<T[]> Forget() {
|
||||
if (!mReturnBuf)
|
||||
return nullptr;
|
||||
// In uncompressed mmap case, give up buffer
|
||||
if (mAutoBuf.get() == mReturnBuf) {
|
||||
mReturnBuf = nullptr;
|
||||
return mozilla::UniquePtr<T[]>(reinterpret_cast<T*>(mAutoBuf.release()));
|
||||
}
|
||||
auto ret = mozilla::MakeUnique<T[]>(Length());
|
||||
memcpy(ret.get(), mReturnBuf, Length());
|
||||
mReturnBuf = nullptr;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class nsZipHandle final
|
||||
{
|
||||
friend class nsZipArchive;
|
||||
friend class mozilla::FileLocation;
|
||||
public:
|
||||
static nsresult Init(nsIFile *file, nsZipHandle **ret,
|
||||
PRFileDesc **aFd = nullptr);
|
||||
static nsresult Init(nsZipArchive *zip, const char *entry,
|
||||
nsZipHandle **ret);
|
||||
static nsresult Init(const uint8_t* aData, uint32_t aLen,
|
||||
nsZipHandle **aRet);
|
||||
|
||||
NS_METHOD_(MozExternalRefCountType) AddRef(void);
|
||||
NS_METHOD_(MozExternalRefCountType) Release(void);
|
||||
|
||||
int64_t SizeOfMapping();
|
||||
|
||||
nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc);
|
||||
|
||||
protected:
|
||||
const uint8_t * mFileData; /* pointer to zip data */
|
||||
uint32_t mLen; /* length of zip data */
|
||||
mozilla::FileLocation mFile; /* source file if any, for logging */
|
||||
|
||||
private:
|
||||
nsZipHandle();
|
||||
~nsZipHandle();
|
||||
|
||||
nsresult findDataStart();
|
||||
|
||||
PRFileMap * mMap; /* nspr datastructure for mmap */
|
||||
mozilla::AutoFDClose mNSPRFileDesc;
|
||||
nsAutoPtr<nsZipItemPtr<uint8_t> > mBuf;
|
||||
mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
const uint8_t * mFileStart; /* pointer to mmaped file */
|
||||
uint32_t mTotalLen; /* total length of the mmaped file */
|
||||
|
||||
/* Magic number for CRX type expressed in Big Endian since it is a literal */
|
||||
static const uint32_t kCRXMagic = 0x34327243;
|
||||
};
|
||||
|
||||
nsresult gZlibInit(z_stream *zs);
|
||||
|
||||
#endif /* nsZipArchive_h_ */
|
||||
9
modules/libjar/test/chrome/chrome.ini
Normal file
9
modules/libjar/test/chrome/chrome.ini
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
signed-added.zip
|
||||
signed-badca.zip
|
||||
signed-tampered.zip
|
||||
signed.zip
|
||||
unsigned.zip
|
||||
|
||||
[test_bug386153.html]
|
||||
BIN
modules/libjar/test/chrome/signed-added.zip
Normal file
BIN
modules/libjar/test/chrome/signed-added.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/chrome/signed-badca.zip
Normal file
BIN
modules/libjar/test/chrome/signed-badca.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/chrome/signed-tampered.zip
Normal file
BIN
modules/libjar/test/chrome/signed-tampered.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/chrome/signed.zip
Normal file
BIN
modules/libjar/test/chrome/signed.zip
Normal file
Binary file not shown.
97
modules/libjar/test/chrome/test_bug386153.html
Normal file
97
modules/libjar/test/chrome/test_bug386153.html
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=386153
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 386153</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=386153">Mozilla Bug 386153</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 386153 **/
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
// Opens a zip file from the test directory.
|
||||
function openZip(path) {
|
||||
|
||||
var location = window.location.href;
|
||||
location = getRootDirectory(location);
|
||||
var jar = getJar(location);
|
||||
if (jar != null) {
|
||||
var resolved = extractJarToTmp(jar);
|
||||
} else {
|
||||
var resolvedURI = getResolvedURI(window.location.href);
|
||||
var resolved = getChromeDir(resolvedURI);
|
||||
}
|
||||
resolved.append(path);
|
||||
|
||||
var zip = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zip.open(resolved);
|
||||
return zip;
|
||||
}
|
||||
|
||||
// Gets the pretty name from the signing cert or null if the zip is unsigned.
|
||||
function getSigner(zip) {
|
||||
var signingCert = zip.getSigningCert(null);
|
||||
if (signingCert) {
|
||||
return signingCert.organization;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function verifySigning(zip) {
|
||||
var signingCert = zip.getSigningCert(null);
|
||||
var count = 0;
|
||||
var entries = zip.findEntries(null);
|
||||
while (entries.hasMore()) {
|
||||
var entry = entries.getNext();
|
||||
// Nothing in META-INF is in the manifest.
|
||||
if (entry.substr(0, 9) == "META-INF/")
|
||||
continue;
|
||||
// Directory entries aren't in the manifest.
|
||||
if (entry.substr(-1) == "/")
|
||||
continue;
|
||||
count++;
|
||||
var entryCert = zip.getSigningCert(entry);
|
||||
if (!entryCert || !signingCert.equals(entryCert)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return zip.manifestEntriesCount == count;
|
||||
}
|
||||
|
||||
var zip = openZip("unsigned.zip");
|
||||
is(getSigner(zip), null, "Should not be signed");
|
||||
|
||||
zip = openZip("signed.zip");
|
||||
is(getSigner(zip), "Mozilla Testing", "Should be signed by the right cert");
|
||||
ok(verifySigning(zip), "Should be correctly signed");
|
||||
|
||||
zip = openZip("signed-added.zip");
|
||||
is(getSigner(zip), "Mozilla Testing", "Should be signed by the right cert");
|
||||
ok(!verifySigning(zip), "Should be incorrectly signed");
|
||||
|
||||
zip = openZip("signed-tampered.zip");
|
||||
is(getSigner(zip), "Mozilla Testing", "Should be signed by the right cert");
|
||||
ok(!verifySigning(zip), "Should be incorrectly signed");
|
||||
|
||||
zip = openZip("signed-badca.zip");
|
||||
is(getSigner(zip), null, "Should not appear to be signed");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
BIN
modules/libjar/test/chrome/unsigned.zip
Normal file
BIN
modules/libjar/test/chrome/unsigned.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/mochitest/bug403331.zip
Normal file
BIN
modules/libjar/test/mochitest/bug403331.zip
Normal file
Binary file not shown.
1
modules/libjar/test/mochitest/bug403331.zip^headers^
Normal file
1
modules/libjar/test/mochitest/bug403331.zip^headers^
Normal file
|
|
@ -0,0 +1 @@
|
|||
Content-Type: application/java-archive
|
||||
11
modules/libjar/test/mochitest/mochitest.ini
Normal file
11
modules/libjar/test/mochitest/mochitest.ini
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
bug403331.zip
|
||||
bug403331.zip^headers^
|
||||
openredirect.sjs
|
||||
!/dom/base/test/file_bug945152.jar
|
||||
|
||||
[test_bug403331.html]
|
||||
[test_bug1034143_mapped.html]
|
||||
run-if = os == 'linux'
|
||||
[test_bug1173171.html]
|
||||
5
modules/libjar/test/mochitest/openredirect.sjs
Normal file
5
modules/libjar/test/mochitest/openredirect.sjs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
function handleRequest(request, response)
|
||||
{
|
||||
response.setStatusLine(request.httpVersion, 301, "Moved Permanently");
|
||||
response.setHeader("Location", request.queryString, false);
|
||||
}
|
||||
53
modules/libjar/test/mochitest/test_bug1034143_mapped.html
Normal file
53
modules/libjar/test/mochitest/test_bug1034143_mapped.html
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1034143
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 945152</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1034143">Mozilla Bug 1034143</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.7">
|
||||
// Ensure that XMLHttpRequest's memory-mapping code can handle a case
|
||||
// where the nsIJARChannel's jarFile property is null, but which is
|
||||
// otherwise eligible for bug 945152's memory-mapping optimization.
|
||||
|
||||
function runTest() {
|
||||
const jarURL = "jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_1.txt";
|
||||
let xhr = new XMLHttpRequest({ mozAnon: true, mozSystem: true });
|
||||
xhr.open("GET", jarURL);
|
||||
xhr.onerror = function onerror(e) {
|
||||
ok(false, "JAR XHR failed: " + e.status);
|
||||
SimpleTest.finish();
|
||||
};
|
||||
xhr.onload = function onload(e) {
|
||||
ok(xhr.status == 200, "Status is 200");
|
||||
let ct = xhr.getResponseHeader("Content-Type");
|
||||
ok(ct.indexOf("mem-mapped") == -1, "Data is not memory-mapped");
|
||||
SimpleTest.finish();
|
||||
};
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.mapped_arraybuffer.enabled", true],
|
||||
["network.jar.block-remote-files", false]]}, function() {
|
||||
SpecialPowers.pushPermissions([{'type': 'systemXHR', 'allow': true, 'context': document}], runTest);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
64
modules/libjar/test/mochitest/test_bug1173171.html
Normal file
64
modules/libjar/test/mochitest/test_bug1173171.html
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1173171
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1173171</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<iframe id="testFrame"></iframe>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript;version=1.7">
|
||||
|
||||
/** Test for Bug 1173171 **/
|
||||
|
||||
// __setPref(key, value)__.
|
||||
// Set a pref value asynchronously, returning a prmoise that resolves
|
||||
// when it succeeds.
|
||||
let pushPref = function (key, value) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
SpecialPowers.pushPrefEnv({"set": [[key, value]]}, resolve);
|
||||
});
|
||||
};
|
||||
|
||||
// __xhr(method, url, responseType__.
|
||||
// A simple async XMLHttpRequest call.
|
||||
// Returns a promise with the response.
|
||||
let xhr = function (method, url, responseType) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open(method, url, true);
|
||||
xhr.onload = function () {
|
||||
resolve(xhr.response);
|
||||
};
|
||||
xhr.onerror = function() {
|
||||
resolve(null);
|
||||
};
|
||||
xhr.responseType = responseType;
|
||||
xhr.send();
|
||||
});
|
||||
};
|
||||
|
||||
let jarURL = "jar:http://mochi.test:8888/tests/modules/libjar/test/mochitest/bug403331.zip!/test.html";
|
||||
|
||||
// Test behavior when blocking is deactivated and activated.
|
||||
add_task(function* () {
|
||||
for (let shouldBlock of [false, true]) {
|
||||
yield pushPref("network.jar.block-remote-files", shouldBlock);
|
||||
let response = yield xhr("GET", jarURL, "document");
|
||||
ok(shouldBlock === (response === null),
|
||||
"Remote jars should be blocked if and only if the 'network.jar.block-remote-files' pref is active.");
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
47
modules/libjar/test/mochitest/test_bug403331.html
Normal file
47
modules/libjar/test/mochitest/test_bug403331.html
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=403331
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 403331</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<iframe id="testFrame"></iframe>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 403331 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest() {
|
||||
var testFrame = document.getElementById('testFrame');
|
||||
|
||||
// Try a redirected load from another domain to this one.
|
||||
|
||||
testFrame.onload = function() {
|
||||
// If properly redirected, we'll be able to access elements in the loaded
|
||||
// document.
|
||||
var item = testFrame.contentDocument.getElementById('testitem');
|
||||
is(item.textContent, "testcontents", "Should be able to access the child document");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
testFrame.src = "jar:http://example.org:80/tests/modules/libjar/test/mochitest/openredirect.sjs?http://mochi.test:8888/tests/modules/libjar/test/mochitest/bug403331.zip!/test.html";
|
||||
}
|
||||
|
||||
addLoadEvent(function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["network.jar.block-remote-files", false]]}, runTest);
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
0
modules/libjar/test/unit/data/empty
Normal file
0
modules/libjar/test/unit/data/empty
Normal file
BIN
modules/libjar/test/unit/data/test_bug333423.zip
Normal file
BIN
modules/libjar/test/unit/data/test_bug333423.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/unit/data/test_bug336691.zip
Normal file
BIN
modules/libjar/test/unit/data/test_bug336691.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/unit/data/test_bug370103.jar
Normal file
BIN
modules/libjar/test/unit/data/test_bug370103.jar
Normal file
Binary file not shown.
BIN
modules/libjar/test/unit/data/test_bug379841.zip
Normal file
BIN
modules/libjar/test/unit/data/test_bug379841.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/unit/data/test_bug589292.zip
Normal file
BIN
modules/libjar/test/unit/data/test_bug589292.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/unit/data/test_bug597702.zip
Normal file
BIN
modules/libjar/test/unit/data/test_bug597702.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/unit/data/test_bug637286.zip
Normal file
BIN
modules/libjar/test/unit/data/test_bug637286.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/unit/data/test_bug658093.zip
Normal file
BIN
modules/libjar/test/unit/data/test_bug658093.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/unit/data/test_corrupt.zip
Normal file
BIN
modules/libjar/test/unit/data/test_corrupt.zip
Normal file
Binary file not shown.
1
modules/libjar/test/unit/data/test_corrupt2.zip
Normal file
1
modules/libjar/test/unit/data/test_corrupt2.zip
Normal file
|
|
@ -0,0 +1 @@
|
|||
2
|
||||
BIN
modules/libjar/test/unit/data/test_corrupt3.zip
Normal file
BIN
modules/libjar/test/unit/data/test_corrupt3.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/unit/data/test_crx_dummy.crx
Normal file
BIN
modules/libjar/test/unit/data/test_crx_dummy.crx
Normal file
Binary file not shown.
BIN
modules/libjar/test/unit/data/test_umlaute.zip
Normal file
BIN
modules/libjar/test/unit/data/test_umlaute.zip
Normal file
Binary file not shown.
BIN
modules/libjar/test/unit/data/uncompressed.zip
Normal file
BIN
modules/libjar/test/unit/data/uncompressed.zip
Normal file
Binary file not shown.
39
modules/libjar/test/unit/test_bug278262.js
Normal file
39
modules/libjar/test/unit/test_bug278262.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// Regression test for bug 278262 - JAR URIs should resolve relative URIs in the base section.
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
const path = "data/test_bug333423.zip";
|
||||
|
||||
function test_relative_sub() {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
|
||||
var spec = "jar:" + ios.newFileURI(do_get_file(path)).spec + "!/";
|
||||
var base = ios.newURI(spec, null, null);
|
||||
var uri = ios.newURI("../modules/libjar", null, base);
|
||||
|
||||
// This is the URI we expect to see.
|
||||
var expected = "jar:" + ios.newFileURI(do_get_file(path)).spec +
|
||||
"!/modules/libjar";
|
||||
|
||||
do_check_eq(uri.spec, expected);
|
||||
}
|
||||
|
||||
function test_relative_base() {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
|
||||
var base = ios.newFileURI(do_get_file("data/empty"));
|
||||
var uri = ios.newURI("jar:../" + path + "!/", null, base);
|
||||
|
||||
// This is the URI we expect to see.
|
||||
var expected = "jar:" + ios.newFileURI(do_get_file(path)).spec +
|
||||
"!/";
|
||||
|
||||
do_check_eq(uri.spec, expected);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
test_relative_sub();
|
||||
test_relative_base();
|
||||
}
|
||||
22
modules/libjar/test/unit/test_bug333423.js
Normal file
22
modules/libjar/test/unit/test_bug333423.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Regression test for bug 333423 - crash enumerating entries of a
|
||||
// closed nsIZipReader
|
||||
function run_test() {
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
// the build script have created the zip we can test on in the current dir.
|
||||
var file = do_get_file("data/test_bug333423.zip");
|
||||
|
||||
var zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipreader.open(file);
|
||||
zipreader.close();
|
||||
var entries = zipreader.findEntries('*.*');
|
||||
do_check_true(!entries.hasMore()); // this shouldn't crash
|
||||
}
|
||||
12
modules/libjar/test/unit/test_bug336691.js
Normal file
12
modules/libjar/test/unit/test_bug336691.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Regression test for bug 336691 - nsZipArchive::Test shouldn't try to ExtractFile on directories.
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
function run_test() {
|
||||
var file = do_get_file("data/test_bug336691.zip");
|
||||
var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipReader.open(file);
|
||||
zipReader.test(null); // We shouldn't crash here.
|
||||
zipReader.close();
|
||||
}
|
||||
28
modules/libjar/test/unit/test_bug370103.js
Normal file
28
modules/libjar/test/unit/test_bug370103.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
// Regression test for bug 370103 - crash when passing a null listener to
|
||||
// nsIChannel.asyncOpen
|
||||
function run_test() {
|
||||
// Compose the jar: url
|
||||
var ioService = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var file = do_get_file("data/test_bug370103.jar");
|
||||
var url = ioService.newFileURI(file).spec;
|
||||
url = "jar:" + url + "!/test_bug370103";
|
||||
|
||||
// Try opening channel with null listener
|
||||
var channel = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
|
||||
|
||||
var exception = false;
|
||||
try {
|
||||
channel.asyncOpen2(null);
|
||||
}
|
||||
catch(e) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
do_check_true(exception); // should throw exception instead of crashing
|
||||
}
|
||||
23
modules/libjar/test/unit/test_bug379841.js
Normal file
23
modules/libjar/test/unit/test_bug379841.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// Regression test for bug 379841 - nsIZipReader's last modified time ignores seconds
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
const path = "data/test_bug379841.zip";
|
||||
// Retrieved time should be within 2 seconds of original file's time.
|
||||
const MAX_TIME_DIFF = 2000000;
|
||||
|
||||
var ENTRY_NAME = "test";
|
||||
// Actual time of file was 07 May 2007 13:35:49 UTC
|
||||
var ENTRY_TIME = new Date(Date.UTC(2007, 4, 7, 13, 35, 49, 0));
|
||||
|
||||
function run_test() {
|
||||
var file = do_get_file(path);
|
||||
var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipReader.open(file);
|
||||
var entry = zipReader.getEntry(ENTRY_NAME);
|
||||
var diff = Math.abs(entry.lastModifiedTime - ENTRY_TIME.getTime()*1000);
|
||||
zipReader.close();
|
||||
if (diff >= MAX_TIME_DIFF)
|
||||
do_throw(diff);
|
||||
}
|
||||
42
modules/libjar/test/unit/test_bug407303.js
Normal file
42
modules/libjar/test/unit/test_bug407303.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Regression test for bug 407303 - A failed channel should not be checked
|
||||
// for an unsafe content type.
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
// XXX: NS_ERROR_UNKNOWN_HOST is not in Components.results
|
||||
const NS_ERROR_UNKNOWN_HOST = 0x804B001E;
|
||||
|
||||
var listener = {
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIRequestObserver))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
onStartRequest: function(request, context) {
|
||||
},
|
||||
|
||||
onDataAvailable: function(request, context, stream, offset, count) {
|
||||
do_throw("shouldn't get data!");
|
||||
},
|
||||
|
||||
onStopRequest: function(request, context, status) {
|
||||
do_check_eq(status, NS_ERROR_UNKNOWN_HOST);
|
||||
do_test_finished();
|
||||
}
|
||||
};
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("network.jar.block-remote-files", false);
|
||||
var channel = NetUtil.newChannel({
|
||||
uri: "jar:http://test.invalid/test.jar!/index.html",
|
||||
loadUsingSystemPrincipal: true}
|
||||
);
|
||||
channel.asyncOpen2(listener);
|
||||
do_test_pending();
|
||||
}
|
||||
12
modules/libjar/test/unit/test_bug453254.js
Normal file
12
modules/libjar/test/unit/test_bug453254.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
function run_test() {
|
||||
const zipCache = Components.classes["@mozilla.org/libjar/zip-reader-cache;1"]
|
||||
.createInstance(Components.interfaces.nsIZipReaderCache);
|
||||
zipCache.init(1024);
|
||||
try {
|
||||
zipCache.getZip(null);
|
||||
do_throw("Shouldn't get here!");
|
||||
} catch (e if ((e instanceof Components.interfaces.nsIException) &&
|
||||
(e.result == Components.results.NS_ERROR_INVALID_POINTER))) {
|
||||
// do nothing, this test passes
|
||||
}
|
||||
}
|
||||
11
modules/libjar/test/unit/test_bug458158.js
Normal file
11
modules/libjar/test/unit/test_bug458158.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
function run_test() {
|
||||
var zReader = Components.classes["@mozilla.org/libjar/zip-reader;1"]
|
||||
.createInstance(Components.interfaces.nsIZipReader);
|
||||
try {
|
||||
zReader.open(null);
|
||||
do_throw("Shouldn't get here!");
|
||||
} catch (e if (e instanceof Components.interfaces.nsIException &&
|
||||
e.result == Components.results.NS_ERROR_NULL_POINTER)) {
|
||||
// do nothing, this test passes
|
||||
}
|
||||
}
|
||||
25
modules/libjar/test/unit/test_bug589292.js
Normal file
25
modules/libjar/test/unit/test_bug589292.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Make sure we behave appropriately when asking for content-disposition
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
const path = "data/test_bug589292.zip";
|
||||
|
||||
function run_test() {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var spec = "jar:" + ios.newFileURI(do_get_file(path)).spec + "!/foo.txt";
|
||||
var channel = NetUtil.newChannel({uri: spec, loadUsingSystemPrincipal: true});
|
||||
instr = channel.open2();
|
||||
var val;
|
||||
try {
|
||||
val = channel.contentDisposition;
|
||||
do_check_true(false, "The channel has content disposition?!");
|
||||
} catch (e) {
|
||||
// This is what we want to happen - there's no underlying channel, so no
|
||||
// content-disposition header is available
|
||||
do_check_true(true, "How are you reading this?!");
|
||||
}
|
||||
}
|
||||
35
modules/libjar/test/unit/test_bug597702.js
Normal file
35
modules/libjar/test/unit/test_bug597702.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
// Check that reading non existant inner jars results in the right error
|
||||
|
||||
function run_test() {
|
||||
var file = do_get_file("data/test_bug597702.zip");
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var outerJarBase = "jar:" + ios.newFileURI(file).spec + "!/";
|
||||
var goodSpec = "jar:" + outerJarBase + "inner.jar!/hello";
|
||||
var badSpec = "jar:" + outerJarBase + "jar_that_isnt_in_the.jar!/hello";
|
||||
var goodChannel = NetUtil.newChannel({uri: goodSpec, loadUsingSystemPrincipal: true});
|
||||
var badChannel = NetUtil.newChannel({uri: badSpec, loadUsingSystemPrincipal: true});
|
||||
|
||||
try {
|
||||
instr = goodChannel.open2();
|
||||
} catch (e) {
|
||||
do_throw("Failed to open file in inner jar");
|
||||
}
|
||||
|
||||
try {
|
||||
instr = badChannel.open2();
|
||||
do_throw("Failed to report that file doesn't exist");
|
||||
} catch (e) {
|
||||
do_check_true(e.name == "NS_ERROR_FILE_NOT_FOUND");
|
||||
}
|
||||
}
|
||||
|
||||
29
modules/libjar/test/unit/test_bug637286.js
Normal file
29
modules/libjar/test/unit/test_bug637286.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
// Check that the zip cache can expire entries from nested jars
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
|
||||
function open_inner_zip(base, idx) {
|
||||
var spec = "jar:" + base + "inner" + idx + ".zip!/foo";
|
||||
var channel = NetUtil.newChannel({uri: spec, loadUsingSystemPrincipal: true});
|
||||
var stream = channel.open2();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
var file = do_get_file("data/test_bug637286.zip");
|
||||
var outerJarBase = "jar:" + ios.newFileURI(file).spec + "!/";
|
||||
|
||||
for (var i = 0; i < 40; i++) {
|
||||
open_inner_zip(outerJarBase, i);
|
||||
gc();
|
||||
}
|
||||
}
|
||||
|
||||
25
modules/libjar/test/unit/test_bug658093.js
Normal file
25
modules/libjar/test/unit/test_bug658093.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
// Check that we don't crash on reading a directory entry signature
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
|
||||
function run_test() {
|
||||
var file = do_get_file("data/test_bug658093.zip");
|
||||
var spec = "jar:" + ios.newFileURI(file).spec + "!/0000";
|
||||
var channel = NetUtil.newChannel({uri: spec, loadUsingSystemPrincipal: true});
|
||||
var failed = false;
|
||||
try {
|
||||
var stream = channel.open2();
|
||||
} catch (e) {
|
||||
failed = true;
|
||||
}
|
||||
do_check_true(failed);
|
||||
}
|
||||
34
modules/libjar/test/unit/test_corrupt_1211262.js
Normal file
34
modules/libjar/test/unit/test_corrupt_1211262.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Regression test ensuring that that a STORED entry with differing compressed
|
||||
// and uncompressed sizes is considered to be corrupt.
|
||||
function run_test() {
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
var file = do_get_file("data/test_corrupt3.zip");
|
||||
|
||||
var zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipreader.open(file);
|
||||
|
||||
var entries = zipreader.findEntries('*');
|
||||
var failed = false;
|
||||
|
||||
while (entries.hasMore()) {
|
||||
let entryPath = entries.getNext();
|
||||
let entry = zipreader.getEntry(entryPath);
|
||||
if (!entry.isDirectory) {
|
||||
try {
|
||||
let inputStream = zipreader.getInputStream(entryPath);
|
||||
} catch (e) {
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_check_true(failed);
|
||||
}
|
||||
|
||||
36
modules/libjar/test/unit/test_corrupt_536911.js
Normal file
36
modules/libjar/test/unit/test_corrupt_536911.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function wrapInputStream(input)
|
||||
{
|
||||
var nsIScriptableInputStream = Components.interfaces.nsIScriptableInputStream;
|
||||
var factory = Components.classes["@mozilla.org/scriptableinputstream;1"];
|
||||
var wrapper = factory.createInstance(nsIScriptableInputStream);
|
||||
wrapper.init(input);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Check that files can be read from after closing zipreader
|
||||
function run_test() {
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
// the build script have created the zip we can test on in the current dir.
|
||||
var file = do_get_file("data/test_corrupt.zip");
|
||||
|
||||
var zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipreader.open(file);
|
||||
// var entries = zipreader.findEntries(null);
|
||||
// the signature for file is corrupt, should not segfault
|
||||
var failed = false;
|
||||
try {
|
||||
var stream = wrapInputStream(zipreader.getInputStream("file"));
|
||||
stream.read(1024);
|
||||
} catch (ex) {
|
||||
failed = true;
|
||||
}
|
||||
do_check_true(failed);
|
||||
}
|
||||
|
||||
24
modules/libjar/test/unit/test_corrupt_541828.js
Normal file
24
modules/libjar/test/unit/test_corrupt_541828.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Check that files can be read from after closing zipreader
|
||||
function run_test() {
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
// the build script have created the zip we can test on in the current dir.
|
||||
var file = do_get_file("data/test_corrupt2.zip");
|
||||
|
||||
var zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
var failed = false;
|
||||
try {
|
||||
zipreader.open(file);
|
||||
// corrupt files should trigger an exception
|
||||
} catch (ex) {
|
||||
failed = true;
|
||||
}
|
||||
do_check_true(failed);
|
||||
}
|
||||
|
||||
43
modules/libjar/test/unit/test_crx.js
Normal file
43
modules/libjar/test/unit/test_crx.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function wrapInputStream(input)
|
||||
{
|
||||
let nsIScriptableInputStream = Components.interfaces.nsIScriptableInputStream;
|
||||
let factory = Components.classes["@mozilla.org/scriptableinputstream;1"];
|
||||
let wrapper = factory.createInstance(nsIScriptableInputStream);
|
||||
wrapper.init(input);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Make sure that we can read from CRX files as if they were ZIP files.
|
||||
function run_test() {
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
// Note: test_crx_dummy.crx is a dummy crx file created for this test. The
|
||||
// public key and signature fields in the header are both empty.
|
||||
let file = do_get_file("data/test_crx_dummy.crx");
|
||||
|
||||
let zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipreader.open(file);
|
||||
// do crc stuff
|
||||
function check_archive_crc() {
|
||||
zipreader.test(null);
|
||||
return true;
|
||||
}
|
||||
Assert.ok(check_archive_crc())
|
||||
let entries = zipreader.findEntries(null);
|
||||
let stream = wrapInputStream(zipreader.getInputStream("modules/libjar/test/Makefile.in"))
|
||||
let dirstream= wrapInputStream(zipreader.getInputStream("modules/libjar/test/"))
|
||||
zipreader.close();
|
||||
zipreader = null;
|
||||
Components.utils.forceGC();
|
||||
Assert.ok(stream.read(1024).length > 0);
|
||||
Assert.ok(dirstream.read(100).length > 0);
|
||||
}
|
||||
|
||||
25
modules/libjar/test/unit/test_dirjar_bug525755.js
Normal file
25
modules/libjar/test/unit/test_dirjar_bug525755.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Check that we refuse to open weird files
|
||||
function run_test() {
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
// open a bogus file
|
||||
var file = do_get_file("/");
|
||||
|
||||
var zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
var failed = false;
|
||||
try {
|
||||
zipreader.open(file);
|
||||
} catch (e) {
|
||||
failed = true;
|
||||
}
|
||||
do_check_true(failed);
|
||||
zipreader = null;
|
||||
}
|
||||
|
||||
216
modules/libjar/test/unit/test_jarchannel.js
Normal file
216
modules/libjar/test/unit/test_jarchannel.js
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests some basic jar channel functionality
|
||||
*/
|
||||
|
||||
|
||||
const {classes: Cc,
|
||||
interfaces: Ci,
|
||||
results: Cr,
|
||||
utils: Cu,
|
||||
Constructor: ctor
|
||||
} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
const ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
const dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
const obs = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
|
||||
const nsIBinaryInputStream = ctor("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream",
|
||||
"setInputStream"
|
||||
);
|
||||
|
||||
const fileBase = "test_bug637286.zip";
|
||||
const file = do_get_file("data/" + fileBase);
|
||||
const jarBase = "jar:" + ios.newFileURI(file).spec + "!";
|
||||
const tmpDir = dirSvc.get("TmpD", Ci.nsIFile);
|
||||
|
||||
function Listener(callback) {
|
||||
this._callback = callback;
|
||||
}
|
||||
Listener.prototype = {
|
||||
gotStartRequest: false,
|
||||
available: -1,
|
||||
gotStopRequest: false,
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIRequestObserver))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
onDataAvailable: function(request, ctx, stream, offset, count) {
|
||||
try {
|
||||
this.available = stream.available();
|
||||
do_check_eq(this.available, count);
|
||||
// Need to consume stream to avoid assertion
|
||||
new nsIBinaryInputStream(stream).readBytes(count);
|
||||
}
|
||||
catch (ex) {
|
||||
do_throw(ex);
|
||||
}
|
||||
},
|
||||
onStartRequest: function(request, ctx) {
|
||||
this.gotStartRequest = true;
|
||||
},
|
||||
onStopRequest: function(request, ctx, status) {
|
||||
this.gotStopRequest = true;
|
||||
do_check_eq(status, 0);
|
||||
if (this._callback) {
|
||||
this._callback.call(null, this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Basic reading test for asynchronously opened jar channel
|
||||
*/
|
||||
function testAsync() {
|
||||
var uri = jarBase + "/inner40.zip";
|
||||
var chan = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true});
|
||||
do_check_true(chan.contentLength < 0);
|
||||
chan.asyncOpen2(new Listener(function(l) {
|
||||
do_check_true(chan.contentLength > 0);
|
||||
do_check_true(l.gotStartRequest);
|
||||
do_check_true(l.gotStopRequest);
|
||||
do_check_eq(l.available, chan.contentLength);
|
||||
|
||||
run_next_test();
|
||||
}));
|
||||
}
|
||||
|
||||
add_test(testAsync);
|
||||
// Run same test again so we test the codepath for a zipcache hit
|
||||
add_test(testAsync);
|
||||
|
||||
/**
|
||||
* Basic test for nsIZipReader.
|
||||
*/
|
||||
function testZipEntry() {
|
||||
var uri = jarBase + "/inner40.zip";
|
||||
var chan = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true})
|
||||
.QueryInterface(Ci.nsIJARChannel);
|
||||
var entry = chan.zipEntry;
|
||||
do_check_true(entry.CRC32 == 0x8b635486);
|
||||
do_check_true(entry.realSize == 184);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(testZipEntry);
|
||||
|
||||
|
||||
/**
|
||||
* Basic reading test for synchronously opened jar channels
|
||||
*/
|
||||
add_test(function testSync() {
|
||||
var uri = jarBase + "/inner40.zip";
|
||||
var chan = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true});
|
||||
var stream = chan.open2();
|
||||
do_check_true(chan.contentLength > 0);
|
||||
do_check_eq(stream.available(), chan.contentLength);
|
||||
stream.close();
|
||||
stream.close(); // should still not throw
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Basic reading test for synchronously opened, nested jar channels
|
||||
*/
|
||||
add_test(function testSyncNested() {
|
||||
var uri = "jar:" + jarBase + "/inner40.zip!/foo";
|
||||
var chan = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true});
|
||||
var stream = chan.open2();
|
||||
do_check_true(chan.contentLength > 0);
|
||||
do_check_eq(stream.available(), chan.contentLength);
|
||||
stream.close();
|
||||
stream.close(); // should still not throw
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Basic reading test for asynchronously opened, nested jar channels
|
||||
*/
|
||||
add_test(function testAsyncNested(next) {
|
||||
var uri = "jar:" + jarBase + "/inner40.zip!/foo";
|
||||
var chan = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true});
|
||||
chan.asyncOpen2(new Listener(function(l) {
|
||||
do_check_true(chan.contentLength > 0);
|
||||
do_check_true(l.gotStartRequest);
|
||||
do_check_true(l.gotStopRequest);
|
||||
do_check_eq(l.available, chan.contentLength);
|
||||
|
||||
run_next_test();
|
||||
}));
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify that file locks are released when closing a synchronously
|
||||
* opened jar channel stream
|
||||
*/
|
||||
add_test(function testSyncCloseUnlocks() {
|
||||
var copy = tmpDir.clone();
|
||||
copy.append(fileBase);
|
||||
file.copyTo(copy.parent, copy.leafName);
|
||||
var uri = "jar:" + ios.newFileURI(copy).spec + "!/inner40.zip";
|
||||
var chan = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true});
|
||||
var stream = chan.open2();
|
||||
do_check_true(chan.contentLength > 0);
|
||||
stream.close();
|
||||
|
||||
// Drop any jar caches
|
||||
obs.notifyObservers(null, "chrome-flush-caches", null);
|
||||
|
||||
try {
|
||||
copy.remove(false);
|
||||
}
|
||||
catch (ex) {
|
||||
do_throw(ex);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify that file locks are released when closing an asynchronously
|
||||
* opened jar channel stream
|
||||
*/
|
||||
add_test(function testAsyncCloseUnlocks() {
|
||||
var copy = tmpDir.clone();
|
||||
copy.append(fileBase);
|
||||
file.copyTo(copy.parent, copy.leafName);
|
||||
|
||||
var uri = "jar:" + ios.newFileURI(copy).spec + "!/inner40.zip";
|
||||
var chan = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true});
|
||||
|
||||
chan.asyncOpen2(new Listener(function (l) {
|
||||
do_check_true(chan.contentLength > 0);
|
||||
|
||||
// Drop any jar caches
|
||||
obs.notifyObservers(null, "chrome-flush-caches", null);
|
||||
|
||||
try {
|
||||
copy.remove(false);
|
||||
}
|
||||
catch (ex) {
|
||||
do_throw(ex);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
function run_test() {
|
||||
return run_next_test();
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function wrapInputStream(input)
|
||||
{
|
||||
var nsIScriptableInputStream = Components.interfaces.nsIScriptableInputStream;
|
||||
var factory = Components.classes["@mozilla.org/scriptableinputstream;1"];
|
||||
var wrapper = factory.createInstance(nsIScriptableInputStream);
|
||||
wrapper.init(input);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Check that files can be read from after closing zipreader
|
||||
function run_test() {
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
// the build script have created the zip we can test on in the current dir.
|
||||
var file = do_get_file("data/test_bug333423.zip");
|
||||
|
||||
var zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipreader.open(file);
|
||||
// do crc stuff
|
||||
function check_archive_crc() {
|
||||
zipreader.test(null);
|
||||
return true;
|
||||
}
|
||||
do_check_true(check_archive_crc())
|
||||
var entries = zipreader.findEntries(null);
|
||||
var stream = wrapInputStream(zipreader.getInputStream("modules/libjar/test/Makefile.in"))
|
||||
var dirstream= wrapInputStream(zipreader.getInputStream("modules/libjar/test/"))
|
||||
zipreader.close();
|
||||
zipreader = null;
|
||||
Components.utils.forceGC();
|
||||
do_check_true(stream.read(1024).length > 0);
|
||||
do_check_true(dirstream.read(100).length > 0);
|
||||
}
|
||||
|
||||
24
modules/libjar/test/unit/test_not_found.js
Normal file
24
modules/libjar/test/unit/test_not_found.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Should report file not found on non-existent files
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
const path = "data/test_bug333423.zip";
|
||||
|
||||
function run_test() {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var spec = "jar:" + ios.newFileURI(do_get_file(path)).spec + "!/";
|
||||
var channel = NetUtil.newChannel({
|
||||
uri: spec + "file_that_isnt_in.archive",
|
||||
loadUsingSystemPrincipal: true
|
||||
});
|
||||
try {
|
||||
instr = channel.open2();
|
||||
do_throw("Failed to report that file doesn't exist")
|
||||
} catch (e) {
|
||||
do_check_true(e.name == "NS_ERROR_FILE_NOT_FOUND")
|
||||
}
|
||||
}
|
||||
40
modules/libjar/test/unit/test_umlaute.js
Normal file
40
modules/libjar/test/unit/test_umlaute.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
function run_test() {
|
||||
var dirService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
|
||||
var tmpDir = dirService.get("TmpD", Ci.nsIFile);
|
||||
|
||||
var zipfile = do_get_file("data/test_umlaute.zip");
|
||||
|
||||
var testFile = tmpDir.clone();
|
||||
testFile.append("test_\u00FC.txt");
|
||||
if (testFile.exists()) {
|
||||
testFile.remove(false);
|
||||
}
|
||||
|
||||
var zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(Ci.nsIZipReader);
|
||||
zipreader.open(zipfile);
|
||||
|
||||
var entries = zipreader.findEntries(null);
|
||||
do_check_true(entries.hasMore());
|
||||
|
||||
var entryName = entries.getNext();
|
||||
do_check_eq(entryName, "test_\u00FC.txt");
|
||||
|
||||
do_check_true(zipreader.hasEntry(entryName));
|
||||
|
||||
var target = tmpDir.clone();
|
||||
target.append(entryName);
|
||||
target.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0o640); // 0640
|
||||
|
||||
zipreader.extract(entryName, target);
|
||||
|
||||
var entry = zipreader.getEntry(entryName);
|
||||
do_check_true(entry != null);
|
||||
|
||||
zipreader.test(entryName);
|
||||
|
||||
zipreader.close();
|
||||
}
|
||||
12
modules/libjar/test/unit/test_uncompressed.js
Normal file
12
modules/libjar/test/unit/test_uncompressed.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Make sure uncompressed files pass crc
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
function run_test() {
|
||||
var file = do_get_file("data/uncompressed.zip");
|
||||
var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipReader.open(file);
|
||||
zipReader.test("hello");
|
||||
zipReader.close();
|
||||
}
|
||||
44
modules/libjar/test/unit/xpcshell.ini
Normal file
44
modules/libjar/test/unit/xpcshell.ini
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
skip-if = toolkit == 'android'
|
||||
support-files =
|
||||
data/empty
|
||||
data/test_bug333423.zip
|
||||
data/test_bug336691.zip
|
||||
data/test_bug370103.jar
|
||||
data/test_bug379841.zip
|
||||
data/test_bug589292.zip
|
||||
data/test_bug597702.zip
|
||||
data/test_bug637286.zip
|
||||
data/test_bug658093.zip
|
||||
data/test_corrupt.zip
|
||||
data/test_corrupt2.zip
|
||||
data/test_corrupt3.zip
|
||||
data/test_crx_dummy.crx
|
||||
data/test_umlaute.zip
|
||||
data/uncompressed.zip
|
||||
|
||||
[test_jarchannel.js]
|
||||
skip-if = os == "mac"
|
||||
[test_bug278262.js]
|
||||
[test_bug333423.js]
|
||||
[test_bug336691.js]
|
||||
[test_bug370103.js]
|
||||
[test_bug379841.js]
|
||||
[test_bug407303.js]
|
||||
[test_bug453254.js]
|
||||
[test_bug458158.js]
|
||||
[test_bug589292.js]
|
||||
[test_bug597702.js]
|
||||
[test_bug637286.js]
|
||||
[test_bug658093.js]
|
||||
[test_corrupt_536911.js]
|
||||
[test_corrupt_541828.js]
|
||||
[test_corrupt_1211262.js]
|
||||
[test_crx.js]
|
||||
[test_dirjar_bug525755.js]
|
||||
[test_jarinput_stream_zipreader_reference.js]
|
||||
[test_not_found.js]
|
||||
[test_uncompressed.js]
|
||||
[test_umlaute.js]
|
||||
107
modules/libjar/zipstruct.h
Normal file
107
modules/libjar/zipstruct.h
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef _zipstruct_h
|
||||
#define _zipstruct_h
|
||||
|
||||
|
||||
/*
|
||||
* Certain constants and structures for
|
||||
* the Phil Katz ZIP archive format.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct ZipLocal_
|
||||
{
|
||||
unsigned char signature [4];
|
||||
unsigned char word [2];
|
||||
unsigned char bitflag [2];
|
||||
unsigned char method [2];
|
||||
unsigned char time [2];
|
||||
unsigned char date [2];
|
||||
unsigned char crc32 [4];
|
||||
unsigned char size [4];
|
||||
unsigned char orglen [4];
|
||||
unsigned char filename_len [2];
|
||||
unsigned char extrafield_len [2];
|
||||
} ZipLocal;
|
||||
|
||||
/*
|
||||
* 'sizeof(struct XXX)' includes padding on ARM (see bug 87965)
|
||||
* As the internals of a jar/zip file must not depend on the target
|
||||
* architecture (i386, ppc, ARM, ...), use a fixed value instead.
|
||||
*/
|
||||
#define ZIPLOCAL_SIZE (4+2+2+2+2+2+4+4+4+2+2)
|
||||
|
||||
typedef struct ZipCentral_
|
||||
{
|
||||
unsigned char signature [4];
|
||||
unsigned char version_made_by [2];
|
||||
unsigned char version [2];
|
||||
unsigned char bitflag [2];
|
||||
unsigned char method [2];
|
||||
unsigned char time [2];
|
||||
unsigned char date [2];
|
||||
unsigned char crc32 [4];
|
||||
unsigned char size [4];
|
||||
unsigned char orglen [4];
|
||||
unsigned char filename_len [2];
|
||||
unsigned char extrafield_len [2];
|
||||
unsigned char commentfield_len [2];
|
||||
unsigned char diskstart_number [2];
|
||||
unsigned char internal_attributes [2];
|
||||
unsigned char external_attributes [4];
|
||||
unsigned char localhdr_offset [4];
|
||||
} ZipCentral;
|
||||
|
||||
/*
|
||||
* 'sizeof(struct XXX)' includes padding on ARM (see bug 87965)
|
||||
* As the internals of a jar/zip file must not depend on the target
|
||||
* architecture (i386, ppc, ARM, ...), use a fixed value instead.
|
||||
*/
|
||||
#define ZIPCENTRAL_SIZE (4+2+2+2+2+2+2+4+4+4+2+2+2+2+2+4+4)
|
||||
|
||||
typedef struct ZipEnd_
|
||||
{
|
||||
unsigned char signature [4];
|
||||
unsigned char disk_nr [2];
|
||||
unsigned char start_central_dir [2];
|
||||
unsigned char total_entries_disk [2];
|
||||
unsigned char total_entries_archive [2];
|
||||
unsigned char central_dir_size [4];
|
||||
unsigned char offset_central_dir [4];
|
||||
unsigned char commentfield_len [2];
|
||||
} ZipEnd;
|
||||
|
||||
/*
|
||||
* 'sizeof(struct XXX)' includes padding on ARM (see bug 87965)
|
||||
* As the internals of a jar/zip file must not depend on the target
|
||||
* architecture (i386, ppc, ARM, ...), use a fixed value instead.
|
||||
*/
|
||||
#define ZIPEND_SIZE (4+2+2+2+2+4+4+2)
|
||||
|
||||
/* signatures */
|
||||
#define LOCALSIG 0x04034B50l
|
||||
#define CENTRALSIG 0x02014B50l
|
||||
#define ENDSIG 0x06054B50l
|
||||
|
||||
/* extra fields */
|
||||
#define EXTENDED_TIMESTAMP_FIELD 0x5455
|
||||
#define EXTENDED_TIMESTAMP_MODTIME 0x01
|
||||
|
||||
/* compression methods */
|
||||
#define STORED 0
|
||||
#define SHRUNK 1
|
||||
#define REDUCED1 2
|
||||
#define REDUCED2 3
|
||||
#define REDUCED3 4
|
||||
#define REDUCED4 5
|
||||
#define IMPLODED 6
|
||||
#define TOKENIZED 7
|
||||
#define DEFLATED 8
|
||||
#define UNSUPPORTED 0xFF
|
||||
|
||||
|
||||
#endif /* _zipstruct_h */
|
||||
48
modules/libjar/zipwriter/StreamFunctions.cpp
Normal file
48
modules/libjar/zipwriter/StreamFunctions.cpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#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.
|
||||
*/
|
||||
nsresult ZW_ReadData(nsIInputStream *aStream, char *aBuffer, uint32_t aCount)
|
||||
{
|
||||
while (aCount > 0) {
|
||||
uint32_t 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 until all the
|
||||
* data is written or an error is hit.
|
||||
*/
|
||||
nsresult ZW_WriteData(nsIOutputStream *aStream, const char *aBuffer,
|
||||
uint32_t aCount)
|
||||
{
|
||||
while (aCount > 0) {
|
||||
uint32_t 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;
|
||||
}
|
||||
68
modules/libjar/zipwriter/StreamFunctions.h
Normal file
68
modules/libjar/zipwriter/StreamFunctions.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#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, where present, is incremented according to the number of
|
||||
* bytes consumed from the buffer.
|
||||
*/
|
||||
inline void WRITE8(uint8_t* buf, uint32_t* off, uint8_t val)
|
||||
{
|
||||
buf[(*off)++] = val;
|
||||
}
|
||||
|
||||
inline void WRITE16(uint8_t* buf, uint32_t* off, uint16_t val)
|
||||
{
|
||||
WRITE8(buf, off, val & 0xff);
|
||||
WRITE8(buf, off, (val >> 8) & 0xff);
|
||||
}
|
||||
|
||||
inline void WRITE32(uint8_t* buf, uint32_t* off, uint32_t val)
|
||||
{
|
||||
WRITE16(buf, off, val & 0xffff);
|
||||
WRITE16(buf, off, (val >> 16) & 0xffff);
|
||||
}
|
||||
|
||||
inline uint8_t READ8(const uint8_t* buf, uint32_t* off)
|
||||
{
|
||||
return buf[(*off)++];
|
||||
}
|
||||
|
||||
inline uint16_t READ16(const uint8_t* buf, uint32_t* off)
|
||||
{
|
||||
uint16_t val = READ8(buf, off);
|
||||
val |= READ8(buf, off) << 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
inline uint32_t READ32(const uint8_t* buf, uint32_t* off)
|
||||
{
|
||||
uint32_t val = READ16(buf, off);
|
||||
val |= READ16(buf, off) << 16;
|
||||
return val;
|
||||
}
|
||||
|
||||
inline uint32_t PEEK32(const uint8_t* buf)
|
||||
{
|
||||
return (uint32_t)( (buf [0] ) |
|
||||
(buf [1] << 8) |
|
||||
(buf [2] << 16) |
|
||||
(buf [3] << 24) );
|
||||
}
|
||||
|
||||
nsresult ZW_ReadData(nsIInputStream *aStream, char *aBuffer, uint32_t aCount);
|
||||
|
||||
nsresult ZW_WriteData(nsIOutputStream *aStream, const char *aBuffer,
|
||||
uint32_t aCount);
|
||||
|
||||
#endif
|
||||
37
modules/libjar/zipwriter/ZipWriterModule.cpp
Normal file
37
modules/libjar/zipwriter/ZipWriterModule.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsDeflateConverter.h"
|
||||
#include "nsZipWriter.h"
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeflateConverter)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsZipWriter)
|
||||
|
||||
NS_DEFINE_NAMED_CID(DEFLATECONVERTER_CID);
|
||||
NS_DEFINE_NAMED_CID(ZIPWRITER_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kZipWriterCIDs[] = {
|
||||
{ &kDEFLATECONVERTER_CID, false, nullptr, nsDeflateConverterConstructor },
|
||||
{ &kZIPWRITER_CID, false, nullptr, nsZipWriterConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kZipWriterContracts[] = {
|
||||
{ "@mozilla.org/streamconv;1?from=uncompressed&to=deflate", &kDEFLATECONVERTER_CID },
|
||||
{ "@mozilla.org/streamconv;1?from=uncompressed&to=gzip", &kDEFLATECONVERTER_CID },
|
||||
{ "@mozilla.org/streamconv;1?from=uncompressed&to=x-gzip", &kDEFLATECONVERTER_CID },
|
||||
{ "@mozilla.org/streamconv;1?from=uncompressed&to=rawdeflate", &kDEFLATECONVERTER_CID },
|
||||
{ ZIPWRITER_CONTRACTID, &kZIPWRITER_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module kZipWriterModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kZipWriterCIDs,
|
||||
kZipWriterContracts
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(ZipWriterModule) = &kZipWriterModule;
|
||||
24
modules/libjar/zipwriter/moz.build
Normal file
24
modules/libjar/zipwriter/moz.build
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIZipWriter.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'zipwriter'
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'nsDeflateConverter.cpp',
|
||||
'nsZipDataStream.cpp',
|
||||
'nsZipHeader.cpp',
|
||||
'nsZipWriter.cpp',
|
||||
'StreamFunctions.cpp',
|
||||
'ZipWriterModule.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
188
modules/libjar/zipwriter/nsDeflateConverter.cpp
Normal file
188
modules/libjar/zipwriter/nsDeflateConverter.cpp
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "StreamFunctions.h"
|
||||
#include "nsDeflateConverter.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsIInputStreamPump.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsMemory.h"
|
||||
#include "plstr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#define ZLIB_TYPE "deflate"
|
||||
#define GZIP_TYPE "gzip"
|
||||
#define X_GZIP_TYPE "x-gzip"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/**
|
||||
* nsDeflateConverter is a stream converter applies the deflate compression
|
||||
* method to the data.
|
||||
*/
|
||||
NS_IMPL_ISUPPORTS(nsDeflateConverter, nsIStreamConverter,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver)
|
||||
|
||||
nsresult nsDeflateConverter::Init()
|
||||
{
|
||||
int zerr;
|
||||
|
||||
mOffset = 0;
|
||||
|
||||
mZstream.zalloc = Z_NULL;
|
||||
mZstream.zfree = Z_NULL;
|
||||
mZstream.opaque = Z_NULL;
|
||||
|
||||
int32_t window = MAX_WBITS;
|
||||
switch (mWrapMode) {
|
||||
case WRAP_NONE:
|
||||
window = -window;
|
||||
break;
|
||||
case WRAP_GZIP:
|
||||
window += 16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
zerr = deflateInit2(&mZstream, mLevel, Z_DEFLATED, window, 8,
|
||||
Z_DEFAULT_STRATEGY);
|
||||
if (zerr != Z_OK) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mZstream.next_out = mWriteBuffer;
|
||||
mZstream.avail_out = sizeof(mWriteBuffer);
|
||||
|
||||
// mark the input buffer as empty.
|
||||
mZstream.avail_in = 0;
|
||||
mZstream.next_in = Z_NULL;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDeflateConverter::Convert(nsIInputStream *aFromStream,
|
||||
const char *aFromType,
|
||||
const char *aToType,
|
||||
nsISupports *aCtxt,
|
||||
nsIInputStream **_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!PL_strncasecmp(aToType, ZLIB_TYPE, sizeof(ZLIB_TYPE)-1))
|
||||
mWrapMode = WRAP_ZLIB;
|
||||
else if (!PL_strcasecmp(aToType, GZIP_TYPE) ||
|
||||
!PL_strcasecmp(aToType, X_GZIP_TYPE))
|
||||
mWrapMode = WRAP_GZIP;
|
||||
else
|
||||
mWrapMode = WRAP_NONE;
|
||||
|
||||
nsresult rv = Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mListener = aListener;
|
||||
mContext = aCtxt;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDeflateConverter::OnDataAvailable(nsIRequest *aRequest,
|
||||
nsISupports *aContext,
|
||||
nsIInputStream *aInputStream,
|
||||
uint64_t aOffset,
|
||||
uint32_t aCount)
|
||||
{
|
||||
if (!mListener)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
auto buffer = MakeUnique<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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDeflateConverter::OnStartRequest(nsIRequest *aRequest,
|
||||
nsISupports *aContext)
|
||||
{
|
||||
if (!mListener)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
return mListener->OnStartRequest(aRequest, mContext);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
uint32_t bytesToWrite = sizeof(mWriteBuffer) - mZstream.avail_out;
|
||||
// We don't need to do anything if there isn't any data
|
||||
if (bytesToWrite == 0)
|
||||
return NS_OK;
|
||||
|
||||
MOZ_ASSERT(bytesToWrite <= INT32_MAX);
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
|
||||
(char*)mWriteBuffer, bytesToWrite);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
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;
|
||||
}
|
||||
63
modules/libjar/zipwriter/nsDeflateConverter.h
Normal file
63
modules/libjar/zipwriter/nsDeflateConverter.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef _nsDeflateConverter_h_
|
||||
#define _nsDeflateConverter_h_
|
||||
|
||||
#include "nsIStreamConverter.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIPipe.h"
|
||||
#include "zlib.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#define DEFLATECONVERTER_CID { 0x461cd5dd, 0x73c6, 0x47a4, \
|
||||
{ 0x8c, 0xc3, 0x60, 0x3b, 0x37, 0xd8, 0x4a, 0x61 } }
|
||||
|
||||
#define ZIP_BUFLEN (4 * 1024 - 1)
|
||||
|
||||
class nsDeflateConverter final : public nsIStreamConverter
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSISTREAMCONVERTER
|
||||
|
||||
nsDeflateConverter()
|
||||
{
|
||||
// 6 is Z_DEFAULT_COMPRESSION but we need the actual value
|
||||
mLevel = 6;
|
||||
}
|
||||
|
||||
explicit nsDeflateConverter(int32_t level)
|
||||
{
|
||||
mLevel = level;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
~nsDeflateConverter()
|
||||
{
|
||||
}
|
||||
|
||||
enum WrapMode {
|
||||
WRAP_ZLIB,
|
||||
WRAP_GZIP,
|
||||
WRAP_NONE
|
||||
};
|
||||
|
||||
WrapMode mWrapMode;
|
||||
uint64_t mOffset;
|
||||
int32_t mLevel;
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsISupports> mContext;
|
||||
z_stream mZstream;
|
||||
unsigned char mWriteBuffer[ZIP_BUFLEN];
|
||||
|
||||
nsresult Init();
|
||||
nsresult PushAvailableData(nsIRequest *aRequest, nsISupports *aContext);
|
||||
};
|
||||
|
||||
#endif
|
||||
220
modules/libjar/zipwriter/nsIZipWriter.idl
Normal file
220
modules/libjar/zipwriter/nsIZipWriter.idl
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#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(3ca10750-797e-4a22-bcfe-66170b5e96dd)]
|
||||
interface nsIZipWriter : nsISupports
|
||||
{
|
||||
/**
|
||||
* Some predefined compression levels
|
||||
*/
|
||||
const uint32_t COMPRESSION_NONE = 0;
|
||||
const uint32_t COMPRESSION_FASTEST = 1;
|
||||
const uint32_t COMPRESSION_DEFAULT = 6;
|
||||
const uint32_t 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 <other-error> on failure to open zip file (most likely corrupt
|
||||
* or unsupported form)
|
||||
*/
|
||||
void open(in nsIFile aFile, in int32_t 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 int32_t 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 int32_t 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 int32_t 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 <other-error> 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 <other-error> on failure to complete the zip file
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Make all stored(uncompressed) files align to given alignment size.
|
||||
*
|
||||
* @param aAlignSize is the alignment size, valid values from 2 to 32768, and
|
||||
must be power of 2.
|
||||
*
|
||||
* @throws NS_ERROR_INVALID_ARG if aAlignSize is invalid
|
||||
* @throws <other-error> on failure to update the zip file
|
||||
*/
|
||||
void alignStoredFiles(in uint16_t aAlignSize);
|
||||
};
|
||||
181
modules/libjar/zipwriter/nsZipDataStream.cpp
Normal file
181
modules/libjar/zipwriter/nsZipDataStream.cpp
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "StreamFunctions.h"
|
||||
#include "nsZipDataStream.h"
|
||||
#include "nsStringStream.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
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/**
|
||||
* 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_ISUPPORTS(nsZipDataStream, nsIStreamListener,
|
||||
nsIRequestObserver)
|
||||
|
||||
nsresult nsZipDataStream::Init(nsZipWriter *aWriter,
|
||||
nsIOutputStream *aStream,
|
||||
nsZipHeader *aHeader,
|
||||
int32_t aCompression)
|
||||
{
|
||||
mWriter = aWriter;
|
||||
mHeader = aHeader;
|
||||
mStream = aStream;
|
||||
mHeader->mCRC = crc32(0L, Z_NULL, 0);
|
||||
|
||||
nsresult rv = NS_NewSimpleStreamListener(getter_AddRefs(mOutput), aStream,
|
||||
nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aCompression > 0) {
|
||||
mHeader->mMethod = ZIP_METHOD_DEFLATE;
|
||||
nsCOMPtr<nsIStreamConverter> converter =
|
||||
new nsDeflateConverter(aCompression);
|
||||
NS_ENSURE_TRUE(converter, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = converter->AsyncConvertData("uncompressed", "rawdeflate", mOutput,
|
||||
nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mOutput = do_QueryInterface(converter, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
mHeader->mMethod = ZIP_METHOD_STORE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsZipDataStream::OnDataAvailable(nsIRequest *aRequest,
|
||||
nsISupports *aContext,
|
||||
nsIInputStream *aInputStream,
|
||||
uint64_t aOffset,
|
||||
uint32_t aCount)
|
||||
{
|
||||
if (!mOutput)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
auto buffer = MakeUnique<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);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsZipDataStream::OnStartRequest(nsIRequest *aRequest,
|
||||
nsISupports *aContext)
|
||||
{
|
||||
if (!mOutput)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
return mOutput->OnStartRequest(aRequest, aContext);
|
||||
}
|
||||
|
||||
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 = nullptr;
|
||||
if (NS_FAILED(rv)) {
|
||||
mWriter->EntryCompleteCallback(mHeader, rv);
|
||||
}
|
||||
else {
|
||||
rv = CompleteEntry();
|
||||
rv = mWriter->EntryCompleteCallback(mHeader, rv);
|
||||
}
|
||||
|
||||
mStream = nullptr;
|
||||
mWriter = nullptr;
|
||||
mHeader = nullptr;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
inline nsresult nsZipDataStream::CompleteEntry()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
int64_t pos;
|
||||
rv = seekable->Tell(&pos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mHeader->mCSize = pos - mHeader->mOffset - mHeader->GetFileHeaderLength();
|
||||
mHeader->mWriteOnClose = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsZipDataStream::ProcessData(nsIRequest *aRequest,
|
||||
nsISupports *aContext, char *aBuffer,
|
||||
uint64_t aOffset, uint32_t aCount)
|
||||
{
|
||||
mHeader->mCRC = crc32(mHeader->mCRC,
|
||||
reinterpret_cast<const unsigned char*>(aBuffer),
|
||||
aCount);
|
||||
|
||||
MOZ_ASSERT(aCount <= INT32_MAX);
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
|
||||
aBuffer, aCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
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(nullptr, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
auto buffer = MakeUnique<char[]>(4096);
|
||||
NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
uint32_t read = 0;
|
||||
uint32_t offset = 0;
|
||||
do
|
||||
{
|
||||
rv = aStream->Read(buffer.get(), 4096, &read);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnStopRequest(nullptr, nullptr, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (read > 0) {
|
||||
rv = ProcessData(nullptr, nullptr, buffer.get(), offset, read);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnStopRequest(nullptr, nullptr, rv);
|
||||
return rv;
|
||||
}
|
||||
offset += read;
|
||||
}
|
||||
} while (read > 0);
|
||||
|
||||
return OnStopRequest(nullptr, nullptr, NS_OK);
|
||||
}
|
||||
45
modules/libjar/zipwriter/nsZipDataStream.h
Normal file
45
modules/libjar/zipwriter/nsZipDataStream.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef _nsZipDataStream_h_
|
||||
#define _nsZipDataStream_h_
|
||||
|
||||
#include "nsZipWriter.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsZipDataStream final : public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
nsZipDataStream()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult Init(nsZipWriter *aWriter, nsIOutputStream *aStream,
|
||||
nsZipHeader *aHeader, int32_t aCompression);
|
||||
|
||||
nsresult ReadStream(nsIInputStream *aStream);
|
||||
|
||||
private:
|
||||
|
||||
~nsZipDataStream() {}
|
||||
|
||||
nsCOMPtr<nsIStreamListener> mOutput;
|
||||
nsCOMPtr<nsIOutputStream> mStream;
|
||||
RefPtr<nsZipWriter> mWriter;
|
||||
RefPtr<nsZipHeader> mHeader;
|
||||
|
||||
nsresult CompleteEntry();
|
||||
nsresult ProcessData(nsIRequest *aRequest, nsISupports *aContext,
|
||||
char *aBuffer, uint64_t aOffset, uint32_t aCount);
|
||||
};
|
||||
|
||||
#endif
|
||||
389
modules/libjar/zipwriter/nsZipHeader.cpp
Normal file
389
modules/libjar/zipwriter/nsZipHeader.cpp
Normal file
|
|
@ -0,0 +1,389 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "StreamFunctions.h"
|
||||
#include "nsZipHeader.h"
|
||||
#include "nsMemory.h"
|
||||
#include "prtime.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
|
||||
|
||||
#define ZIP_EXTENDED_TIMESTAMP_FIELD 0x5455
|
||||
#define ZIP_EXTENDED_TIMESTAMP_MODTIME 0x01
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/**
|
||||
* nsZipHeader represents an entry from a zip file.
|
||||
*/
|
||||
NS_IMPL_ISUPPORTS(nsZipHeader, nsIZipEntry)
|
||||
|
||||
NS_IMETHODIMP nsZipHeader::GetCompression(uint16_t *aCompression)
|
||||
{
|
||||
NS_ASSERTION(mInited, "Not initalised");
|
||||
|
||||
*aCompression = mMethod;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsZipHeader::GetSize(uint32_t *aSize)
|
||||
{
|
||||
NS_ASSERTION(mInited, "Not initalised");
|
||||
|
||||
*aSize = mCSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsZipHeader::GetRealSize(uint32_t *aRealSize)
|
||||
{
|
||||
NS_ASSERTION(mInited, "Not initalised");
|
||||
|
||||
*aRealSize = mUSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsZipHeader::GetCRC32(uint32_t *aCRC32)
|
||||
{
|
||||
NS_ASSERTION(mInited, "Not initalised");
|
||||
|
||||
*aCRC32 = mCRC;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsZipHeader::GetIsDirectory(bool *aIsDirectory)
|
||||
{
|
||||
NS_ASSERTION(mInited, "Not initalised");
|
||||
|
||||
if (mName.Last() == '/')
|
||||
*aIsDirectory = true;
|
||||
else
|
||||
*aIsDirectory = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsZipHeader::GetLastModifiedTime(PRTime *aLastModifiedTime)
|
||||
{
|
||||
NS_ASSERTION(mInited, "Not initalised");
|
||||
|
||||
// Try to read timestamp from extra field
|
||||
uint16_t blocksize;
|
||||
const uint8_t *tsField = GetExtraField(ZIP_EXTENDED_TIMESTAMP_FIELD, false, &blocksize);
|
||||
if (tsField && blocksize >= 5) {
|
||||
uint32_t pos = 4;
|
||||
uint8_t flags;
|
||||
flags = READ8(tsField, &pos);
|
||||
if (flags & ZIP_EXTENDED_TIMESTAMP_MODTIME) {
|
||||
*aLastModifiedTime = (PRTime)(READ32(tsField, &pos))
|
||||
* PR_USEC_PER_SEC;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Use DOS date/time fields
|
||||
// Note that on DST shift we can't handle correctly the hour that is valid
|
||||
// in both DST zones
|
||||
PRExplodedTime time;
|
||||
|
||||
time.tm_usec = 0;
|
||||
|
||||
time.tm_hour = (mTime >> 11) & 0x1F;
|
||||
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.tp_gmt_offset = PR_LocalTimeParameters(&time).tp_gmt_offset;
|
||||
PR_NormalizeTime(&time, PR_GMTParameters);
|
||||
time.tm_params.tp_dst_offset = PR_LocalTimeParameters(&time).tp_dst_offset;
|
||||
|
||||
*aLastModifiedTime = PR_ImplodeTime(&time);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsZipHeader::GetIsSynthetic(bool *aIsSynthetic)
|
||||
{
|
||||
NS_ASSERTION(mInited, "Not initalised");
|
||||
|
||||
*aIsSynthetic = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsZipHeader::GetPermissions(uint32_t *aPermissions)
|
||||
{
|
||||
NS_ASSERTION(mInited, "Not initalised");
|
||||
|
||||
// Always give user read access at least, this matches nsIZipReader's behaviour
|
||||
*aPermissions = ((mEAttr >> 16) & 0xfff) | 0x100;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsZipHeader::Init(const nsACString & aPath, PRTime aDate, uint32_t aAttr,
|
||||
uint32_t 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);
|
||||
|
||||
// Store modification timestamp as extra field
|
||||
// First fill CDS extra field
|
||||
mFieldLength = 9;
|
||||
mExtraField = MakeUnique<uint8_t[]>(mFieldLength);
|
||||
if (!mExtraField) {
|
||||
mFieldLength = 0;
|
||||
} else {
|
||||
uint32_t pos = 0;
|
||||
WRITE16(mExtraField.get(), &pos, ZIP_EXTENDED_TIMESTAMP_FIELD);
|
||||
WRITE16(mExtraField.get(), &pos, 5);
|
||||
WRITE8(mExtraField.get(), &pos, ZIP_EXTENDED_TIMESTAMP_MODTIME);
|
||||
WRITE32(mExtraField.get(), &pos, aDate / PR_USEC_PER_SEC);
|
||||
|
||||
// Fill local extra field
|
||||
mLocalExtraField = MakeUnique<uint8_t[]>(mFieldLength);
|
||||
if (mLocalExtraField) {
|
||||
mLocalFieldLength = mFieldLength;
|
||||
memcpy(mLocalExtraField.get(), mExtraField.get(), mLocalFieldLength);
|
||||
}
|
||||
}
|
||||
|
||||
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 = true;
|
||||
}
|
||||
|
||||
uint32_t nsZipHeader::GetFileHeaderLength()
|
||||
{
|
||||
return ZIP_FILE_HEADER_SIZE + mName.Length() + mLocalFieldLength;
|
||||
}
|
||||
|
||||
nsresult nsZipHeader::WriteFileHeader(nsIOutputStream *aStream)
|
||||
{
|
||||
NS_ASSERTION(mInited, "Not initalised");
|
||||
|
||||
uint8_t buf[ZIP_FILE_HEADER_SIZE];
|
||||
uint32_t 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, mLocalFieldLength);
|
||||
|
||||
nsresult rv = ZW_WriteData(aStream, (const char *)buf, pos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = ZW_WriteData(aStream, mName.get(), mName.Length());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mLocalFieldLength)
|
||||
{
|
||||
rv = ZW_WriteData(aStream, (const char *)mLocalExtraField.get(), mLocalFieldLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t nsZipHeader::GetCDSHeaderLength()
|
||||
{
|
||||
return ZIP_CDS_HEADER_SIZE + mName.Length() + mComment.Length() +
|
||||
mFieldLength;
|
||||
}
|
||||
|
||||
nsresult nsZipHeader::WriteCDSHeader(nsIOutputStream *aStream)
|
||||
{
|
||||
NS_ASSERTION(mInited, "Not initalised");
|
||||
|
||||
uint8_t buf[ZIP_CDS_HEADER_SIZE];
|
||||
uint32_t 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, (const char *)buf, pos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = ZW_WriteData(aStream, mName.get(), mName.Length());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (mExtraField) {
|
||||
rv = ZW_WriteData(aStream, (const char *)mExtraField.get(), mFieldLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return ZW_WriteData(aStream, mComment.get(), mComment.Length());
|
||||
}
|
||||
|
||||
nsresult nsZipHeader::ReadCDSHeader(nsIInputStream *stream)
|
||||
{
|
||||
NS_ASSERTION(!mInited, "Already initalised");
|
||||
|
||||
uint8_t buf[ZIP_CDS_HEADER_SIZE];
|
||||
|
||||
nsresult rv = ZW_ReadData(stream, (char *)buf, ZIP_CDS_HEADER_SIZE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t pos = 0;
|
||||
uint32_t 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);
|
||||
uint16_t namelength = READ16(buf, &pos);
|
||||
mFieldLength = READ16(buf, &pos);
|
||||
uint16_t commentlength = READ16(buf, &pos);
|
||||
mDisk = READ16(buf, &pos);
|
||||
mIAttr = READ16(buf, &pos);
|
||||
mEAttr = READ32(buf, &pos);
|
||||
mOffset = READ32(buf, &pos);
|
||||
|
||||
if (namelength > 0) {
|
||||
auto field = MakeUnique<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.get(), namelength);
|
||||
}
|
||||
else
|
||||
mName = NS_LITERAL_CSTRING("");
|
||||
|
||||
if (mFieldLength > 0) {
|
||||
mExtraField = MakeUnique<uint8_t[]>(mFieldLength);
|
||||
NS_ENSURE_TRUE(mExtraField, NS_ERROR_OUT_OF_MEMORY);
|
||||
rv = ZW_ReadData(stream, (char *)mExtraField.get(), mFieldLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (commentlength > 0) {
|
||||
auto field = MakeUnique<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.get(), commentlength);
|
||||
}
|
||||
else
|
||||
mComment = NS_LITERAL_CSTRING("");
|
||||
|
||||
mInited = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const uint8_t * nsZipHeader::GetExtraField(uint16_t aTag, bool aLocal, uint16_t *aBlockSize)
|
||||
{
|
||||
const uint8_t *buf = aLocal ? mLocalExtraField.get() : mExtraField.get();
|
||||
uint32_t buflen = aLocal ? mLocalFieldLength : mFieldLength;
|
||||
uint32_t pos = 0;
|
||||
uint16_t tag, blocksize;
|
||||
|
||||
while (buf && (pos + 4) <= buflen) {
|
||||
tag = READ16(buf, &pos);
|
||||
blocksize = READ16(buf, &pos);
|
||||
|
||||
if (aTag == tag && (pos + blocksize) <= buflen) {
|
||||
*aBlockSize = blocksize;
|
||||
return buf + pos - 4;
|
||||
}
|
||||
|
||||
pos += blocksize;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pad extra field to align data starting position to specified size.
|
||||
*/
|
||||
nsresult nsZipHeader::PadExtraField(uint32_t aOffset, uint16_t aAlignSize)
|
||||
{
|
||||
uint32_t pad_size;
|
||||
uint32_t pa_offset;
|
||||
uint32_t pa_end;
|
||||
|
||||
// Check for range and power of 2.
|
||||
if (aAlignSize < 2 || aAlignSize > 32768 ||
|
||||
(aAlignSize & (aAlignSize - 1)) != 0) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Point to current starting data position.
|
||||
aOffset += ZIP_FILE_HEADER_SIZE + mName.Length() + mLocalFieldLength;
|
||||
|
||||
// Calculate aligned offset.
|
||||
pa_offset = aOffset & ~(aAlignSize - 1);
|
||||
pa_end = pa_offset + aAlignSize;
|
||||
pad_size = pa_end - aOffset;
|
||||
if (pad_size == 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Leave enough room(at least 4 bytes) for valid values in extra field.
|
||||
while (pad_size < 4) {
|
||||
pad_size += aAlignSize;
|
||||
}
|
||||
// Extra field length is 2 bytes.
|
||||
if (mLocalFieldLength + pad_size > 65535) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
UniquePtr<uint8_t[]> field = Move(mLocalExtraField);
|
||||
uint32_t pos = mLocalFieldLength;
|
||||
|
||||
mLocalExtraField = MakeUnique<uint8_t[]>(mLocalFieldLength + pad_size);
|
||||
memcpy(mLocalExtraField.get(), field.get(), mLocalFieldLength);
|
||||
// Use 0xFFFF as tag ID to avoid conflict with other IDs.
|
||||
// For more information, please read "Extensible data fields" section in:
|
||||
// http://www.pkware.com/documents/casestudies/APPNOTE.TXT
|
||||
WRITE16(mLocalExtraField.get(), &pos, 0xFFFF);
|
||||
WRITE16(mLocalExtraField.get(), &pos, pad_size - 4);
|
||||
memset(mLocalExtraField.get() + pos, 0, pad_size - 4);
|
||||
mLocalFieldLength += pad_size;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
94
modules/libjar/zipwriter/nsZipHeader.h
Normal file
94
modules/libjar/zipwriter/nsZipHeader.h
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef _nsZipHeader_h_
|
||||
#define _nsZipHeader_h_
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIZipReader.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
// High word is S_IFREG, low word is DOS file attribute
|
||||
#define ZIP_ATTRS_FILE 0x80000000
|
||||
// High word is S_IFDIR, low word is DOS dir attribute
|
||||
#define ZIP_ATTRS_DIRECTORY 0x40000010
|
||||
#define PERMISSIONS_FILE 0644
|
||||
#define PERMISSIONS_DIR 0755
|
||||
|
||||
// Combine file type attributes with unix style permissions
|
||||
#define ZIP_ATTRS(p, a) ((p & 0xfff) << 16) | a
|
||||
|
||||
class nsZipHeader final : public nsIZipEntry
|
||||
{
|
||||
~nsZipHeader()
|
||||
{
|
||||
mExtraField = nullptr;
|
||||
mLocalExtraField = nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIZIPENTRY
|
||||
|
||||
nsZipHeader() :
|
||||
mCRC(0),
|
||||
mCSize(0),
|
||||
mUSize(0),
|
||||
mEAttr(0),
|
||||
mOffset(0),
|
||||
mFieldLength(0),
|
||||
mLocalFieldLength(0),
|
||||
mVersionMade(0x0300 + 23), // Generated on Unix by v2.3 (matches infozip)
|
||||
mVersionNeeded(20), // Requires v2.0 to extract
|
||||
mFlags(0),
|
||||
mMethod(0),
|
||||
mTime(0),
|
||||
mDate(0),
|
||||
mDisk(0),
|
||||
mIAttr(0),
|
||||
mInited(false),
|
||||
mWriteOnClose(false),
|
||||
mExtraField(nullptr),
|
||||
mLocalExtraField(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t mCRC;
|
||||
uint32_t mCSize;
|
||||
uint32_t mUSize;
|
||||
uint32_t mEAttr;
|
||||
uint32_t mOffset;
|
||||
uint32_t mFieldLength;
|
||||
uint32_t mLocalFieldLength;
|
||||
uint16_t mVersionMade;
|
||||
uint16_t mVersionNeeded;
|
||||
uint16_t mFlags;
|
||||
uint16_t mMethod;
|
||||
uint16_t mTime;
|
||||
uint16_t mDate;
|
||||
uint16_t mDisk;
|
||||
uint16_t mIAttr;
|
||||
bool mInited;
|
||||
bool mWriteOnClose;
|
||||
nsCString mName;
|
||||
nsCString mComment;
|
||||
mozilla::UniquePtr<uint8_t[]> mExtraField;
|
||||
mozilla::UniquePtr<uint8_t[]> mLocalExtraField;
|
||||
|
||||
void Init(const nsACString & aPath, PRTime aDate, uint32_t aAttr,
|
||||
uint32_t aOffset);
|
||||
uint32_t GetFileHeaderLength();
|
||||
nsresult WriteFileHeader(nsIOutputStream *aStream);
|
||||
uint32_t GetCDSHeaderLength();
|
||||
nsresult WriteCDSHeader(nsIOutputStream *aStream);
|
||||
nsresult ReadCDSHeader(nsIInputStream *aStream);
|
||||
const uint8_t * GetExtraField(uint16_t aTag, bool aLocal, uint16_t *aBlockSize);
|
||||
nsresult PadExtraField(uint32_t aOffset, uint16_t aAlignSize);
|
||||
};
|
||||
|
||||
#endif
|
||||
1133
modules/libjar/zipwriter/nsZipWriter.cpp
Normal file
1133
modules/libjar/zipwriter/nsZipWriter.cpp
Normal file
File diff suppressed because it is too large
Load diff
80
modules/libjar/zipwriter/nsZipWriter.h
Normal file
80
modules/libjar/zipwriter/nsZipWriter.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#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"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#define ZIPWRITER_CONTRACTID "@mozilla.org/zipwriter;1"
|
||||
#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:
|
||||
uint32_t mOperation;
|
||||
nsCString mZipEntry;
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
PRTime mModTime;
|
||||
int32_t mCompression;
|
||||
uint32_t mPermissions;
|
||||
};
|
||||
|
||||
class nsZipWriter final : public nsIZipWriter,
|
||||
public nsIRequestObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIZIPWRITER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
nsZipWriter();
|
||||
nsresult EntryCompleteCallback(nsZipHeader *aHeader, nsresult aStatus);
|
||||
|
||||
private:
|
||||
~nsZipWriter();
|
||||
|
||||
uint32_t mCDSOffset;
|
||||
bool mCDSDirty;
|
||||
bool mInQueue;
|
||||
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsCOMPtr<nsIRequestObserver> mProcessObserver;
|
||||
nsCOMPtr<nsISupports> mProcessContext;
|
||||
nsCOMPtr<nsIOutputStream> mStream;
|
||||
nsCOMArray<nsZipHeader> mHeaders;
|
||||
nsTArray<nsZipQueueItem> mQueue;
|
||||
nsDataHashtable<nsCStringHashKey, int32_t> mEntryHash;
|
||||
nsCString mComment;
|
||||
|
||||
nsresult SeekCDS();
|
||||
void Cleanup();
|
||||
nsresult ReadFile(nsIFile *aFile);
|
||||
nsresult InternalAddEntryDirectory(const nsACString & aZipEntry,
|
||||
PRTime aModTime, uint32_t aPermissions);
|
||||
nsresult BeginProcessingAddition(nsZipQueueItem* aItem, bool* complete);
|
||||
nsresult BeginProcessingRemoval(int32_t aPos);
|
||||
nsresult AddEntryStream(const nsACString & aZipEntry, PRTime aModTime,
|
||||
int32_t aCompression, nsIInputStream *aStream,
|
||||
bool aQueue, uint32_t aPermissions);
|
||||
void BeginProcessingNextItem();
|
||||
void FinishQueue(nsresult aStatus);
|
||||
};
|
||||
|
||||
#endif
|
||||
0
modules/libjar/zipwriter/test/unit/data/emptyfile.txt
Normal file
0
modules/libjar/zipwriter/test/unit/data/emptyfile.txt
Normal file
1
modules/libjar/zipwriter/test/unit/data/smallfile.txt
Normal file
1
modules/libjar/zipwriter/test/unit/data/smallfile.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
Small (16 bytes)
|
||||
BIN
modules/libjar/zipwriter/test/unit/data/test.png
Normal file
BIN
modules/libjar/zipwriter/test/unit/data/test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
5
modules/libjar/zipwriter/test/unit/data/test.txt
Normal file
5
modules/libjar/zipwriter/test/unit/data/test.txt
Normal file
|
|
@ -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.
|
||||
BIN
modules/libjar/zipwriter/test/unit/data/test.zip
Normal file
BIN
modules/libjar/zipwriter/test/unit/data/test.zip
Normal file
Binary file not shown.
160
modules/libjar/zipwriter/test/unit/data/test_bug399727.html
Normal file
160
modules/libjar/zipwriter/test/unit/data/test_bug399727.html
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv="Content-Language" content="en-gb"><meta http-equiv="Content-Type" content="text/html; charset=windows-1252"><meta name="generator" content="Fog Creek CityDesk 2.0.19"><meta name="citydesk" content="BB40F561/251"><title>TK's Sleater-Kinney pages</title><style type="text/css">
|
||||
<!--
|
||||
body {
|
||||
font-family: verdana, arial;
|
||||
font-size: 10pt;
|
||||
color: black;
|
||||
background-color: #D0E8E8;
|
||||
}
|
||||
td {
|
||||
font-family: verdana, arial;
|
||||
font-size: 10pt;
|
||||
}
|
||||
hr {
|
||||
color: #808080;
|
||||
height: 1px;
|
||||
}
|
||||
caption {
|
||||
font-family: verdana, arial;
|
||||
font-size: 8pt;
|
||||
color: #808080;
|
||||
background-color: white;
|
||||
}
|
||||
.bigText {
|
||||
font-family: verdana, arial;
|
||||
font-size: 18pt;
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.smallText {
|
||||
font-family: verdana, arial;
|
||||
font-size: 7pt;
|
||||
color: #808080;
|
||||
}
|
||||
.tabText {
|
||||
font-family: Courier, "Courier New", monospace;
|
||||
font-size: 7pt;
|
||||
color: #808080;
|
||||
}
|
||||
.emphasis
|
||||
{
|
||||
font-weight: bold;
|
||||
color: #000000;
|
||||
}
|
||||
.articleHeader {
|
||||
padding-bottom: 4px;
|
||||
border-bottom: #808080 dotted 1px;
|
||||
}
|
||||
.headerCell {
|
||||
background-color: #689090;
|
||||
color: white;
|
||||
padding: 4px;
|
||||
}
|
||||
.navbarText {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
.articleTable {
|
||||
border: #808080 solid 1px;
|
||||
background-color: white;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
-->
|
||||
</style></head><body>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div align="center">
|
||||
<center>
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="700">
|
||||
<tbody><tr>
|
||||
<td><p class="bigText">TK's Sleater-Kinney pages</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<table class="articleTable" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tbody><tr>
|
||||
<td class="headerCell" align="right"><p class="navbarText">
|
||||
: <a class="navbarText" href="http://tk-jk.net/S-K/index.html"> <span class="1home">Home</span></a>
|
||||
: <a class="navbarText" href="http://tk-jk.net/S-K/blog/general/Archive.html"> <span class="2archive">Archive</span></a>
|
||||
: <a class="navbarText" href="http://tk-jk.net/S-K/blog/general/Tabs.html"> <span class="3tabs">Tabs</span></a>
|
||||
: <a class="navbarText" href="http://tk-jk.net/S-K/blog/general/Drumtabs.html"> <span class="4drumtabs">Drum tabs</span></a>
|
||||
: <a class="navbarText" href="http://tk-jk.net/S-K/blog/general/SetLists.html"> <span class="5setlists">Set Lists</span></a>
|
||||
: <a class="navbarText" href="http://tk-jk.net/S-K/blog/general/About.html"> <span class="6about">About</span></a> :
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<div align="left">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tbody><tr>
|
||||
<td width="100%">
|
||||
<p class="bigText"><strong>All Hands on the Bad One</strong>
|
||||
</p>
|
||||
<p></p><p><strong>All Hands on the Bad One, <em>"All Hands on the Bad One"</em></strong></p>
|
||||
<p dir="ltr">This, followed by <a href="http://tk-jk.net/S-K/Tabs/YouthDecay.html">Youth Decay</a> - wow - most bands would be happy just to have just one of these songs. S-K has a boatload.</p>
|
||||
<p dir="ltr">Tabbing this was very frustrating. Riff 3 is a
|
||||
masterpiece of guitar and vocal harmony, rhythm and guitar
|
||||
interplay. It has a bass intro and stacks guitars and vocals on
|
||||
top. This is the definition of Sleater-Kinney magic. You can't get
|
||||
it all done on two guitars. You can get close. I
|
||||
haven't done it justice.</p>
|
||||
<p dir="ltr">As usual the guitar 2's rhythms are vital to the S-K sound. It's still good if you don't get it just right.</p>
|
||||
<p dir="ltr">I sure hope I've done this well enough for you to figure out.</p>
|
||||
<ul dir="ltr">
|
||||
<li>
|
||||
<div style="margin-right: 0px;">Quarter note = 153 or so.</div>
|
||||
</li><li>
|
||||
<div style="margin-right: 0px;">Standard tuning. But tuning down 3 half steps makes Riff 3 easier and more authentic.</div>
|
||||
</li><li>
|
||||
<div style="margin-right: 0px;">Tabbed where it felt good on the fretboard but there are alternatives.</div>
|
||||
</li><li>
|
||||
<div style="margin-right: 0px;">Tuning down is required for authenticity but it sounds great in standard tuning</div></li></ul><strong>
|
||||
</strong><p dir="ltr"><strong><br>1:</strong></p>
|
||||
<p></p><span><img alt="All Hands on the Bad One Riff 1" src="AllHandsontheBadOne_files/AHOTBO1.jpg" cd:pos="2" align="left" border="0" height="500" hspace="4" width="580"><br clear="all"></span>
|
||||
<p><strong></strong> </p>
|
||||
<p><strong>2:</strong></p><span><img alt="All Hands on the Bad One Riff 2" src="AllHandsontheBadOne_files/AHOTBO2.jpg" cd:pos="2" align="left" border="0" height="257" hspace="4" width="580"><br clear="all"></span>
|
||||
<p><strong></strong> </p>
|
||||
<p><strong>Riff 3 (3a and 3b) is a little masterpeice:</strong></p><span><img alt="All Hands on the Bad One Riff 3a" src="AllHandsontheBadOne_files/AHOTBO3a.jpg" cd:pos="2" align="left" border="0" height="446" hspace="4" width="580"><br clear="all"></span>
|
||||
<p><span><img alt="All Hands on the Bad One Riff 3b" src="AllHandsontheBadOne_files/AHOTBO3b.jpg" cd:pos="2" align="left" border="0" height="179" hspace="4" width="580"><br clear="all"></span></p>
|
||||
<p> </p>
|
||||
<p>The Outro</p>
|
||||
<p><span><img alt="All Hands on the Bad One Riff 4" src="AllHandsontheBadOne_files/AHOTBO4.jpg" cd:pos="2" align="left" border="0" height="216" hspace="4" width="580"><br clear="all"></span></p><p></p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<hr>
|
||||
<center>
|
||||
<div class="smallText">
|
||||
The views expressed within this site pretty much represent those of the author.<br>
|
||||
Copyright (c) 2002 <a href="http://tk-jk.net/">Terry Kearns</a>. All rights reserved.
|
||||
</div>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</center>
|
||||
</div>
|
||||
</body></html>
|
||||
BIN
modules/libjar/zipwriter/test/unit/data/test_bug399727.zlib
Normal file
BIN
modules/libjar/zipwriter/test/unit/data/test_bug399727.zlib
Normal file
Binary file not shown.
Binary file not shown.
BIN
modules/libjar/zipwriter/test/unit/data/test_bug717061.gz
Normal file
BIN
modules/libjar/zipwriter/test/unit/data/test_bug717061.gz
Normal file
Binary file not shown.
16
modules/libjar/zipwriter/test/unit/data/test_bug717061.html
Normal file
16
modules/libjar/zipwriter/test/unit/data/test_bug717061.html
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv="Content-Language" content="en-us"><title>Lorem Ipsum</title><style type="text/css">
|
||||
body {
|
||||
font-family: verdana, arial;
|
||||
font-size: 10pt;
|
||||
color: black;
|
||||
background-color: #D0E8E8;
|
||||
}
|
||||
</style></head><body>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
|
||||
|
||||
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
|
||||
|
||||
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.</p>
|
||||
|
||||
</body></html>
|
||||
46
modules/libjar/zipwriter/test/unit/head_zipwriter.js
Normal file
46
modules/libjar/zipwriter/test/unit/head_zipwriter.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var 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 ZIP_EXTENDED_TIMESTAMP_SIZE = 9;
|
||||
|
||||
const PR_USEC_PER_MSEC = 1000;
|
||||
const PR_USEC_PER_SEC = 1000000;
|
||||
const PR_MSEC_PER_SEC = 1000;
|
||||
|
||||
const DATA_DIR = "data/";
|
||||
|
||||
var ioSvc = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
|
||||
var ZipWriter = Components.Constructor("@mozilla.org/zipwriter;1",
|
||||
"nsIZipWriter");
|
||||
var ZipReader = Components.Constructor("@mozilla.org/libjar/zip-reader;1",
|
||||
"nsIZipReader", "open");
|
||||
|
||||
var tmpDir = do_get_profile();
|
||||
var tmpFile = tmpDir.clone();
|
||||
tmpFile.append("zipwriter-test.zip");
|
||||
if (tmpFile.exists())
|
||||
tmpFile.remove(true);
|
||||
|
||||
var zipW = new ZipWriter();
|
||||
14
modules/libjar/zipwriter/test/unit/tail_zipwriter.js
Normal file
14
modules/libjar/zipwriter/test/unit/tail_zipwriter.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
try {
|
||||
zipW.close();
|
||||
}
|
||||
catch (e) {
|
||||
// Just ignore a failure here and attempt to delete the file anyway.
|
||||
}
|
||||
|
||||
if (tmpFile.exists())
|
||||
tmpFile.remove(true);
|
||||
113
modules/libjar/zipwriter/test/unit/test_alignment.js
Normal file
113
modules/libjar/zipwriter/test/unit/test_alignment.js
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
const DATA = "ZIP WRITER TEST DATA";
|
||||
const FILENAME = "test_data.txt";
|
||||
const CRC = 0xe6164331;
|
||||
const time = 1199145600000; // Jan 1st 2008
|
||||
|
||||
var TESTS = [
|
||||
{
|
||||
name: "test.txt",
|
||||
compression: Ci.nsIZipWriter.COMPRESSION_DEFAULT
|
||||
},
|
||||
{
|
||||
name: "test.png",
|
||||
compression: Ci.nsIZipWriter.COMPRESSION_NONE
|
||||
}
|
||||
];
|
||||
|
||||
function swap16(n)
|
||||
{
|
||||
return (((n >> 8) & 0xFF) << 0) |
|
||||
(((n >> 0) & 0xFF) << 8);
|
||||
}
|
||||
|
||||
function swap32(n)
|
||||
{
|
||||
return (((n >> 24) & 0xFF) << 0) |
|
||||
(((n >> 16) & 0xFF) << 8) |
|
||||
(((n >> 8) & 0xFF) << 16) |
|
||||
(((n >> 0) & 0xFF) << 24);
|
||||
}
|
||||
|
||||
function move_to_data(bis, offset)
|
||||
{
|
||||
bis.readBytes(18); // Move to compressed size
|
||||
var size = swap32(bis.read32());
|
||||
bis.readBytes(4);
|
||||
var file_len = swap16(bis.read16());
|
||||
var extra_len = swap16(bis.read16());
|
||||
var file = bis.readBytes(file_len);
|
||||
bis.readBytes(extra_len);
|
||||
offset += ZIP_FILE_HEADER_SIZE + file_len + extra_len;
|
||||
|
||||
return {offset: offset, size: size};
|
||||
}
|
||||
|
||||
function test_alignment(align_size)
|
||||
{
|
||||
// Create zip for testing.
|
||||
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, TESTS[i].compression, source, false);
|
||||
}
|
||||
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);
|
||||
zipW.alignStoredFiles(align_size);
|
||||
zipW.close();
|
||||
|
||||
// Check data can be decompressed.
|
||||
var zipR = new ZipReader(tmpFile);
|
||||
var stream = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Ci.nsIScriptableInputStream);
|
||||
stream.init(zipR.getInputStream(FILENAME));
|
||||
var result = stream.read(DATA.length);
|
||||
do_check_eq(result, DATA);
|
||||
stream.close();
|
||||
zipR.close();
|
||||
|
||||
// Check data is correct and aligned.
|
||||
var fis = Cc["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(tmpFile, -1, -1, null);
|
||||
let bis = Cc["@mozilla.org/binaryinputstream;1"]
|
||||
.createInstance(Ci.nsIBinaryInputStream);
|
||||
bis.setInputStream(fis);
|
||||
var offset = 0;
|
||||
|
||||
var ret = move_to_data(bis, offset); // "test.txt"
|
||||
offset = ret.offset;
|
||||
bis.readBytes(ret.size);
|
||||
offset += ret.size;
|
||||
|
||||
ret = move_to_data(bis, offset); // "test.png"
|
||||
offset = ret.offset;
|
||||
do_check_eq(offset % align_size, 0);
|
||||
bis.readBytes(ret.size);
|
||||
offset += ret.size;
|
||||
|
||||
ret = move_to_data(bis, offset); // "test_data.txt"
|
||||
offset = ret.offset;
|
||||
var result = bis.readBytes(DATA.length);
|
||||
do_check_eq(result, DATA);
|
||||
do_check_eq(offset % align_size, 0);
|
||||
|
||||
fis.close();
|
||||
bis.close();
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
test_alignment(2);
|
||||
test_alignment(4);
|
||||
test_alignment(16);
|
||||
test_alignment(4096);
|
||||
test_alignment(32768);
|
||||
}
|
||||
107
modules/libjar/zipwriter/test/unit/test_asyncadd.js
Normal file
107
modules/libjar/zipwriter/test/unit/test_asyncadd.js
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
var Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
// 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++) {
|
||||
var source = do_get_file(DATA_DIR + TESTS[i].name);
|
||||
for (let method in methods) {
|
||||
var entryName = method + "/" + TESTS[i].name;
|
||||
do_check_true(zipR.hasEntry(entryName));
|
||||
|
||||
var entry = zipR.getEntry(entryName);
|
||||
do_check_eq(entry.realSize, TESTS[i].size);
|
||||
do_check_eq(entry.size, TESTS[i].size);
|
||||
do_check_eq(entry.CRC32, TESTS[i].crc);
|
||||
do_check_eq(Math.floor(entry.lastModifiedTime / PR_USEC_PER_SEC),
|
||||
Math.floor(source.lastModifiedTime / PR_MSEC_PER_SEC));
|
||||
|
||||
zipR.test(entryName);
|
||||
}
|
||||
}
|
||||
|
||||
zipR.close();
|
||||
do_test_finished();
|
||||
}
|
||||
};
|
||||
|
||||
var methods = {
|
||||
file: function method_file(entry, source)
|
||||
{
|
||||
zipW.addEntryFile(entry, Ci.nsIZipWriter.COMPRESSION_NONE, source,
|
||||
true);
|
||||
},
|
||||
channel: function method_channel(entry, source)
|
||||
{
|
||||
zipW.addEntryChannel(entry, source.lastModifiedTime * PR_MSEC_PER_SEC,
|
||||
Ci.nsIZipWriter.COMPRESSION_NONE,
|
||||
NetUtil.newChannel({
|
||||
uri: ioSvc.newFileURI(source),
|
||||
loadUsingSystemPrincipal: true
|
||||
}), true);
|
||||
},
|
||||
stream: function method_stream(entry, source)
|
||||
{
|
||||
zipW.addEntryStream(entry, source.lastModifiedTime * PR_MSEC_PER_SEC,
|
||||
Ci.nsIZipWriter.COMPRESSION_NONE,
|
||||
NetUtil.newChannel({
|
||||
uri: ioSvc.newFileURI(source),
|
||||
loadUsingSystemPrincipal: true
|
||||
}).open2(), true);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
for (let method in methods) {
|
||||
var entry = method + "/" + TESTS[i].name;
|
||||
methods[method](entry, source);
|
||||
size += ZIP_FILE_HEADER_SIZE + ZIP_CDS_HEADER_SIZE +
|
||||
(ZIP_EXTENDED_TIMESTAMP_SIZE * 2) +
|
||||
(entry.length*2) + TESTS[i].size;
|
||||
}
|
||||
}
|
||||
do_test_pending();
|
||||
zipW.processQueue(observer, null);
|
||||
do_check_true(zipW.inQueue);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue