Bug 445991, followup fix for milestone
[mozilla-1.9.git] / embedding / lite / nsEmbedChromeRegistry.cpp
blob5efbaad052f97c48256089e7e877875d6321e49f
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
13 * License.
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.
22 * Contributor(s):
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"
39 #include "nsString.h"
40 #include "nsReadableUtils.h"
41 #include "plstr.h"
43 #include "nsIDirectoryService.h"
44 #include "nsAppDirectoryServiceDefs.h"
45 #include "nsIProperties.h"
46 #include "nsILocalFile.h"
47 #include "nsIURI.h"
49 #define CHROME_TYPE_CONTENT 0
50 #define CHROME_TYPE_LOCALE 1
51 #define CHROME_TYPE_SKIN 2
53 const char kChromePrefix[] = "chrome://";
55 static nsresult
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 // \------/ \----/\---/ \-----/
65 // | | | |
66 // | | | `-- RemainingPortion
67 // | | |
68 // | | `-- Provider
69 // | |
70 // | `-- Package
71 // |
72 // `-- Always "chrome://"
76 nsresult rv;
78 nsCAutoString str;
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;
90 PRInt32 idx;
91 idx = aPackage.FindChar('/');
92 if (idx < 0)
93 return NS_OK;
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('/');
100 if (idx < 0) {
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();
111 if (nofile) {
112 // If there is no file, then construct the default file
113 aFile = aPackage;
115 if (aProvider.Equals("content")) {
116 aFile += ".xul";
118 else if (aProvider.Equals("skin")) {
119 aFile += ".css";
121 else if (aProvider.Equals("locale")) {
122 aFile += ".dtd";
124 else {
125 NS_ERROR("unknown provider");
126 return NS_ERROR_FAILURE;
128 } else {
129 // Protect against URIs containing .. that reach up out of the
130 // chrome directory to grant chrome privileges to non-chrome files.
131 int depth = 0;
132 PRBool sawSlash = PR_TRUE; // .. at the beginning is suspect as well as /..
133 for (const char* p=aFile.get(); *p; p++) {
134 if (sawSlash) {
135 if (p[0] == '.' && p[1] == '.'){
136 depth--; // we have /.., decrement depth.
137 } else {
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] == '/');
147 if (depth < 0) {
148 return NS_ERROR_FAILURE;
152 if (aModified)
153 *aModified = nofile;
154 return NS_OK;
157 NS_IMPL_ISUPPORTS1(nsEmbedChromeRegistry, nsIChromeRegistry)
159 nsEmbedChromeRegistry::nsEmbedChromeRegistry()
163 nsresult
164 nsEmbedChromeRegistry::Init()
166 NS_ASSERTION(0, "Creating embedding chrome registry\n");
167 nsresult rv;
169 rv = NS_NewISupportsArray(getter_AddRefs(mEmptyArray));
170 if (NS_FAILED(rv)) return rv;
172 rv = ReadChromeRegistry();
173 if (NS_FAILED(rv)) return rv;
175 return NS_OK;
178 nsresult
179 nsEmbedChromeRegistry::ReadChromeRegistry()
181 nsresult rv;
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;
194 PRFileDesc *file;
195 rv = listFile->OpenNSPRFileDesc(PR_RDONLY, 0, &file);
196 if (NS_FAILED(rv)) return rv;
198 PRFileInfo finfo;
200 if (PR_GetOpenFileInfo(file, &finfo) == PR_SUCCESS) {
201 char *dataBuffer = new char[finfo.size+1];
202 if (dataBuffer) {
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;
211 PR_Close(file);
213 return rv;
216 nsresult
217 nsEmbedChromeRegistry::ProcessNewChromeBuffer(char* aBuffer, PRInt32 aLength)
219 while (aLength > 0) {
220 PRInt32 processedBytes = ProcessChromeLine(aBuffer, aLength);
221 aBuffer += processedBytes;
222 aLength -= processedBytes;
224 return NS_OK;
227 #define MAX_TOKENS 5
228 struct chromeToken {
229 const char *tokenStart;
230 const char *tokenEnd;
233 PRInt32
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 == ',') {
246 tokenCount++;
247 expectingToken = PR_TRUE;
249 else if (expectingToken)
250 tokens[tokenCount].tokenStart = aBuffer;
251 else
252 tokens[tokenCount].tokenEnd = aBuffer;
255 aBuffer++;
256 bytesProcessed++;
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;
273 nsresult
274 nsEmbedChromeRegistry::RegisterChrome(const nsACString& aChromeType,
275 const nsACString& aChromeProfile,
276 const nsACString& aChromeLocType,
277 const nsACString& aChromeLocation)
279 PRInt32 chromeType;
280 if (aChromeType.EqualsLiteral("skin"))
281 chromeType = CHROME_TYPE_SKIN;
282 else if (aChromeType.EqualsLiteral("locale"))
283 chromeType = CHROME_TYPE_LOCALE;
284 else
285 chromeType = CHROME_TYPE_CONTENT;
287 PRBool chromeIsProfile =
288 aChromeProfile.EqualsLiteral("profile");
290 PRBool chromeIsURL =
291 aChromeProfile.EqualsLiteral("url");
293 return RegisterChrome(chromeType, chromeIsProfile, chromeIsURL,
294 aChromeLocation);
297 nsresult
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)
305 return NS_OK;
308 NS_IMETHODIMP
309 nsEmbedChromeRegistry::CheckForNewChrome()
311 return NS_OK;
314 NS_IMETHODIMP
315 nsEmbedChromeRegistry::Canonify(nsIURI* aChromeURI)
317 #if 1
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".
322 if (! aChromeURI)
323 return NS_ERROR_NULL_POINTER;
325 PRBool modified = PR_TRUE; // default is we do canonification
326 nsCAutoString package, provider, file;
327 nsresult rv;
328 rv = SplitURL(aChromeURI, package, provider, file, &modified);
329 if (NS_FAILED(rv))
330 return rv;
332 if (!modified)
333 return NS_OK;
335 nsCAutoString canonical( kChromePrefix );
336 canonical += package;
337 canonical += "/";
338 canonical += provider;
339 canonical += "/";
340 canonical += file;
342 return aChromeURI->SetSpec(canonical);
343 #else
344 return NS_OK;
345 #endif
348 NS_IMETHODIMP
349 nsEmbedChromeRegistry::ConvertChromeURL(nsIURI* aChromeURL, nsACString& aResult)
351 nsresult rv;
353 rv = aChromeURL->GetSpec(aResult);
354 if (NS_FAILED(rv)) return rv;
356 return NS_OK;