1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2001
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsEmbedChromeRegistry.h"
40 #include "nsReadableUtils.h"
43 #include "nsIDirectoryService.h"
44 #include "nsAppDirectoryServiceDefs.h"
45 #include "nsIProperties.h"
46 #include "nsILocalFile.h"
49 #define CHROME_TYPE_CONTENT 0
50 #define CHROME_TYPE_LOCALE 1
51 #define CHROME_TYPE_SKIN 2
53 const char kChromePrefix
[] = "chrome://";
56 SplitURL(nsIURI
*aChromeURI
, nsCString
& aPackage
, nsCString
& aProvider
, nsCString
& aFile
,
57 PRBool
*aModified
= nsnull
)
59 // Splits a "chrome:" URL into its package, provider, and file parts.
60 // Here are the current portions of a
61 // chrome: url that make up the chrome-
63 // chrome://global/skin/foo?bar
64 // \------/ \----/\---/ \-----/
66 // | | | `-- RemainingPortion
72 // `-- Always "chrome://"
79 rv
= aChromeURI
->GetSpec(str
);
80 if (NS_FAILED(rv
)) return rv
;
82 // We only want to deal with "chrome:" URLs here. We could return
83 // an error code if the URL isn't properly prefixed here...
84 if (PL_strncmp(str
.get(), kChromePrefix
, sizeof(kChromePrefix
) - 1) != 0)
85 return NS_ERROR_INVALID_ARG
;
87 // Cull out the "package" string; e.g., "navigator"
88 aPackage
= str
.get() + sizeof(kChromePrefix
) - 1;
91 idx
= aPackage
.FindChar('/');
95 // Cull out the "provider" string; e.g., "content"
96 aPackage
.Right(aProvider
, aPackage
.Length() - (idx
+ 1));
97 aPackage
.Truncate(idx
);
99 idx
= aProvider
.FindChar('/');
101 // Force the provider to end with a '/'
102 idx
= aProvider
.Length();
103 aProvider
.Append('/');
106 // Cull out the "file"; e.g., "navigator.xul"
107 aProvider
.Right(aFile
, aProvider
.Length() - (idx
+ 1));
108 aProvider
.Truncate(idx
);
110 PRBool nofile
= aFile
.IsEmpty();
112 // If there is no file, then construct the default file
115 if (aProvider
.Equals("content")) {
118 else if (aProvider
.Equals("skin")) {
121 else if (aProvider
.Equals("locale")) {
125 NS_ERROR("unknown provider");
126 return NS_ERROR_FAILURE
;
129 // Protect against URIs containing .. that reach up out of the
130 // chrome directory to grant chrome privileges to non-chrome files.
132 PRBool sawSlash
= PR_TRUE
; // .. at the beginning is suspect as well as /..
133 for (const char* p
=aFile
.get(); *p
; p
++) {
135 if (p
[0] == '.' && p
[1] == '.'){
136 depth
--; // we have /.., decrement depth.
138 static const char escape
[] = "%2E%2E";
139 if (PL_strncasecmp(p
, escape
, sizeof(escape
)-1) == 0)
140 depth
--; // we have the HTML-escaped form of /.., decrement depth.
142 } else if (p
[0] != '/') {
143 depth
++; // we have /x for some x that is not /
145 sawSlash
= (p
[0] == '/');
148 return NS_ERROR_FAILURE
;
157 NS_IMPL_ISUPPORTS1(nsEmbedChromeRegistry
, nsIChromeRegistry
)
159 nsEmbedChromeRegistry::nsEmbedChromeRegistry()
164 nsEmbedChromeRegistry::Init()
166 NS_ASSERTION(0, "Creating embedding chrome registry\n");
169 rv
= NS_NewISupportsArray(getter_AddRefs(mEmptyArray
));
170 if (NS_FAILED(rv
)) return rv
;
172 rv
= ReadChromeRegistry();
173 if (NS_FAILED(rv
)) return rv
;
179 nsEmbedChromeRegistry::ReadChromeRegistry()
182 nsCOMPtr
<nsIProperties
> directoryService
=
183 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
, &rv
);
184 if (NS_FAILED(rv
)) return rv
;
186 nsCOMPtr
<nsILocalFile
> listFile
;
187 rv
= directoryService
->Get(NS_APP_CHROME_DIR
, NS_GET_IID(nsILocalFile
),
188 getter_AddRefs(listFile
));
189 if (NS_FAILED(rv
)) return rv
;
191 rv
= listFile
->AppendRelativeNativePath(NS_LITERAL_CSTRING("installed-chrome.txt"));
192 if (NS_FAILED(rv
)) return rv
;
195 rv
= listFile
->OpenNSPRFileDesc(PR_RDONLY
, 0, &file
);
196 if (NS_FAILED(rv
)) return rv
;
200 if (PR_GetOpenFileInfo(file
, &finfo
) == PR_SUCCESS
) {
201 char *dataBuffer
= new char[finfo
.size
+1];
203 PRInt32 bufferSize
= PR_Read(file
, dataBuffer
, finfo
.size
);
204 if (bufferSize
> 0) {
205 dataBuffer
[bufferSize
] = '\r';
206 rv
= ProcessNewChromeBuffer(dataBuffer
, bufferSize
);
208 delete [] dataBuffer
;
217 nsEmbedChromeRegistry::ProcessNewChromeBuffer(char* aBuffer
, PRInt32 aLength
)
219 while (aLength
> 0) {
220 PRInt32 processedBytes
= ProcessChromeLine(aBuffer
, aLength
);
221 aBuffer
+= processedBytes
;
222 aLength
-= processedBytes
;
229 const char *tokenStart
;
230 const char *tokenEnd
;
234 nsEmbedChromeRegistry::ProcessChromeLine(const char* aBuffer
, PRInt32 aLength
)
236 PRInt32 bytesProcessed
= 0;
237 chromeToken tokens
[MAX_TOKENS
];
238 PRInt32 tokenCount
= 0;
239 PRBool expectingToken
= PR_TRUE
;
241 while (bytesProcessed
<= aLength
&&
242 *aBuffer
!= '\n' && *aBuffer
!= '\r' &&
243 tokenCount
< MAX_TOKENS
) {
245 if (*aBuffer
== ',') {
247 expectingToken
= PR_TRUE
;
249 else if (expectingToken
)
250 tokens
[tokenCount
].tokenStart
= aBuffer
;
252 tokens
[tokenCount
].tokenEnd
= aBuffer
;
258 NS_ASSERTION(tokenCount
== 4, "Unexpected tokens in line");
260 nsDependentCSubstring
261 chromeType(tokens
[0].tokenStart
, tokens
[0].tokenEnd
);
262 nsDependentCSubstring
263 chromeProfile(tokens
[1].tokenStart
, tokens
[1].tokenEnd
);
264 nsDependentCSubstring
265 chromeLocType(tokens
[2].tokenStart
, tokens
[2].tokenEnd
);
266 nsDependentCSubstring
267 chromeLocation(tokens
[3].tokenStart
, tokens
[3].tokenEnd
);
269 RegisterChrome(chromeType
, chromeProfile
, chromeLocType
, chromeLocation
);
270 return bytesProcessed
;
274 nsEmbedChromeRegistry::RegisterChrome(const nsACString
& aChromeType
,
275 const nsACString
& aChromeProfile
,
276 const nsACString
& aChromeLocType
,
277 const nsACString
& aChromeLocation
)
280 if (aChromeType
.EqualsLiteral("skin"))
281 chromeType
= CHROME_TYPE_SKIN
;
282 else if (aChromeType
.EqualsLiteral("locale"))
283 chromeType
= CHROME_TYPE_LOCALE
;
285 chromeType
= CHROME_TYPE_CONTENT
;
287 PRBool chromeIsProfile
=
288 aChromeProfile
.EqualsLiteral("profile");
291 aChromeProfile
.EqualsLiteral("url");
293 return RegisterChrome(chromeType
, chromeIsProfile
, chromeIsURL
,
298 nsEmbedChromeRegistry::RegisterChrome(PRInt32 aChromeType
, // CHROME_TYPE_CONTENT, etc
299 PRBool aChromeIsProfile
, // per-profile?
300 PRBool aChromeIsURL
, // is it a url? (else path)
301 const nsACString
& aChromeLocation
)
309 nsEmbedChromeRegistry::CheckForNewChrome()
315 nsEmbedChromeRegistry::Canonify(nsIURI
* aChromeURI
)
318 // Canonicalize 'chrome:' URLs. We'll take any 'chrome:' URL
319 // without a filename, and change it to a URL -with- a filename;
320 // e.g., "chrome://navigator/content" to
321 // "chrome://navigator/content/navigator.xul".
323 return NS_ERROR_NULL_POINTER
;
325 PRBool modified
= PR_TRUE
; // default is we do canonification
326 nsCAutoString package
, provider
, file
;
328 rv
= SplitURL(aChromeURI
, package
, provider
, file
, &modified
);
335 nsCAutoString
canonical( kChromePrefix
);
336 canonical
+= package
;
338 canonical
+= provider
;
342 return aChromeURI
->SetSpec(canonical
);
349 nsEmbedChromeRegistry::ConvertChromeURL(nsIURI
* aChromeURL
, nsACString
& aResult
)
353 rv
= aChromeURL
->GetSpec(aResult
);
354 if (NS_FAILED(rv
)) return rv
;