diff --git a/intl/uconv/idl/nsITextToSubURI.idl b/intl/uconv/idl/nsITextToSubURI.idl index 0a81b25a086..7fe68be3f2e 100644 --- a/intl/uconv/idl/nsITextToSubURI.idl +++ b/intl/uconv/idl/nsITextToSubURI.idl @@ -50,4 +50,17 @@ interface nsITextToSubURI : nsISupports { string ConvertAndEscape(in string charset, in wstring text); wstring UnEscapeAndConvert(in string charset, in string text); + + /** + * Unescapes the given URI fragment (for UI purpose only) + * note: escaping back the result unescaped string is not guaranteed to be + * identical to the original escaped string + * + * @param aCharset the charset to convert from + * @param aURIFragment the URI (or URI fragment) to unescape + * @return Unescaped aURIFragment converted to unicode + * @throws NS_ERROR_UCONV_NOCONV when there is no decoder for aCharset + * or error code of nsIUnicodeDecoder in case of covnersion failure + */ + AString unEscapeURIForUI(in ACString aCharset, in AUTF8String aURIFragment); }; diff --git a/intl/uconv/src/nsTextToSubURI.cpp b/intl/uconv/src/nsTextToSubURI.cpp index ae0b4466da0..87116840429 100644 --- a/intl/uconv/src/nsTextToSubURI.cpp +++ b/intl/uconv/src/nsTextToSubURI.cpp @@ -39,6 +39,8 @@ #include "nsString.h" #include "nsIUnicodeEncoder.h" #include "nsICharsetConverterManager.h" +#include "nsICharsetConverterManager2.h" +#include "nsReadableUtils.h" #include "nsITextToSubURI.h" #include "nsIServiceManager.h" #include "nsUConvDll.h" @@ -157,4 +159,66 @@ NS_IMETHODIMP nsTextToSubURI::UnEscapeAndConvert( return rv; } +nsresult nsTextToSubURI::convertURItoUnicode(const nsAFlatCString &aCharset, + const nsAFlatCString &aURI, + PRBool aIRI, + nsAString &_retval) +{ + nsresult rv = NS_OK; + + if (IsASCII(aURI)) { + _retval.Assign(NS_ConvertASCIItoUCS2(aURI)); + return rv; + } + + if (aIRI) { + NS_ConvertUTF8toUCS2 ucs2(aURI); + if (aURI.Equals(NS_ConvertUCS2toUTF8(ucs2))) { + _retval.Assign(ucs2); + return rv; + } + } + + nsCOMPtr charsetConverterManager; + + charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr charsetAtom; + rv = charsetConverterManager->GetCharsetAtom2(aCharset.get(), getter_AddRefs(charsetAtom)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr unicodeDecoder; + rv = charsetConverterManager->GetUnicodeDecoder(charsetAtom, + getter_AddRefs(unicodeDecoder)); + NS_ENSURE_SUCCESS(rv, rv); + + PRInt32 srcLen = aURI.Length(); + PRInt32 dstLen; + rv = unicodeDecoder->GetMaxLength(aURI.get(), srcLen, &dstLen); + NS_ENSURE_SUCCESS(rv, rv); + + PRUnichar *ustr = (PRUnichar *) nsMemory::Alloc(dstLen * sizeof(PRUnichar)); + NS_ENSURE_TRUE(ustr, NS_ERROR_OUT_OF_MEMORY); + + rv = unicodeDecoder->Convert(aURI.get(), &srcLen, ustr, &dstLen); + + if (NS_SUCCEEDED(rv)) + _retval.Assign(ustr, dstLen); + + nsMemory::Free(ustr); + + return rv; +} + +NS_IMETHODIMP nsTextToSubURI::UnEscapeURIForUI(const nsACString & aCharset, + const nsACString &aURIFragment, + nsAString &_retval) +{ + nsCAutoString unescapedSpec(aURIFragment); + NS_UnescapeURL(unescapedSpec); + + return convertURItoUnicode(PromiseFlatCString(aCharset), unescapedSpec, PR_TRUE, _retval); +} + //---------------------------------------------------------------------- diff --git a/intl/uconv/src/nsTextToSubURI.h b/intl/uconv/src/nsTextToSubURI.h index 7472cd578bd..5d62a473150 100644 --- a/intl/uconv/src/nsTextToSubURI.h +++ b/intl/uconv/src/nsTextToSubURI.h @@ -48,6 +48,21 @@ class nsTextToSubURI: public nsITextToSubURI { public: nsTextToSubURI(); virtual ~nsTextToSubURI(); + +private: + // IRI is "Internationalized Resource Identifiers" + // http://www.ietf.org/internet-drafts/draft-duerst-iri-01.txt + // + // if the IRI option is true then we assume that the URI is encoded as UTF-8 + // note: there is no definite way to distinguish between IRI and a URI encoded + // with a non-UTF-8 charset + // Use this option carefully -- it may cause dataloss + // (recommended to set to true for UI purpose only) + // + nsresult convertURItoUnicode(const nsAFlatCString &aCharset, + const nsAFlatCString &aURI, + PRBool aIRI, + nsAString &_retval); }; #endif // nsTextToSubURI_h__ diff --git a/uriloader/build/Makefile.in b/uriloader/build/Makefile.in index ad80e6bb2d5..43e70cc2579 100644 --- a/uriloader/build/Makefile.in +++ b/uriloader/build/Makefile.in @@ -40,6 +40,7 @@ REQUIRES = xpcom \ rdf \ helperAppDlg \ dom \ + uconv \ $(NULL) CPPSRCS = nsURILoaderModule.cpp diff --git a/uriloader/exthandler/Makefile.in b/uriloader/exthandler/Makefile.in index 3035ed6cac0..ad53437710d 100644 --- a/uriloader/exthandler/Makefile.in +++ b/uriloader/exthandler/Makefile.in @@ -52,6 +52,7 @@ REQUIRES = xpcom \ plugin \ pref \ intl \ + uconv \ windowwatcher \ $(NULL) diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index bda5a31dc48..868906805e7 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -80,6 +80,8 @@ #include "nsIPromptService.h" #include "nsIDOMWindow.h" +#include "nsITextToSubURI.h" + const char *FORCE_ALWAYS_ASK_PREF = "browser.helperApps.alwaysAsk.force"; static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); @@ -1046,8 +1048,21 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel) url->GetFileName(leafName); if (!leafName.IsEmpty()) { - NS_UnescapeURL(leafName); - mSuggestedFileName = NS_ConvertUTF8toUCS2(leafName); // XXX leafName may not be UTF-8 + + nsCOMPtr textToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) + { + nsCAutoString originCharset; + url->GetOriginCharset(originCharset); + rv = textToSubURI->UnEscapeURIForUI(originCharset, leafName, + mSuggestedFileName); + } + + if (NS_FAILED(rv)) + { + mSuggestedFileName = NS_ConvertUTF8toUCS2(leafName); // use escaped name + rv = NS_OK; + } #ifdef XP_WIN // Make sure extension is still correct.