michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "base/basictypes.h" michael@0: michael@0: #include "nsJARURI.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsIIOService.h" michael@0: #include "nsIStandardURL.h" michael@0: #include "nsCRT.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIZipReader.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsNetCID.h" michael@0: #include "nsIObjectInputStream.h" michael@0: #include "nsIObjectOutputStream.h" michael@0: #include "nsIProgrammingLanguage.h" michael@0: #include "mozilla/ipc/URIUtils.h" michael@0: michael@0: using namespace mozilla::ipc; michael@0: michael@0: static NS_DEFINE_CID(kJARURICID, NS_JARURI_CID); michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: nsJARURI::nsJARURI() michael@0: { michael@0: } michael@0: michael@0: nsJARURI::~nsJARURI() michael@0: { michael@0: } michael@0: michael@0: // XXX Why is this threadsafe? michael@0: NS_IMPL_ADDREF(nsJARURI) michael@0: NS_IMPL_RELEASE(nsJARURI) michael@0: NS_INTERFACE_MAP_BEGIN(nsJARURI) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJARURI) michael@0: NS_INTERFACE_MAP_ENTRY(nsIURI) michael@0: NS_INTERFACE_MAP_ENTRY(nsIURL) michael@0: NS_INTERFACE_MAP_ENTRY(nsIJARURI) michael@0: NS_INTERFACE_MAP_ENTRY(nsISerializable) michael@0: NS_INTERFACE_MAP_ENTRY(nsIClassInfo) michael@0: NS_INTERFACE_MAP_ENTRY(nsINestedURI) michael@0: NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableURI) michael@0: // see nsJARURI::Equals michael@0: if (aIID.Equals(NS_GET_IID(nsJARURI))) michael@0: foundInterface = reinterpret_cast(this); michael@0: else michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: nsresult michael@0: nsJARURI::Init(const char *charsetHint) michael@0: { michael@0: mCharsetHint = charsetHint; michael@0: return NS_OK; michael@0: } michael@0: michael@0: #define NS_JAR_SCHEME NS_LITERAL_CSTRING("jar:") michael@0: #define NS_JAR_DELIMITER NS_LITERAL_CSTRING("!/") michael@0: #define NS_BOGUS_ENTRY_SCHEME NS_LITERAL_CSTRING("x:///") michael@0: michael@0: // FormatSpec takes the entry spec (including the "x:///" at the michael@0: // beginning) and gives us a full JAR spec. michael@0: nsresult michael@0: nsJARURI::FormatSpec(const nsACString &entrySpec, nsACString &result, michael@0: bool aIncludeScheme) michael@0: { michael@0: // The entrySpec MUST start with "x:///" michael@0: NS_ASSERTION(StringBeginsWith(entrySpec, NS_BOGUS_ENTRY_SCHEME), michael@0: "bogus entry spec"); michael@0: michael@0: nsAutoCString fileSpec; michael@0: nsresult rv = mJARFile->GetSpec(fileSpec); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (aIncludeScheme) michael@0: result = NS_JAR_SCHEME; michael@0: else michael@0: result.Truncate(); michael@0: michael@0: result.Append(fileSpec + NS_JAR_DELIMITER + michael@0: Substring(entrySpec, 5, entrySpec.Length() - 5)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsJARURI::CreateEntryURL(const nsACString& entryFilename, michael@0: const char* charset, michael@0: nsIURL** url) michael@0: { michael@0: *url = nullptr; michael@0: michael@0: nsCOMPtr stdURL(do_CreateInstance(NS_STANDARDURL_CONTRACTID)); michael@0: if (!stdURL) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: // Flatten the concatenation, just in case. See bug 128288 michael@0: nsAutoCString spec(NS_BOGUS_ENTRY_SCHEME + entryFilename); michael@0: nsresult rv = stdURL->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, michael@0: spec, charset, nullptr); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: return CallQueryInterface(stdURL, url); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsISerializable methods: michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::Read(nsIObjectInputStream* aInputStream) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr supports; michael@0: rv = aInputStream->ReadObject(true, getter_AddRefs(supports)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mJARFile = do_QueryInterface(supports, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = aInputStream->ReadObject(true, getter_AddRefs(supports)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mJAREntry = do_QueryInterface(supports); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = aInputStream->ReadCString(mCharsetHint); michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::Write(nsIObjectOutputStream* aOutputStream) michael@0: { michael@0: nsresult rv; michael@0: michael@0: rv = aOutputStream->WriteCompoundObject(mJARFile, NS_GET_IID(nsIURI), michael@0: true); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = aOutputStream->WriteCompoundObject(mJAREntry, NS_GET_IID(nsIURL), michael@0: true); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = aOutputStream->WriteStringZ(mCharsetHint.get()); michael@0: return rv; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIClassInfo methods: michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetInterfaces(uint32_t *count, nsIID * **array) michael@0: { michael@0: *count = 0; michael@0: *array = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetHelperForLanguage(uint32_t language, nsISupports **_retval) michael@0: { michael@0: *_retval = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetContractID(char * *aContractID) michael@0: { michael@0: *aContractID = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetClassDescription(char * *aClassDescription) michael@0: { michael@0: *aClassDescription = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetClassID(nsCID * *aClassID) michael@0: { michael@0: *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID)); michael@0: if (!*aClassID) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: return GetClassIDNoAlloc(*aClassID); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetImplementationLanguage(uint32_t *aImplementationLanguage) michael@0: { michael@0: *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetFlags(uint32_t *aFlags) michael@0: { michael@0: // XXX We implement THREADSAFE addref/release, but probably shouldn't. michael@0: *aFlags = nsIClassInfo::MAIN_THREAD_ONLY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) michael@0: { michael@0: *aClassIDNoAlloc = kJARURICID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIURI methods: michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetSpec(nsACString &aSpec) michael@0: { michael@0: nsAutoCString entrySpec; michael@0: mJAREntry->GetSpec(entrySpec); michael@0: return FormatSpec(entrySpec, aSpec); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetSpecIgnoringRef(nsACString &aSpec) michael@0: { michael@0: nsAutoCString entrySpec; michael@0: mJAREntry->GetSpecIgnoringRef(entrySpec); michael@0: return FormatSpec(entrySpec, aSpec); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetHasRef(bool *result) michael@0: { michael@0: return mJAREntry->GetHasRef(result); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetSpec(const nsACString& aSpec) michael@0: { michael@0: return SetSpecWithBase(aSpec, nullptr); michael@0: } michael@0: michael@0: nsresult michael@0: nsJARURI::SetSpecWithBase(const nsACString &aSpec, nsIURI* aBaseURL) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr ioServ(do_GetIOService(&rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsAutoCString scheme; michael@0: rv = ioServ->ExtractScheme(aSpec, scheme); michael@0: if (NS_FAILED(rv)) { michael@0: // not an absolute URI michael@0: if (!aBaseURL) michael@0: return NS_ERROR_MALFORMED_URI; michael@0: michael@0: nsRefPtr otherJAR; michael@0: aBaseURL->QueryInterface(NS_GET_IID(nsJARURI), getter_AddRefs(otherJAR)); michael@0: NS_ENSURE_TRUE(otherJAR, NS_NOINTERFACE); michael@0: michael@0: mJARFile = otherJAR->mJARFile; michael@0: michael@0: nsCOMPtr entry(do_CreateInstance(NS_STANDARDURL_CONTRACTID)); michael@0: if (!entry) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: rv = entry->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, michael@0: aSpec, mCharsetHint.get(), otherJAR->mJAREntry); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: mJAREntry = do_QueryInterface(entry); michael@0: if (!mJAREntry) michael@0: return NS_NOINTERFACE; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_ENSURE_TRUE(scheme.EqualsLiteral("jar"), NS_ERROR_MALFORMED_URI); michael@0: michael@0: nsACString::const_iterator begin, end; michael@0: aSpec.BeginReading(begin); michael@0: aSpec.EndReading(end); michael@0: michael@0: while (begin != end && *begin != ':') michael@0: ++begin; michael@0: michael@0: ++begin; // now we're past the "jar:" michael@0: michael@0: // Search backward from the end for the "!/" delimiter. Remember, jar URLs michael@0: // can nest, e.g.: michael@0: // jar:jar:http://www.foo.com/bar.jar!/a.jar!/b.html michael@0: // This gets the b.html document from out of the a.jar file, that's michael@0: // contained within the bar.jar file. michael@0: // Also, the outermost "inner" URI may be a relative URI: michael@0: // jar:../relative.jar!/a.html michael@0: michael@0: nsACString::const_iterator delim_begin (begin), michael@0: delim_end (end); michael@0: michael@0: if (!RFindInReadable(NS_JAR_DELIMITER, delim_begin, delim_end)) michael@0: return NS_ERROR_MALFORMED_URI; michael@0: michael@0: rv = ioServ->NewURI(Substring(begin, delim_begin), mCharsetHint.get(), michael@0: aBaseURL, getter_AddRefs(mJARFile)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: NS_TryToSetImmutable(mJARFile); michael@0: michael@0: // skip over any extra '/' chars michael@0: while (*delim_end == '/') michael@0: ++delim_end; michael@0: michael@0: return SetJAREntry(Substring(delim_end, end)); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetPrePath(nsACString &prePath) michael@0: { michael@0: prePath = NS_JAR_SCHEME; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetScheme(nsACString &aScheme) michael@0: { michael@0: aScheme = "jar"; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetScheme(const nsACString &aScheme) michael@0: { michael@0: // doesn't make sense to set the scheme of a jar: URL michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetUserPass(nsACString &aUserPass) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetUserPass(const nsACString &aUserPass) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetUsername(nsACString &aUsername) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetUsername(const nsACString &aUsername) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetPassword(nsACString &aPassword) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetPassword(const nsACString &aPassword) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetHostPort(nsACString &aHostPort) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetHostPort(const nsACString &aHostPort) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetHost(nsACString &aHost) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetHost(const nsACString &aHost) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetPort(int32_t *aPort) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetPort(int32_t aPort) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetPath(nsACString &aPath) michael@0: { michael@0: nsAutoCString entrySpec; michael@0: mJAREntry->GetSpec(entrySpec); michael@0: return FormatSpec(entrySpec, aPath, false); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetPath(const nsACString &aPath) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetAsciiSpec(nsACString &aSpec) michael@0: { michael@0: // XXX Shouldn't this like... make sure it returns ASCII or something? michael@0: return GetSpec(aSpec); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetAsciiHost(nsACString &aHost) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetOriginCharset(nsACString &aOriginCharset) michael@0: { michael@0: aOriginCharset = mCharsetHint; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::Equals(nsIURI *other, bool *result) michael@0: { michael@0: return EqualsInternal(other, eHonorRef, result); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::EqualsExceptRef(nsIURI *other, bool *result) michael@0: { michael@0: return EqualsInternal(other, eIgnoreRef, result); michael@0: } michael@0: michael@0: // Helper method: michael@0: /* virtual */ nsresult michael@0: nsJARURI::EqualsInternal(nsIURI *other, michael@0: nsJARURI::RefHandlingEnum refHandlingMode, michael@0: bool *result) michael@0: { michael@0: *result = false; michael@0: michael@0: if (!other) michael@0: return NS_OK; // not equal michael@0: michael@0: nsRefPtr otherJAR; michael@0: other->QueryInterface(NS_GET_IID(nsJARURI), getter_AddRefs(otherJAR)); michael@0: if (!otherJAR) michael@0: return NS_OK; // not equal michael@0: michael@0: bool equal; michael@0: nsresult rv = mJARFile->Equals(otherJAR->mJARFile, &equal); michael@0: if (NS_FAILED(rv) || !equal) { michael@0: return rv; // not equal michael@0: } michael@0: michael@0: return refHandlingMode == eHonorRef ? michael@0: mJAREntry->Equals(otherJAR->mJAREntry, result) : michael@0: mJAREntry->EqualsExceptRef(otherJAR->mJAREntry, result); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SchemeIs(const char *i_Scheme, bool *o_Equals) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(o_Equals); michael@0: if (!i_Scheme) return NS_ERROR_INVALID_ARG; michael@0: michael@0: if (*i_Scheme == 'j' || *i_Scheme == 'J') { michael@0: *o_Equals = PL_strcasecmp("jar", i_Scheme) ? false : true; michael@0: } else { michael@0: *o_Equals = false; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::Clone(nsIURI **result) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr uri; michael@0: rv = CloneWithJARFileInternal(mJARFile, eHonorRef, getter_AddRefs(uri)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: return CallQueryInterface(uri, result); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::CloneIgnoringRef(nsIURI **result) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr uri; michael@0: rv = CloneWithJARFileInternal(mJARFile, eIgnoreRef, getter_AddRefs(uri)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: return CallQueryInterface(uri, result); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::Resolve(const nsACString &relativePath, nsACString &result) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr ioServ(do_GetIOService(&rv)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsAutoCString scheme; michael@0: rv = ioServ->ExtractScheme(relativePath, scheme); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: // then aSpec is absolute michael@0: result = relativePath; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsAutoCString resolvedPath; michael@0: mJAREntry->Resolve(relativePath, resolvedPath); michael@0: michael@0: return FormatSpec(resolvedPath, result); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIURL methods: michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetFilePath(nsACString& filePath) michael@0: { michael@0: return mJAREntry->GetFilePath(filePath); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetFilePath(const nsACString& filePath) michael@0: { michael@0: return mJAREntry->SetFilePath(filePath); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetQuery(nsACString& query) michael@0: { michael@0: return mJAREntry->GetQuery(query); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetQuery(const nsACString& query) michael@0: { michael@0: return mJAREntry->SetQuery(query); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetRef(nsACString& ref) michael@0: { michael@0: return mJAREntry->GetRef(ref); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetRef(const nsACString& ref) michael@0: { michael@0: return mJAREntry->SetRef(ref); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetDirectory(nsACString& directory) michael@0: { michael@0: return mJAREntry->GetDirectory(directory); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetDirectory(const nsACString& directory) michael@0: { michael@0: return mJAREntry->SetDirectory(directory); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetFileName(nsACString& fileName) michael@0: { michael@0: return mJAREntry->GetFileName(fileName); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetFileName(const nsACString& fileName) michael@0: { michael@0: return mJAREntry->SetFileName(fileName); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetFileBaseName(nsACString& fileBaseName) michael@0: { michael@0: return mJAREntry->GetFileBaseName(fileBaseName); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetFileBaseName(const nsACString& fileBaseName) michael@0: { michael@0: return mJAREntry->SetFileBaseName(fileBaseName); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetFileExtension(nsACString& fileExtension) michael@0: { michael@0: return mJAREntry->GetFileExtension(fileExtension); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetFileExtension(const nsACString& fileExtension) michael@0: { michael@0: return mJAREntry->SetFileExtension(fileExtension); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetCommonBaseSpec(nsIURI* uriToCompare, nsACString& commonSpec) michael@0: { michael@0: commonSpec.Truncate(); michael@0: michael@0: NS_ENSURE_ARG_POINTER(uriToCompare); michael@0: michael@0: commonSpec.Truncate(); michael@0: nsCOMPtr otherJARURI(do_QueryInterface(uriToCompare)); michael@0: if (!otherJARURI) { michael@0: // Nothing in common michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr otherJARFile; michael@0: nsresult rv = otherJARURI->GetJARFile(getter_AddRefs(otherJARFile)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: bool equal; michael@0: rv = mJARFile->Equals(otherJARFile, &equal); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (!equal) { michael@0: // See what the JAR file URIs have in common michael@0: nsCOMPtr ourJARFileURL(do_QueryInterface(mJARFile)); michael@0: if (!ourJARFileURL) { michael@0: // Not a URL, so nothing in common michael@0: return NS_OK; michael@0: } michael@0: nsAutoCString common; michael@0: rv = ourJARFileURL->GetCommonBaseSpec(otherJARFile, common); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: commonSpec = NS_JAR_SCHEME + common; michael@0: return NS_OK; michael@0: michael@0: } michael@0: michael@0: // At this point we have the same JAR file. Compare the JAREntrys michael@0: nsAutoCString otherEntry; michael@0: rv = otherJARURI->GetJAREntry(otherEntry); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsAutoCString otherCharset; michael@0: rv = uriToCompare->GetOriginCharset(otherCharset); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr url; michael@0: rv = CreateEntryURL(otherEntry, otherCharset.get(), getter_AddRefs(url)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsAutoCString common; michael@0: rv = mJAREntry->GetCommonBaseSpec(url, common); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = FormatSpec(common, commonSpec); michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetRelativeSpec(nsIURI* uriToCompare, nsACString& relativeSpec) michael@0: { michael@0: GetSpec(relativeSpec); michael@0: michael@0: NS_ENSURE_ARG_POINTER(uriToCompare); michael@0: michael@0: nsCOMPtr otherJARURI(do_QueryInterface(uriToCompare)); michael@0: if (!otherJARURI) { michael@0: // Nothing in common michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr otherJARFile; michael@0: nsresult rv = otherJARURI->GetJARFile(getter_AddRefs(otherJARFile)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: bool equal; michael@0: rv = mJARFile->Equals(otherJARFile, &equal); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (!equal) { michael@0: // We live in different JAR files. Nothing in common. michael@0: return rv; michael@0: } michael@0: michael@0: // Same JAR file. Compare the JAREntrys michael@0: nsAutoCString otherEntry; michael@0: rv = otherJARURI->GetJAREntry(otherEntry); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsAutoCString otherCharset; michael@0: rv = uriToCompare->GetOriginCharset(otherCharset); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr url; michael@0: rv = CreateEntryURL(otherEntry, otherCharset.get(), getter_AddRefs(url)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsAutoCString relativeEntrySpec; michael@0: rv = mJAREntry->GetRelativeSpec(url, relativeEntrySpec); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (!StringBeginsWith(relativeEntrySpec, NS_BOGUS_ENTRY_SCHEME)) { michael@0: // An actual relative spec! michael@0: relativeSpec = relativeEntrySpec; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIJARURI methods: michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetJARFile(nsIURI* *jarFile) michael@0: { michael@0: return GetInnerURI(jarFile); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetJAREntry(nsACString &entryPath) michael@0: { michael@0: nsAutoCString filePath; michael@0: mJAREntry->GetFilePath(filePath); michael@0: NS_ASSERTION(filePath.Length() > 0, "path should never be empty!"); michael@0: // Trim off the leading '/' michael@0: entryPath = Substring(filePath, 1, filePath.Length() - 1); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::SetJAREntry(const nsACString &entryPath) michael@0: { michael@0: return CreateEntryURL(entryPath, mCharsetHint.get(), michael@0: getter_AddRefs(mJAREntry)); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::CloneWithJARFile(nsIURI *jarFile, nsIJARURI **result) michael@0: { michael@0: return CloneWithJARFileInternal(jarFile, eHonorRef, result); michael@0: } michael@0: michael@0: nsresult michael@0: nsJARURI::CloneWithJARFileInternal(nsIURI *jarFile, michael@0: nsJARURI::RefHandlingEnum refHandlingMode, michael@0: nsIJARURI **result) michael@0: { michael@0: if (!jarFile) { michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr newJARFile; michael@0: rv = jarFile->Clone(getter_AddRefs(newJARFile)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: NS_TryToSetImmutable(newJARFile); michael@0: michael@0: nsCOMPtr newJAREntryURI; michael@0: rv = refHandlingMode == eHonorRef ? michael@0: mJAREntry->Clone(getter_AddRefs(newJAREntryURI)) : michael@0: mJAREntry->CloneIgnoringRef(getter_AddRefs(newJAREntryURI)); michael@0: michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr newJAREntry(do_QueryInterface(newJAREntryURI)); michael@0: NS_ASSERTION(newJAREntry, "This had better QI to nsIURL!"); michael@0: michael@0: nsJARURI* uri = new nsJARURI(); michael@0: NS_ADDREF(uri); michael@0: uri->mJARFile = newJARFile; michael@0: uri->mJAREntry = newJAREntry; michael@0: *result = uri; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetInnerURI(nsIURI **uri) michael@0: { michael@0: return NS_EnsureSafeToReturn(mJARFile, uri); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsJARURI::GetInnermostURI(nsIURI** uri) michael@0: { michael@0: return NS_ImplGetInnermostURI(this, uri); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIIPCSerializableURI methods: michael@0: michael@0: void michael@0: nsJARURI::Serialize(URIParams& aParams) michael@0: { michael@0: JARURIParams params; michael@0: michael@0: SerializeURI(mJARFile, params.jarFile()); michael@0: SerializeURI(mJAREntry, params.jarEntry()); michael@0: params.charset() = mCharsetHint; michael@0: michael@0: aParams = params; michael@0: } michael@0: michael@0: bool michael@0: nsJARURI::Deserialize(const URIParams& aParams) michael@0: { michael@0: if (aParams.type() != URIParams::TJARURIParams) { michael@0: NS_ERROR("Received unknown parameters from the other process!"); michael@0: return false; michael@0: } michael@0: michael@0: const JARURIParams& params = aParams.get_JARURIParams(); michael@0: michael@0: nsCOMPtr file = DeserializeURI(params.jarFile()); michael@0: if (!file) { michael@0: NS_ERROR("Couldn't deserialize jar file URI!"); michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr entry = DeserializeURI(params.jarEntry()); michael@0: if (!entry) { michael@0: NS_ERROR("Couldn't deserialize jar entry URI!"); michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr entryURL = do_QueryInterface(entry); michael@0: if (!entryURL) { michael@0: NS_ERROR("Couldn't QI jar entry URI to nsIURL!"); michael@0: return false; michael@0: } michael@0: michael@0: mJARFile.swap(file); michael@0: mJAREntry.swap(entryURL); michael@0: mCharsetHint = params.charset(); michael@0: michael@0: return true; michael@0: }