Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/basictypes.h"
9 #include "nsJARURI.h"
10 #include "nsNetUtil.h"
11 #include "nsIIOService.h"
12 #include "nsIStandardURL.h"
13 #include "nsCRT.h"
14 #include "nsIComponentManager.h"
15 #include "nsIServiceManager.h"
16 #include "nsIZipReader.h"
17 #include "nsReadableUtils.h"
18 #include "nsAutoPtr.h"
19 #include "nsNetCID.h"
20 #include "nsIObjectInputStream.h"
21 #include "nsIObjectOutputStream.h"
22 #include "nsIProgrammingLanguage.h"
23 #include "mozilla/ipc/URIUtils.h"
25 using namespace mozilla::ipc;
27 static NS_DEFINE_CID(kJARURICID, NS_JARURI_CID);
29 ////////////////////////////////////////////////////////////////////////////////
31 nsJARURI::nsJARURI()
32 {
33 }
35 nsJARURI::~nsJARURI()
36 {
37 }
39 // XXX Why is this threadsafe?
40 NS_IMPL_ADDREF(nsJARURI)
41 NS_IMPL_RELEASE(nsJARURI)
42 NS_INTERFACE_MAP_BEGIN(nsJARURI)
43 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJARURI)
44 NS_INTERFACE_MAP_ENTRY(nsIURI)
45 NS_INTERFACE_MAP_ENTRY(nsIURL)
46 NS_INTERFACE_MAP_ENTRY(nsIJARURI)
47 NS_INTERFACE_MAP_ENTRY(nsISerializable)
48 NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
49 NS_INTERFACE_MAP_ENTRY(nsINestedURI)
50 NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableURI)
51 // see nsJARURI::Equals
52 if (aIID.Equals(NS_GET_IID(nsJARURI)))
53 foundInterface = reinterpret_cast<nsISupports*>(this);
54 else
55 NS_INTERFACE_MAP_END
57 nsresult
58 nsJARURI::Init(const char *charsetHint)
59 {
60 mCharsetHint = charsetHint;
61 return NS_OK;
62 }
64 #define NS_JAR_SCHEME NS_LITERAL_CSTRING("jar:")
65 #define NS_JAR_DELIMITER NS_LITERAL_CSTRING("!/")
66 #define NS_BOGUS_ENTRY_SCHEME NS_LITERAL_CSTRING("x:///")
68 // FormatSpec takes the entry spec (including the "x:///" at the
69 // beginning) and gives us a full JAR spec.
70 nsresult
71 nsJARURI::FormatSpec(const nsACString &entrySpec, nsACString &result,
72 bool aIncludeScheme)
73 {
74 // The entrySpec MUST start with "x:///"
75 NS_ASSERTION(StringBeginsWith(entrySpec, NS_BOGUS_ENTRY_SCHEME),
76 "bogus entry spec");
78 nsAutoCString fileSpec;
79 nsresult rv = mJARFile->GetSpec(fileSpec);
80 if (NS_FAILED(rv)) return rv;
82 if (aIncludeScheme)
83 result = NS_JAR_SCHEME;
84 else
85 result.Truncate();
87 result.Append(fileSpec + NS_JAR_DELIMITER +
88 Substring(entrySpec, 5, entrySpec.Length() - 5));
89 return NS_OK;
90 }
92 nsresult
93 nsJARURI::CreateEntryURL(const nsACString& entryFilename,
94 const char* charset,
95 nsIURL** url)
96 {
97 *url = nullptr;
99 nsCOMPtr<nsIStandardURL> stdURL(do_CreateInstance(NS_STANDARDURL_CONTRACTID));
100 if (!stdURL) {
101 return NS_ERROR_OUT_OF_MEMORY;
102 }
104 // Flatten the concatenation, just in case. See bug 128288
105 nsAutoCString spec(NS_BOGUS_ENTRY_SCHEME + entryFilename);
106 nsresult rv = stdURL->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
107 spec, charset, nullptr);
108 if (NS_FAILED(rv)) {
109 return rv;
110 }
112 return CallQueryInterface(stdURL, url);
113 }
115 ////////////////////////////////////////////////////////////////////////////////
116 // nsISerializable methods:
118 NS_IMETHODIMP
119 nsJARURI::Read(nsIObjectInputStream* aInputStream)
120 {
121 nsresult rv;
123 nsCOMPtr<nsISupports> supports;
124 rv = aInputStream->ReadObject(true, getter_AddRefs(supports));
125 NS_ENSURE_SUCCESS(rv, rv);
127 mJARFile = do_QueryInterface(supports, &rv);
128 NS_ENSURE_SUCCESS(rv, rv);
130 rv = aInputStream->ReadObject(true, getter_AddRefs(supports));
131 NS_ENSURE_SUCCESS(rv, rv);
133 mJAREntry = do_QueryInterface(supports);
134 NS_ENSURE_SUCCESS(rv, rv);
136 rv = aInputStream->ReadCString(mCharsetHint);
137 return rv;
138 }
140 NS_IMETHODIMP
141 nsJARURI::Write(nsIObjectOutputStream* aOutputStream)
142 {
143 nsresult rv;
145 rv = aOutputStream->WriteCompoundObject(mJARFile, NS_GET_IID(nsIURI),
146 true);
147 NS_ENSURE_SUCCESS(rv, rv);
149 rv = aOutputStream->WriteCompoundObject(mJAREntry, NS_GET_IID(nsIURL),
150 true);
151 NS_ENSURE_SUCCESS(rv, rv);
153 rv = aOutputStream->WriteStringZ(mCharsetHint.get());
154 return rv;
155 }
157 ////////////////////////////////////////////////////////////////////////////////
158 // nsIClassInfo methods:
160 NS_IMETHODIMP
161 nsJARURI::GetInterfaces(uint32_t *count, nsIID * **array)
162 {
163 *count = 0;
164 *array = nullptr;
165 return NS_OK;
166 }
168 NS_IMETHODIMP
169 nsJARURI::GetHelperForLanguage(uint32_t language, nsISupports **_retval)
170 {
171 *_retval = nullptr;
172 return NS_OK;
173 }
175 NS_IMETHODIMP
176 nsJARURI::GetContractID(char * *aContractID)
177 {
178 *aContractID = nullptr;
179 return NS_OK;
180 }
182 NS_IMETHODIMP
183 nsJARURI::GetClassDescription(char * *aClassDescription)
184 {
185 *aClassDescription = nullptr;
186 return NS_OK;
187 }
189 NS_IMETHODIMP
190 nsJARURI::GetClassID(nsCID * *aClassID)
191 {
192 *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
193 if (!*aClassID)
194 return NS_ERROR_OUT_OF_MEMORY;
195 return GetClassIDNoAlloc(*aClassID);
196 }
198 NS_IMETHODIMP
199 nsJARURI::GetImplementationLanguage(uint32_t *aImplementationLanguage)
200 {
201 *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
202 return NS_OK;
203 }
205 NS_IMETHODIMP
206 nsJARURI::GetFlags(uint32_t *aFlags)
207 {
208 // XXX We implement THREADSAFE addref/release, but probably shouldn't.
209 *aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
210 return NS_OK;
211 }
213 NS_IMETHODIMP
214 nsJARURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
215 {
216 *aClassIDNoAlloc = kJARURICID;
217 return NS_OK;
218 }
220 ////////////////////////////////////////////////////////////////////////////////
221 // nsIURI methods:
223 NS_IMETHODIMP
224 nsJARURI::GetSpec(nsACString &aSpec)
225 {
226 nsAutoCString entrySpec;
227 mJAREntry->GetSpec(entrySpec);
228 return FormatSpec(entrySpec, aSpec);
229 }
231 NS_IMETHODIMP
232 nsJARURI::GetSpecIgnoringRef(nsACString &aSpec)
233 {
234 nsAutoCString entrySpec;
235 mJAREntry->GetSpecIgnoringRef(entrySpec);
236 return FormatSpec(entrySpec, aSpec);
237 }
239 NS_IMETHODIMP
240 nsJARURI::GetHasRef(bool *result)
241 {
242 return mJAREntry->GetHasRef(result);
243 }
245 NS_IMETHODIMP
246 nsJARURI::SetSpec(const nsACString& aSpec)
247 {
248 return SetSpecWithBase(aSpec, nullptr);
249 }
251 nsresult
252 nsJARURI::SetSpecWithBase(const nsACString &aSpec, nsIURI* aBaseURL)
253 {
254 nsresult rv;
256 nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
257 NS_ENSURE_SUCCESS(rv, rv);
259 nsAutoCString scheme;
260 rv = ioServ->ExtractScheme(aSpec, scheme);
261 if (NS_FAILED(rv)) {
262 // not an absolute URI
263 if (!aBaseURL)
264 return NS_ERROR_MALFORMED_URI;
266 nsRefPtr<nsJARURI> otherJAR;
267 aBaseURL->QueryInterface(NS_GET_IID(nsJARURI), getter_AddRefs(otherJAR));
268 NS_ENSURE_TRUE(otherJAR, NS_NOINTERFACE);
270 mJARFile = otherJAR->mJARFile;
272 nsCOMPtr<nsIStandardURL> entry(do_CreateInstance(NS_STANDARDURL_CONTRACTID));
273 if (!entry)
274 return NS_ERROR_OUT_OF_MEMORY;
276 rv = entry->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
277 aSpec, mCharsetHint.get(), otherJAR->mJAREntry);
278 if (NS_FAILED(rv))
279 return rv;
281 mJAREntry = do_QueryInterface(entry);
282 if (!mJAREntry)
283 return NS_NOINTERFACE;
285 return NS_OK;
286 }
288 NS_ENSURE_TRUE(scheme.EqualsLiteral("jar"), NS_ERROR_MALFORMED_URI);
290 nsACString::const_iterator begin, end;
291 aSpec.BeginReading(begin);
292 aSpec.EndReading(end);
294 while (begin != end && *begin != ':')
295 ++begin;
297 ++begin; // now we're past the "jar:"
299 // Search backward from the end for the "!/" delimiter. Remember, jar URLs
300 // can nest, e.g.:
301 // jar:jar:http://www.foo.com/bar.jar!/a.jar!/b.html
302 // This gets the b.html document from out of the a.jar file, that's
303 // contained within the bar.jar file.
304 // Also, the outermost "inner" URI may be a relative URI:
305 // jar:../relative.jar!/a.html
307 nsACString::const_iterator delim_begin (begin),
308 delim_end (end);
310 if (!RFindInReadable(NS_JAR_DELIMITER, delim_begin, delim_end))
311 return NS_ERROR_MALFORMED_URI;
313 rv = ioServ->NewURI(Substring(begin, delim_begin), mCharsetHint.get(),
314 aBaseURL, getter_AddRefs(mJARFile));
315 if (NS_FAILED(rv)) return rv;
317 NS_TryToSetImmutable(mJARFile);
319 // skip over any extra '/' chars
320 while (*delim_end == '/')
321 ++delim_end;
323 return SetJAREntry(Substring(delim_end, end));
324 }
326 NS_IMETHODIMP
327 nsJARURI::GetPrePath(nsACString &prePath)
328 {
329 prePath = NS_JAR_SCHEME;
330 return NS_OK;
331 }
333 NS_IMETHODIMP
334 nsJARURI::GetScheme(nsACString &aScheme)
335 {
336 aScheme = "jar";
337 return NS_OK;
338 }
340 NS_IMETHODIMP
341 nsJARURI::SetScheme(const nsACString &aScheme)
342 {
343 // doesn't make sense to set the scheme of a jar: URL
344 return NS_ERROR_FAILURE;
345 }
347 NS_IMETHODIMP
348 nsJARURI::GetUserPass(nsACString &aUserPass)
349 {
350 return NS_ERROR_FAILURE;
351 }
353 NS_IMETHODIMP
354 nsJARURI::SetUserPass(const nsACString &aUserPass)
355 {
356 return NS_ERROR_FAILURE;
357 }
359 NS_IMETHODIMP
360 nsJARURI::GetUsername(nsACString &aUsername)
361 {
362 return NS_ERROR_FAILURE;
363 }
365 NS_IMETHODIMP
366 nsJARURI::SetUsername(const nsACString &aUsername)
367 {
368 return NS_ERROR_FAILURE;
369 }
371 NS_IMETHODIMP
372 nsJARURI::GetPassword(nsACString &aPassword)
373 {
374 return NS_ERROR_FAILURE;
375 }
377 NS_IMETHODIMP
378 nsJARURI::SetPassword(const nsACString &aPassword)
379 {
380 return NS_ERROR_FAILURE;
381 }
383 NS_IMETHODIMP
384 nsJARURI::GetHostPort(nsACString &aHostPort)
385 {
386 return NS_ERROR_FAILURE;
387 }
389 NS_IMETHODIMP
390 nsJARURI::SetHostPort(const nsACString &aHostPort)
391 {
392 return NS_ERROR_FAILURE;
393 }
395 NS_IMETHODIMP
396 nsJARURI::GetHost(nsACString &aHost)
397 {
398 return NS_ERROR_FAILURE;
399 }
401 NS_IMETHODIMP
402 nsJARURI::SetHost(const nsACString &aHost)
403 {
404 return NS_ERROR_FAILURE;
405 }
407 NS_IMETHODIMP
408 nsJARURI::GetPort(int32_t *aPort)
409 {
410 return NS_ERROR_FAILURE;
411 }
413 NS_IMETHODIMP
414 nsJARURI::SetPort(int32_t aPort)
415 {
416 return NS_ERROR_FAILURE;
417 }
419 NS_IMETHODIMP
420 nsJARURI::GetPath(nsACString &aPath)
421 {
422 nsAutoCString entrySpec;
423 mJAREntry->GetSpec(entrySpec);
424 return FormatSpec(entrySpec, aPath, false);
425 }
427 NS_IMETHODIMP
428 nsJARURI::SetPath(const nsACString &aPath)
429 {
430 return NS_ERROR_FAILURE;
431 }
433 NS_IMETHODIMP
434 nsJARURI::GetAsciiSpec(nsACString &aSpec)
435 {
436 // XXX Shouldn't this like... make sure it returns ASCII or something?
437 return GetSpec(aSpec);
438 }
440 NS_IMETHODIMP
441 nsJARURI::GetAsciiHost(nsACString &aHost)
442 {
443 return NS_ERROR_FAILURE;
444 }
446 NS_IMETHODIMP
447 nsJARURI::GetOriginCharset(nsACString &aOriginCharset)
448 {
449 aOriginCharset = mCharsetHint;
450 return NS_OK;
451 }
453 NS_IMETHODIMP
454 nsJARURI::Equals(nsIURI *other, bool *result)
455 {
456 return EqualsInternal(other, eHonorRef, result);
457 }
459 NS_IMETHODIMP
460 nsJARURI::EqualsExceptRef(nsIURI *other, bool *result)
461 {
462 return EqualsInternal(other, eIgnoreRef, result);
463 }
465 // Helper method:
466 /* virtual */ nsresult
467 nsJARURI::EqualsInternal(nsIURI *other,
468 nsJARURI::RefHandlingEnum refHandlingMode,
469 bool *result)
470 {
471 *result = false;
473 if (!other)
474 return NS_OK; // not equal
476 nsRefPtr<nsJARURI> otherJAR;
477 other->QueryInterface(NS_GET_IID(nsJARURI), getter_AddRefs(otherJAR));
478 if (!otherJAR)
479 return NS_OK; // not equal
481 bool equal;
482 nsresult rv = mJARFile->Equals(otherJAR->mJARFile, &equal);
483 if (NS_FAILED(rv) || !equal) {
484 return rv; // not equal
485 }
487 return refHandlingMode == eHonorRef ?
488 mJAREntry->Equals(otherJAR->mJAREntry, result) :
489 mJAREntry->EqualsExceptRef(otherJAR->mJAREntry, result);
490 }
492 NS_IMETHODIMP
493 nsJARURI::SchemeIs(const char *i_Scheme, bool *o_Equals)
494 {
495 NS_ENSURE_ARG_POINTER(o_Equals);
496 if (!i_Scheme) return NS_ERROR_INVALID_ARG;
498 if (*i_Scheme == 'j' || *i_Scheme == 'J') {
499 *o_Equals = PL_strcasecmp("jar", i_Scheme) ? false : true;
500 } else {
501 *o_Equals = false;
502 }
503 return NS_OK;
504 }
506 NS_IMETHODIMP
507 nsJARURI::Clone(nsIURI **result)
508 {
509 nsresult rv;
511 nsCOMPtr<nsIJARURI> uri;
512 rv = CloneWithJARFileInternal(mJARFile, eHonorRef, getter_AddRefs(uri));
513 if (NS_FAILED(rv)) return rv;
515 return CallQueryInterface(uri, result);
516 }
518 NS_IMETHODIMP
519 nsJARURI::CloneIgnoringRef(nsIURI **result)
520 {
521 nsresult rv;
523 nsCOMPtr<nsIJARURI> uri;
524 rv = CloneWithJARFileInternal(mJARFile, eIgnoreRef, getter_AddRefs(uri));
525 if (NS_FAILED(rv)) return rv;
527 return CallQueryInterface(uri, result);
528 }
530 NS_IMETHODIMP
531 nsJARURI::Resolve(const nsACString &relativePath, nsACString &result)
532 {
533 nsresult rv;
535 nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
536 if (NS_FAILED(rv))
537 return rv;
539 nsAutoCString scheme;
540 rv = ioServ->ExtractScheme(relativePath, scheme);
541 if (NS_SUCCEEDED(rv)) {
542 // then aSpec is absolute
543 result = relativePath;
544 return NS_OK;
545 }
547 nsAutoCString resolvedPath;
548 mJAREntry->Resolve(relativePath, resolvedPath);
550 return FormatSpec(resolvedPath, result);
551 }
553 ////////////////////////////////////////////////////////////////////////////////
554 // nsIURL methods:
556 NS_IMETHODIMP
557 nsJARURI::GetFilePath(nsACString& filePath)
558 {
559 return mJAREntry->GetFilePath(filePath);
560 }
562 NS_IMETHODIMP
563 nsJARURI::SetFilePath(const nsACString& filePath)
564 {
565 return mJAREntry->SetFilePath(filePath);
566 }
568 NS_IMETHODIMP
569 nsJARURI::GetQuery(nsACString& query)
570 {
571 return mJAREntry->GetQuery(query);
572 }
574 NS_IMETHODIMP
575 nsJARURI::SetQuery(const nsACString& query)
576 {
577 return mJAREntry->SetQuery(query);
578 }
580 NS_IMETHODIMP
581 nsJARURI::GetRef(nsACString& ref)
582 {
583 return mJAREntry->GetRef(ref);
584 }
586 NS_IMETHODIMP
587 nsJARURI::SetRef(const nsACString& ref)
588 {
589 return mJAREntry->SetRef(ref);
590 }
592 NS_IMETHODIMP
593 nsJARURI::GetDirectory(nsACString& directory)
594 {
595 return mJAREntry->GetDirectory(directory);
596 }
598 NS_IMETHODIMP
599 nsJARURI::SetDirectory(const nsACString& directory)
600 {
601 return mJAREntry->SetDirectory(directory);
602 }
604 NS_IMETHODIMP
605 nsJARURI::GetFileName(nsACString& fileName)
606 {
607 return mJAREntry->GetFileName(fileName);
608 }
610 NS_IMETHODIMP
611 nsJARURI::SetFileName(const nsACString& fileName)
612 {
613 return mJAREntry->SetFileName(fileName);
614 }
616 NS_IMETHODIMP
617 nsJARURI::GetFileBaseName(nsACString& fileBaseName)
618 {
619 return mJAREntry->GetFileBaseName(fileBaseName);
620 }
622 NS_IMETHODIMP
623 nsJARURI::SetFileBaseName(const nsACString& fileBaseName)
624 {
625 return mJAREntry->SetFileBaseName(fileBaseName);
626 }
628 NS_IMETHODIMP
629 nsJARURI::GetFileExtension(nsACString& fileExtension)
630 {
631 return mJAREntry->GetFileExtension(fileExtension);
632 }
634 NS_IMETHODIMP
635 nsJARURI::SetFileExtension(const nsACString& fileExtension)
636 {
637 return mJAREntry->SetFileExtension(fileExtension);
638 }
640 NS_IMETHODIMP
641 nsJARURI::GetCommonBaseSpec(nsIURI* uriToCompare, nsACString& commonSpec)
642 {
643 commonSpec.Truncate();
645 NS_ENSURE_ARG_POINTER(uriToCompare);
647 commonSpec.Truncate();
648 nsCOMPtr<nsIJARURI> otherJARURI(do_QueryInterface(uriToCompare));
649 if (!otherJARURI) {
650 // Nothing in common
651 return NS_OK;
652 }
654 nsCOMPtr<nsIURI> otherJARFile;
655 nsresult rv = otherJARURI->GetJARFile(getter_AddRefs(otherJARFile));
656 if (NS_FAILED(rv)) return rv;
658 bool equal;
659 rv = mJARFile->Equals(otherJARFile, &equal);
660 if (NS_FAILED(rv)) return rv;
662 if (!equal) {
663 // See what the JAR file URIs have in common
664 nsCOMPtr<nsIURL> ourJARFileURL(do_QueryInterface(mJARFile));
665 if (!ourJARFileURL) {
666 // Not a URL, so nothing in common
667 return NS_OK;
668 }
669 nsAutoCString common;
670 rv = ourJARFileURL->GetCommonBaseSpec(otherJARFile, common);
671 if (NS_FAILED(rv)) return rv;
673 commonSpec = NS_JAR_SCHEME + common;
674 return NS_OK;
676 }
678 // At this point we have the same JAR file. Compare the JAREntrys
679 nsAutoCString otherEntry;
680 rv = otherJARURI->GetJAREntry(otherEntry);
681 if (NS_FAILED(rv)) return rv;
683 nsAutoCString otherCharset;
684 rv = uriToCompare->GetOriginCharset(otherCharset);
685 if (NS_FAILED(rv)) return rv;
687 nsCOMPtr<nsIURL> url;
688 rv = CreateEntryURL(otherEntry, otherCharset.get(), getter_AddRefs(url));
689 if (NS_FAILED(rv)) return rv;
691 nsAutoCString common;
692 rv = mJAREntry->GetCommonBaseSpec(url, common);
693 if (NS_FAILED(rv)) return rv;
695 rv = FormatSpec(common, commonSpec);
696 return rv;
697 }
699 NS_IMETHODIMP
700 nsJARURI::GetRelativeSpec(nsIURI* uriToCompare, nsACString& relativeSpec)
701 {
702 GetSpec(relativeSpec);
704 NS_ENSURE_ARG_POINTER(uriToCompare);
706 nsCOMPtr<nsIJARURI> otherJARURI(do_QueryInterface(uriToCompare));
707 if (!otherJARURI) {
708 // Nothing in common
709 return NS_OK;
710 }
712 nsCOMPtr<nsIURI> otherJARFile;
713 nsresult rv = otherJARURI->GetJARFile(getter_AddRefs(otherJARFile));
714 if (NS_FAILED(rv)) return rv;
716 bool equal;
717 rv = mJARFile->Equals(otherJARFile, &equal);
718 if (NS_FAILED(rv)) return rv;
720 if (!equal) {
721 // We live in different JAR files. Nothing in common.
722 return rv;
723 }
725 // Same JAR file. Compare the JAREntrys
726 nsAutoCString otherEntry;
727 rv = otherJARURI->GetJAREntry(otherEntry);
728 if (NS_FAILED(rv)) return rv;
730 nsAutoCString otherCharset;
731 rv = uriToCompare->GetOriginCharset(otherCharset);
732 if (NS_FAILED(rv)) return rv;
734 nsCOMPtr<nsIURL> url;
735 rv = CreateEntryURL(otherEntry, otherCharset.get(), getter_AddRefs(url));
736 if (NS_FAILED(rv)) return rv;
738 nsAutoCString relativeEntrySpec;
739 rv = mJAREntry->GetRelativeSpec(url, relativeEntrySpec);
740 if (NS_FAILED(rv)) return rv;
742 if (!StringBeginsWith(relativeEntrySpec, NS_BOGUS_ENTRY_SCHEME)) {
743 // An actual relative spec!
744 relativeSpec = relativeEntrySpec;
745 }
746 return rv;
747 }
749 ////////////////////////////////////////////////////////////////////////////////
750 // nsIJARURI methods:
752 NS_IMETHODIMP
753 nsJARURI::GetJARFile(nsIURI* *jarFile)
754 {
755 return GetInnerURI(jarFile);
756 }
758 NS_IMETHODIMP
759 nsJARURI::GetJAREntry(nsACString &entryPath)
760 {
761 nsAutoCString filePath;
762 mJAREntry->GetFilePath(filePath);
763 NS_ASSERTION(filePath.Length() > 0, "path should never be empty!");
764 // Trim off the leading '/'
765 entryPath = Substring(filePath, 1, filePath.Length() - 1);
766 return NS_OK;
767 }
769 NS_IMETHODIMP
770 nsJARURI::SetJAREntry(const nsACString &entryPath)
771 {
772 return CreateEntryURL(entryPath, mCharsetHint.get(),
773 getter_AddRefs(mJAREntry));
774 }
776 NS_IMETHODIMP
777 nsJARURI::CloneWithJARFile(nsIURI *jarFile, nsIJARURI **result)
778 {
779 return CloneWithJARFileInternal(jarFile, eHonorRef, result);
780 }
782 nsresult
783 nsJARURI::CloneWithJARFileInternal(nsIURI *jarFile,
784 nsJARURI::RefHandlingEnum refHandlingMode,
785 nsIJARURI **result)
786 {
787 if (!jarFile) {
788 return NS_ERROR_INVALID_ARG;
789 }
791 nsresult rv;
793 nsCOMPtr<nsIURI> newJARFile;
794 rv = jarFile->Clone(getter_AddRefs(newJARFile));
795 if (NS_FAILED(rv)) return rv;
797 NS_TryToSetImmutable(newJARFile);
799 nsCOMPtr<nsIURI> newJAREntryURI;
800 rv = refHandlingMode == eHonorRef ?
801 mJAREntry->Clone(getter_AddRefs(newJAREntryURI)) :
802 mJAREntry->CloneIgnoringRef(getter_AddRefs(newJAREntryURI));
804 if (NS_FAILED(rv)) return rv;
806 nsCOMPtr<nsIURL> newJAREntry(do_QueryInterface(newJAREntryURI));
807 NS_ASSERTION(newJAREntry, "This had better QI to nsIURL!");
809 nsJARURI* uri = new nsJARURI();
810 NS_ADDREF(uri);
811 uri->mJARFile = newJARFile;
812 uri->mJAREntry = newJAREntry;
813 *result = uri;
815 return NS_OK;
816 }
818 ////////////////////////////////////////////////////////////////////////////////
820 NS_IMETHODIMP
821 nsJARURI::GetInnerURI(nsIURI **uri)
822 {
823 return NS_EnsureSafeToReturn(mJARFile, uri);
824 }
826 NS_IMETHODIMP
827 nsJARURI::GetInnermostURI(nsIURI** uri)
828 {
829 return NS_ImplGetInnermostURI(this, uri);
830 }
832 ////////////////////////////////////////////////////////////////////////////////
833 // nsIIPCSerializableURI methods:
835 void
836 nsJARURI::Serialize(URIParams& aParams)
837 {
838 JARURIParams params;
840 SerializeURI(mJARFile, params.jarFile());
841 SerializeURI(mJAREntry, params.jarEntry());
842 params.charset() = mCharsetHint;
844 aParams = params;
845 }
847 bool
848 nsJARURI::Deserialize(const URIParams& aParams)
849 {
850 if (aParams.type() != URIParams::TJARURIParams) {
851 NS_ERROR("Received unknown parameters from the other process!");
852 return false;
853 }
855 const JARURIParams& params = aParams.get_JARURIParams();
857 nsCOMPtr<nsIURI> file = DeserializeURI(params.jarFile());
858 if (!file) {
859 NS_ERROR("Couldn't deserialize jar file URI!");
860 return false;
861 }
863 nsCOMPtr<nsIURI> entry = DeserializeURI(params.jarEntry());
864 if (!entry) {
865 NS_ERROR("Couldn't deserialize jar entry URI!");
866 return false;
867 }
869 nsCOMPtr<nsIURL> entryURL = do_QueryInterface(entry);
870 if (!entryURL) {
871 NS_ERROR("Couldn't QI jar entry URI to nsIURL!");
872 return false;
873 }
875 mJARFile.swap(file);
876 mJAREntry.swap(entryURL);
877 mCharsetHint = params.charset();
879 return true;
880 }