Back to index

lightning-sunbird  0.9+nobinonly
nsJARURI.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org Code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsJARURI.h"
00040 #include "nsNetUtil.h"
00041 #include "nsIIOService.h"
00042 #include "nsIStandardURL.h"
00043 #include "nsCRT.h"
00044 #include "nsIComponentManager.h"
00045 #include "nsIServiceManager.h"
00046 #include "nsIZipReader.h"
00047 #include "nsReadableUtils.h"
00048 #include "nsAutoPtr.h"
00049 #include "nsNetCID.h"
00050 #include "nsIObjectInputStream.h"
00051 #include "nsIObjectOutputStream.h"
00052 
00053 static NS_DEFINE_CID(kJARURICID, NS_JARURI_CID);
00054 
00056  
00057 nsJARURI::nsJARURI()
00058 {
00059 }
00060  
00061 nsJARURI::~nsJARURI()
00062 {
00063 }
00064 
00065 // XXX Why is this threadsafe?
00066 NS_IMPL_THREADSAFE_ADDREF(nsJARURI)
00067 NS_IMPL_THREADSAFE_RELEASE(nsJARURI)
00068 NS_INTERFACE_MAP_BEGIN(nsJARURI)
00069   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJARURI)
00070   NS_INTERFACE_MAP_ENTRY(nsIURI)
00071   NS_INTERFACE_MAP_ENTRY(nsIURL)
00072   NS_INTERFACE_MAP_ENTRY(nsIJARURI)
00073   NS_INTERFACE_MAP_ENTRY(nsIJARURI_MOZILLA_1_8_BRANCH)
00074   NS_INTERFACE_MAP_ENTRY(nsISerializable)
00075   NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
00076   // see nsJARURI::Equals
00077   if (aIID.Equals(NS_GET_IID(nsJARURI)))
00078       foundInterface = NS_REINTERPRET_CAST(nsISupports*, this);
00079   else
00080 NS_INTERFACE_MAP_END
00081 
00082 nsresult
00083 nsJARURI::Init(const char *charsetHint)
00084 {
00085     mCharsetHint = charsetHint;
00086     return NS_OK;
00087 }
00088 
00089 #define NS_JAR_SCHEME           NS_LITERAL_CSTRING("jar:")
00090 #define NS_JAR_DELIMITER        NS_LITERAL_CSTRING("!/")
00091 #define NS_BOGUS_ENTRY_SCHEME   NS_LITERAL_CSTRING("x:///")
00092 
00093 // FormatSpec takes the entry spec (including the "x:///" at the
00094 // beginning) and gives us a full JAR spec.
00095 nsresult
00096 nsJARURI::FormatSpec(const nsACString &entrySpec, nsACString &result,
00097                      PRBool aIncludeScheme)
00098 {
00099     // The entrySpec MUST start with "x:///"
00100     NS_ASSERTION(StringBeginsWith(entrySpec, NS_BOGUS_ENTRY_SCHEME),
00101                  "bogus entry spec");
00102 
00103     nsCAutoString fileSpec;
00104     nsresult rv = mJARFile->GetSpec(fileSpec);
00105     if (NS_FAILED(rv)) return rv;
00106 
00107     if (aIncludeScheme)
00108         result = NS_JAR_SCHEME;
00109     else
00110         result.Truncate();
00111 
00112     result.Append(fileSpec + NS_JAR_DELIMITER +
00113                   Substring(entrySpec, 5, entrySpec.Length() - 5));
00114     return NS_OK;
00115 }
00116 
00117 nsresult
00118 nsJARURI::CreateEntryURL(const nsACString& entryFilename,
00119                          const char* charset,
00120                          nsIURL** url)
00121 {
00122     *url = nsnull;
00123 
00124     nsCOMPtr<nsIStandardURL> stdURL(do_CreateInstance(NS_STANDARDURL_CONTRACTID));
00125     if (!stdURL) {
00126         return NS_ERROR_OUT_OF_MEMORY;
00127     }
00128 
00129     // Flatten the concatenation, just in case.  See bug 128288
00130     nsCAutoString spec(NS_BOGUS_ENTRY_SCHEME + entryFilename);
00131     nsresult rv = stdURL->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
00132                                spec, charset, nsnull);
00133     if (NS_FAILED(rv)) {
00134         return rv;
00135     }
00136 
00137     return CallQueryInterface(stdURL, url);
00138 }
00139     
00141 // nsISerializable methods:
00142 
00143 NS_IMETHODIMP
00144 nsJARURI::Read(nsIObjectInputStream* aInputStream)
00145 {
00146     nsresult rv;
00147 
00148     rv = aInputStream->ReadObject(PR_TRUE, getter_AddRefs(mJARFile));
00149     NS_ENSURE_SUCCESS(rv, rv);
00150 
00151     rv = aInputStream->ReadObject(PR_TRUE, getter_AddRefs(mJAREntry));
00152     NS_ENSURE_SUCCESS(rv, rv);
00153 
00154     rv = aInputStream->ReadCString(mCharsetHint);
00155     return rv;
00156 }
00157 
00158 NS_IMETHODIMP
00159 nsJARURI::Write(nsIObjectOutputStream* aOutputStream)
00160 {
00161     nsresult rv;
00162     
00163     rv = aOutputStream->WriteCompoundObject(mJARFile, NS_GET_IID(nsIURI),
00164                                             PR_TRUE);
00165     NS_ENSURE_SUCCESS(rv, rv);
00166 
00167     rv = aOutputStream->WriteCompoundObject(mJAREntry, NS_GET_IID(nsIURL),
00168                                             PR_TRUE);
00169     NS_ENSURE_SUCCESS(rv, rv);
00170 
00171     rv = aOutputStream->WriteStringZ(mCharsetHint.get());
00172     return rv;
00173 }
00174 
00176 // nsIClassInfo methods:
00177 
00178 NS_IMETHODIMP 
00179 nsJARURI::GetInterfaces(PRUint32 *count, nsIID * **array)
00180 {
00181     *count = 0;
00182     *array = nsnull;
00183     return NS_OK;
00184 }
00185 
00186 NS_IMETHODIMP 
00187 nsJARURI::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
00188 {
00189     *_retval = nsnull;
00190     return NS_OK;
00191 }
00192 
00193 NS_IMETHODIMP 
00194 nsJARURI::GetContractID(char * *aContractID)
00195 {
00196     *aContractID = nsnull;
00197     return NS_OK;
00198 }
00199 
00200 NS_IMETHODIMP 
00201 nsJARURI::GetClassDescription(char * *aClassDescription)
00202 {
00203     *aClassDescription = nsnull;
00204     return NS_OK;
00205 }
00206 
00207 NS_IMETHODIMP 
00208 nsJARURI::GetClassID(nsCID * *aClassID)
00209 {
00210     *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
00211     if (!*aClassID)
00212         return NS_ERROR_OUT_OF_MEMORY;
00213     return GetClassIDNoAlloc(*aClassID);
00214 }
00215 
00216 NS_IMETHODIMP 
00217 nsJARURI::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
00218 {
00219     *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
00220     return NS_OK;
00221 }
00222 
00223 NS_IMETHODIMP 
00224 nsJARURI::GetFlags(PRUint32 *aFlags)
00225 {
00226     // XXX We implement THREADSAFE addref/release, but probably shouldn't.
00227     *aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
00228     return NS_OK;
00229 }
00230 
00231 NS_IMETHODIMP 
00232 nsJARURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
00233 {
00234     *aClassIDNoAlloc = kJARURICID;
00235     return NS_OK;
00236 }
00237 
00239 // nsIURI methods:
00240 
00241 NS_IMETHODIMP
00242 nsJARURI::GetSpec(nsACString &aSpec)
00243 {
00244     nsCAutoString entrySpec;
00245     mJAREntry->GetSpec(entrySpec);
00246     return FormatSpec(entrySpec, aSpec);
00247 }
00248 
00249 NS_IMETHODIMP
00250 nsJARURI::SetSpec(const nsACString& aSpec)
00251 {
00252     return SetSpecWithBase(aSpec, nsnull);
00253 }
00254 
00255 nsresult
00256 nsJARURI::SetSpecWithBase(const nsACString &aSpec, nsIURI* aBaseURL)
00257 {
00258     nsresult rv;
00259 
00260     nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
00261     NS_ENSURE_SUCCESS(rv, rv);
00262 
00263     nsCAutoString scheme;
00264     rv = ioServ->ExtractScheme(aSpec, scheme);
00265     if (NS_FAILED(rv)) {
00266         // not an absolute URI
00267         if (!aBaseURL)
00268             return NS_ERROR_MALFORMED_URI;
00269 
00270         nsRefPtr<nsJARURI> otherJAR;
00271         aBaseURL->QueryInterface(NS_GET_IID(nsJARURI), getter_AddRefs(otherJAR));
00272         NS_ENSURE_TRUE(otherJAR, NS_NOINTERFACE);
00273 
00274         mJARFile = otherJAR->mJARFile;
00275 
00276         nsCOMPtr<nsIStandardURL> entry(do_CreateInstance(NS_STANDARDURL_CONTRACTID));
00277         if (!entry)
00278             return NS_ERROR_OUT_OF_MEMORY;
00279 
00280         rv = entry->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
00281                          aSpec, mCharsetHint.get(), otherJAR->mJAREntry);
00282         if (NS_FAILED(rv))
00283             return rv;
00284 
00285         mJAREntry = do_QueryInterface(entry);
00286         if (!mJAREntry)
00287             return NS_NOINTERFACE;
00288 
00289         return NS_OK;
00290     }
00291 
00292     NS_ENSURE_TRUE(scheme.EqualsLiteral("jar"), NS_ERROR_MALFORMED_URI);
00293 
00294     nsACString::const_iterator begin, end;
00295     aSpec.BeginReading(begin);
00296     aSpec.EndReading(end);
00297 
00298     while (begin != end && *begin != ':')
00299         ++begin;
00300 
00301     ++begin; // now we're past the "jar:"
00302 
00303     // Search backward from the end for the "!/" delimiter. Remember, jar URLs
00304     // can nest, e.g.:
00305     //    jar:jar:http://www.foo.com/bar.jar!/a.jar!/b.html
00306     // This gets the b.html document from out of the a.jar file, that's 
00307     // contained within the bar.jar file.
00308     // Also, the outermost "inner" URI may be a relative URI:
00309     //   jar:../relative.jar!/a.html
00310 
00311     nsACString::const_iterator delim_begin (begin),
00312                                delim_end   (end);
00313 
00314     if (!RFindInReadable(NS_JAR_DELIMITER, delim_begin, delim_end))
00315         return NS_ERROR_MALFORMED_URI;
00316 
00317     rv = ioServ->NewURI(Substring(begin, delim_begin), mCharsetHint.get(),
00318                         aBaseURL, getter_AddRefs(mJARFile));
00319     if (NS_FAILED(rv)) return rv;
00320 
00321     // skip over any extra '/' chars
00322     while (*delim_end == '/')
00323         ++delim_end;
00324 
00325     return SetJAREntry(Substring(delim_end, end));
00326 }
00327 
00328 NS_IMETHODIMP
00329 nsJARURI::GetPrePath(nsACString &prePath)
00330 {
00331     prePath = NS_JAR_SCHEME;
00332     return NS_OK;
00333 }
00334 
00335 NS_IMETHODIMP
00336 nsJARURI::GetScheme(nsACString &aScheme)
00337 {
00338     aScheme = "jar";
00339     return NS_OK;
00340 }
00341 
00342 NS_IMETHODIMP
00343 nsJARURI::SetScheme(const nsACString &aScheme)
00344 {
00345     // doesn't make sense to set the scheme of a jar: URL
00346     return NS_ERROR_FAILURE;
00347 }
00348 
00349 NS_IMETHODIMP
00350 nsJARURI::GetUserPass(nsACString &aUserPass)
00351 {
00352     return NS_ERROR_FAILURE;
00353 }
00354 
00355 NS_IMETHODIMP
00356 nsJARURI::SetUserPass(const nsACString &aUserPass)
00357 {
00358     return NS_ERROR_FAILURE;
00359 }
00360 
00361 NS_IMETHODIMP
00362 nsJARURI::GetUsername(nsACString &aUsername)
00363 {
00364     return NS_ERROR_FAILURE;
00365 }
00366 
00367 NS_IMETHODIMP
00368 nsJARURI::SetUsername(const nsACString &aUsername)
00369 {
00370     return NS_ERROR_FAILURE;
00371 }
00372 
00373 NS_IMETHODIMP
00374 nsJARURI::GetPassword(nsACString &aPassword)
00375 {
00376     return NS_ERROR_FAILURE;
00377 }
00378 
00379 NS_IMETHODIMP
00380 nsJARURI::SetPassword(const nsACString &aPassword)
00381 {
00382     return NS_ERROR_FAILURE;
00383 }
00384 
00385 NS_IMETHODIMP
00386 nsJARURI::GetHostPort(nsACString &aHostPort)
00387 {
00388     return NS_ERROR_FAILURE;
00389 }
00390 
00391 NS_IMETHODIMP
00392 nsJARURI::SetHostPort(const nsACString &aHostPort)
00393 {
00394     return NS_ERROR_FAILURE;
00395 }
00396 
00397 NS_IMETHODIMP
00398 nsJARURI::GetHost(nsACString &aHost)
00399 {
00400     return NS_ERROR_FAILURE;
00401 }
00402 
00403 NS_IMETHODIMP
00404 nsJARURI::SetHost(const nsACString &aHost)
00405 {
00406     return NS_ERROR_FAILURE;
00407 }
00408 
00409 NS_IMETHODIMP
00410 nsJARURI::GetPort(PRInt32 *aPort)
00411 {
00412     return NS_ERROR_FAILURE;
00413 }
00414  
00415 NS_IMETHODIMP
00416 nsJARURI::SetPort(PRInt32 aPort)
00417 {
00418     return NS_ERROR_FAILURE;
00419 }
00420 
00421 NS_IMETHODIMP
00422 nsJARURI::GetPath(nsACString &aPath)
00423 {
00424     nsCAutoString entrySpec;
00425     mJAREntry->GetSpec(entrySpec);
00426     return FormatSpec(entrySpec, aPath, PR_FALSE);
00427 }
00428 
00429 NS_IMETHODIMP
00430 nsJARURI::SetPath(const nsACString &aPath)
00431 {
00432     return NS_ERROR_FAILURE;
00433 }
00434 
00435 NS_IMETHODIMP
00436 nsJARURI::GetAsciiSpec(nsACString &aSpec)
00437 {
00438     // XXX Shouldn't this like... make sure it returns ASCII or something?
00439     return GetSpec(aSpec);
00440 }
00441 
00442 NS_IMETHODIMP
00443 nsJARURI::GetAsciiHost(nsACString &aHost)
00444 {
00445     return NS_ERROR_FAILURE;
00446 }
00447 
00448 NS_IMETHODIMP
00449 nsJARURI::GetOriginCharset(nsACString &aOriginCharset)
00450 {
00451     aOriginCharset = mCharsetHint;
00452     return NS_OK;
00453 }
00454 
00455 NS_IMETHODIMP
00456 nsJARURI::Equals(nsIURI *other, PRBool *result)
00457 {
00458     nsresult rv;
00459 
00460     *result = PR_FALSE;
00461 
00462     if (other == nsnull)
00463         return NS_OK;       // not equal
00464 
00465     nsRefPtr<nsJARURI> otherJAR;
00466     other->QueryInterface(NS_GET_IID(nsJARURI), getter_AddRefs(otherJAR));
00467     if (!otherJAR)
00468         return NS_OK;   // not equal
00469 
00470     PRBool equal;
00471     rv = mJARFile->Equals(otherJAR->mJARFile, &equal);
00472     if (NS_FAILED(rv) || !equal) {
00473         return rv;   // not equal
00474     }
00475 
00476     rv = mJAREntry->Equals(otherJAR->mJAREntry, result);
00477     return rv;
00478 }
00479 
00480 NS_IMETHODIMP
00481 nsJARURI::SchemeIs(const char *i_Scheme, PRBool *o_Equals)
00482 {
00483     NS_ENSURE_ARG_POINTER(o_Equals);
00484     if (!i_Scheme) return NS_ERROR_INVALID_ARG;
00485 
00486     if (*i_Scheme == 'j' || *i_Scheme == 'J') {
00487         *o_Equals = PL_strcasecmp("jar", i_Scheme) ? PR_FALSE : PR_TRUE;
00488     } else {
00489         *o_Equals = PR_FALSE;
00490     }
00491     return NS_OK;
00492 }
00493 
00494 NS_IMETHODIMP
00495 nsJARURI::Clone(nsIURI **result)
00496 {
00497     nsresult rv;
00498 
00499     nsCOMPtr<nsIJARURI> uri;
00500     rv = CloneWithJARFile(mJARFile, getter_AddRefs(uri));
00501     if (NS_FAILED(rv)) return rv;
00502 
00503     return CallQueryInterface(uri, result);
00504 }
00505 
00506 NS_IMETHODIMP
00507 nsJARURI::Resolve(const nsACString &relativePath, nsACString &result)
00508 {
00509     nsresult rv;
00510 
00511     nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
00512     if (NS_FAILED(rv))
00513       return rv;
00514 
00515     nsCAutoString scheme;
00516     rv = ioServ->ExtractScheme(relativePath, scheme);
00517     if (NS_SUCCEEDED(rv)) {
00518         // then aSpec is absolute
00519         result = relativePath;
00520         return NS_OK;
00521     }
00522 
00523     nsCAutoString resolvedPath;
00524     mJAREntry->Resolve(relativePath, resolvedPath);
00525     
00526     return FormatSpec(resolvedPath, result);
00527 }
00528 
00530 // nsIURL methods:
00531 
00532 NS_IMETHODIMP
00533 nsJARURI::GetFilePath(nsACString& filePath)
00534 {
00535     return mJAREntry->GetFilePath(filePath);
00536 }
00537 
00538 NS_IMETHODIMP
00539 nsJARURI::SetFilePath(const nsACString& filePath)
00540 {
00541     return mJAREntry->SetFilePath(filePath);
00542 }
00543 
00544 NS_IMETHODIMP
00545 nsJARURI::GetParam(nsACString& param)
00546 {
00547     param.Truncate();
00548     return NS_OK;
00549 }
00550 
00551 NS_IMETHODIMP
00552 nsJARURI::SetParam(const nsACString& param)
00553 {
00554     return NS_ERROR_NOT_AVAILABLE;
00555 }
00556 
00557 NS_IMETHODIMP
00558 nsJARURI::GetQuery(nsACString& query)
00559 {
00560     query.Truncate();
00561     return NS_OK;
00562 }
00563 
00564 NS_IMETHODIMP
00565 nsJARURI::SetQuery(const nsACString& query)
00566 {
00567     return NS_ERROR_NOT_AVAILABLE;
00568 }
00569 
00570 NS_IMETHODIMP
00571 nsJARURI::GetRef(nsACString& ref)
00572 {
00573     return mJAREntry->GetRef(ref);
00574 }
00575 
00576 NS_IMETHODIMP
00577 nsJARURI::SetRef(const nsACString& ref)
00578 {
00579     return mJAREntry->SetRef(ref);
00580 }
00581 
00582 NS_IMETHODIMP
00583 nsJARURI::GetDirectory(nsACString& directory)
00584 {
00585     return mJAREntry->GetDirectory(directory);
00586 }
00587 
00588 NS_IMETHODIMP
00589 nsJARURI::SetDirectory(const nsACString& directory)
00590 {
00591     return mJAREntry->SetDirectory(directory);
00592 }
00593 
00594 NS_IMETHODIMP
00595 nsJARURI::GetFileName(nsACString& fileName)
00596 {
00597     return mJAREntry->GetFileName(fileName);
00598 }
00599 
00600 NS_IMETHODIMP
00601 nsJARURI::SetFileName(const nsACString& fileName)
00602 {
00603     return mJAREntry->SetFileName(fileName);
00604 }
00605 
00606 NS_IMETHODIMP
00607 nsJARURI::GetFileBaseName(nsACString& fileBaseName)
00608 {
00609     return mJAREntry->GetFileBaseName(fileBaseName);
00610 }
00611 
00612 NS_IMETHODIMP
00613 nsJARURI::SetFileBaseName(const nsACString& fileBaseName)
00614 {
00615     return mJAREntry->SetFileBaseName(fileBaseName);
00616 }
00617 
00618 NS_IMETHODIMP
00619 nsJARURI::GetFileExtension(nsACString& fileExtension)
00620 {
00621     return mJAREntry->GetFileExtension(fileExtension);
00622 }
00623 
00624 NS_IMETHODIMP
00625 nsJARURI::SetFileExtension(const nsACString& fileExtension)
00626 {
00627     return mJAREntry->SetFileExtension(fileExtension);
00628 }
00629 
00630 NS_IMETHODIMP
00631 nsJARURI::GetCommonBaseSpec(nsIURI* uriToCompare, nsACString& commonSpec)
00632 {
00633     commonSpec.Truncate();
00634 
00635     NS_ENSURE_ARG_POINTER(uriToCompare);
00636     
00637     commonSpec.Truncate();
00638     nsCOMPtr<nsIJARURI> otherJARURI(do_QueryInterface(uriToCompare));
00639     if (!otherJARURI) {
00640         // Nothing in common
00641         return NS_OK;
00642     }
00643 
00644     nsCOMPtr<nsIURI> otherJARFile;
00645     nsresult rv = otherJARURI->GetJARFile(getter_AddRefs(otherJARFile));
00646     if (NS_FAILED(rv)) return rv;
00647 
00648     PRBool equal;
00649     rv = mJARFile->Equals(otherJARFile, &equal);
00650     if (NS_FAILED(rv)) return rv;
00651 
00652     if (!equal) {
00653         // See what the JAR file URIs have in common
00654         nsCOMPtr<nsIURL> ourJARFileURL(do_QueryInterface(mJARFile));
00655         if (!ourJARFileURL) {
00656             // Not a URL, so nothing in common
00657             return NS_OK;
00658         }
00659         nsCAutoString common;
00660         rv = ourJARFileURL->GetCommonBaseSpec(otherJARFile, common);
00661         if (NS_FAILED(rv)) return rv;
00662 
00663         commonSpec = NS_JAR_SCHEME + common;
00664         return NS_OK;
00665         
00666     }
00667     
00668     // At this point we have the same JAR file.  Compare the JAREntrys
00669     nsCAutoString otherEntry;
00670     rv = otherJARURI->GetJAREntry(otherEntry);
00671     if (NS_FAILED(rv)) return rv;
00672 
00673     nsCAutoString otherCharset;
00674     rv = uriToCompare->GetOriginCharset(otherCharset);
00675     if (NS_FAILED(rv)) return rv;
00676 
00677     nsCOMPtr<nsIURL> url;
00678     rv = CreateEntryURL(otherEntry, otherCharset.get(), getter_AddRefs(url));
00679     if (NS_FAILED(rv)) return rv;
00680 
00681     nsCAutoString common;
00682     rv = mJAREntry->GetCommonBaseSpec(url, common);
00683     if (NS_FAILED(rv)) return rv;
00684 
00685     rv = FormatSpec(common, commonSpec);
00686     return rv;
00687 }
00688 
00689 NS_IMETHODIMP
00690 nsJARURI::GetRelativeSpec(nsIURI* uriToCompare, nsACString& relativeSpec)
00691 {
00692     GetSpec(relativeSpec);
00693 
00694     NS_ENSURE_ARG_POINTER(uriToCompare);
00695 
00696     nsCOMPtr<nsIJARURI> otherJARURI(do_QueryInterface(uriToCompare));
00697     if (!otherJARURI) {
00698         // Nothing in common
00699         return NS_OK;
00700     }
00701 
00702     nsCOMPtr<nsIURI> otherJARFile;
00703     nsresult rv = otherJARURI->GetJARFile(getter_AddRefs(otherJARFile));
00704     if (NS_FAILED(rv)) return rv;
00705 
00706     PRBool equal;
00707     rv = mJARFile->Equals(otherJARFile, &equal);
00708     if (NS_FAILED(rv)) return rv;
00709 
00710     if (!equal) {
00711         // We live in different JAR files.  Nothing in common.
00712         return rv;
00713     }
00714 
00715     // Same JAR file.  Compare the JAREntrys
00716     nsCAutoString otherEntry;
00717     rv = otherJARURI->GetJAREntry(otherEntry);
00718     if (NS_FAILED(rv)) return rv;
00719 
00720     nsCAutoString otherCharset;
00721     rv = uriToCompare->GetOriginCharset(otherCharset);
00722     if (NS_FAILED(rv)) return rv;
00723 
00724     nsCOMPtr<nsIURL> url;
00725     rv = CreateEntryURL(otherEntry, otherCharset.get(), getter_AddRefs(url));
00726     if (NS_FAILED(rv)) return rv;
00727 
00728     nsCAutoString relativeEntrySpec;
00729     rv = mJAREntry->GetRelativeSpec(url, relativeEntrySpec);
00730     if (NS_FAILED(rv)) return rv;
00731 
00732     if (!StringBeginsWith(relativeEntrySpec, NS_BOGUS_ENTRY_SCHEME)) {
00733         // An actual relative spec!
00734         relativeSpec = relativeEntrySpec;
00735     }
00736     return rv;
00737 }
00738 
00740 // nsIJARURI methods:
00741 
00742 NS_IMETHODIMP
00743 nsJARURI::GetJARFile(nsIURI* *jarFile)
00744 {
00745     *jarFile = mJARFile;
00746     NS_ADDREF(*jarFile);
00747     return NS_OK;
00748 }
00749 
00750 NS_IMETHODIMP
00751 nsJARURI::SetJARFile(nsIURI* jarFile)
00752 {
00753     mJARFile = jarFile;
00754     return NS_OK;
00755 }
00756 
00757 NS_IMETHODIMP
00758 nsJARURI::GetJAREntry(nsACString &entryPath)
00759 {
00760     nsCAutoString filePath;
00761     mJAREntry->GetFilePath(filePath);
00762     NS_ASSERTION(filePath.Length() > 0, "path should never be empty!");
00763     // Trim off the leading '/'
00764     entryPath = Substring(filePath, 1, filePath.Length() - 1);
00765     return NS_OK;
00766 }
00767 
00768 NS_IMETHODIMP
00769 nsJARURI::SetJAREntry(const nsACString &entryPath)
00770 {
00771     return CreateEntryURL(entryPath, mCharsetHint.get(),
00772                           getter_AddRefs(mJAREntry));
00773 }
00774 
00775 NS_IMETHODIMP
00776 nsJARURI::CloneWithJARFile(nsIURI *jarFile, nsIJARURI **result)
00777 {
00778     if (!jarFile) {
00779         return NS_ERROR_INVALID_ARG;
00780     }
00781 
00782     nsresult rv;
00783 
00784     nsCOMPtr<nsIURI> newJARFile;
00785     rv = jarFile->Clone(getter_AddRefs(newJARFile));
00786     if (NS_FAILED(rv)) return rv;
00787 
00788     nsCOMPtr<nsIURI> newJAREntryURI;
00789     rv = mJAREntry->Clone(getter_AddRefs(newJAREntryURI));
00790     if (NS_FAILED(rv)) return rv;
00791 
00792     nsCOMPtr<nsIURL> newJAREntry(do_QueryInterface(newJAREntryURI));
00793     NS_ASSERTION(newJAREntry, "This had better QI to nsIURL!");
00794     
00795     nsJARURI* uri = new nsJARURI();
00796     if (uri) {
00797         NS_ADDREF(uri);
00798         uri->mJARFile = newJARFile;
00799         uri->mJAREntry = newJAREntry;
00800         *result = uri;
00801         rv = NS_OK;
00802     } else {
00803         rv = NS_ERROR_OUT_OF_MEMORY;
00804     }
00805 
00806     return rv;
00807 }
00808