|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
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/. */ |
|
6 |
|
7 #include "mozilla/ArrayUtils.h" |
|
8 |
|
9 #include "nsIconURI.h" |
|
10 #include "nsNetUtil.h" |
|
11 #include "nsIIOService.h" |
|
12 #include "nsIURL.h" |
|
13 #include "prprf.h" |
|
14 #include "plstr.h" |
|
15 #include <stdlib.h> |
|
16 |
|
17 using namespace mozilla; |
|
18 |
|
19 #define DEFAULT_IMAGE_SIZE 16 |
|
20 |
|
21 #if defined(MAX_PATH) |
|
22 #define SANE_FILE_NAME_LEN MAX_PATH |
|
23 #elif defined(PATH_MAX) |
|
24 #define SANE_FILE_NAME_LEN PATH_MAX |
|
25 #else |
|
26 #define SANE_FILE_NAME_LEN 1024 |
|
27 #endif |
|
28 |
|
29 // helper function for parsing out attributes like size, and contentType |
|
30 // from the icon url. |
|
31 static void extractAttributeValue(const char * searchString, const char * attributeName, nsCString& aResult); |
|
32 |
|
33 static const char *kSizeStrings[] = |
|
34 { |
|
35 "button", |
|
36 "toolbar", |
|
37 "toolbarsmall", |
|
38 "menu", |
|
39 "dnd", |
|
40 "dialog" |
|
41 }; |
|
42 |
|
43 static const char *kStateStrings[] = |
|
44 { |
|
45 "normal", |
|
46 "disabled" |
|
47 }; |
|
48 |
|
49 //////////////////////////////////////////////////////////////////////////////// |
|
50 |
|
51 nsMozIconURI::nsMozIconURI() |
|
52 : mSize(DEFAULT_IMAGE_SIZE), |
|
53 mIconSize(-1), |
|
54 mIconState(-1) |
|
55 { |
|
56 } |
|
57 |
|
58 nsMozIconURI::~nsMozIconURI() |
|
59 { |
|
60 } |
|
61 |
|
62 NS_IMPL_ISUPPORTS(nsMozIconURI, nsIMozIconURI, nsIURI) |
|
63 |
|
64 #define MOZICON_SCHEME "moz-icon:" |
|
65 #define MOZICON_SCHEME_LEN (sizeof(MOZICON_SCHEME) - 1) |
|
66 |
|
67 //////////////////////////////////////////////////////////////////////////////// |
|
68 // nsIURI methods: |
|
69 |
|
70 NS_IMETHODIMP |
|
71 nsMozIconURI::GetSpec(nsACString &aSpec) |
|
72 { |
|
73 aSpec = MOZICON_SCHEME; |
|
74 |
|
75 if (mIconURL) |
|
76 { |
|
77 nsAutoCString fileIconSpec; |
|
78 nsresult rv = mIconURL->GetSpec(fileIconSpec); |
|
79 NS_ENSURE_SUCCESS(rv, rv); |
|
80 aSpec += fileIconSpec; |
|
81 } |
|
82 else if (!mStockIcon.IsEmpty()) |
|
83 { |
|
84 aSpec += "//stock/"; |
|
85 aSpec += mStockIcon; |
|
86 } |
|
87 else |
|
88 { |
|
89 aSpec += "//"; |
|
90 aSpec += mFileName; |
|
91 } |
|
92 |
|
93 aSpec += "?size="; |
|
94 if (mIconSize >= 0) |
|
95 { |
|
96 aSpec += kSizeStrings[mIconSize]; |
|
97 } |
|
98 else |
|
99 { |
|
100 char buf[20]; |
|
101 PR_snprintf(buf, sizeof(buf), "%d", mSize); |
|
102 aSpec.Append(buf); |
|
103 } |
|
104 |
|
105 if (mIconState >= 0) { |
|
106 aSpec += "&state="; |
|
107 aSpec += kStateStrings[mIconState]; |
|
108 } |
|
109 |
|
110 if (!mContentType.IsEmpty()) |
|
111 { |
|
112 aSpec += "&contentType="; |
|
113 aSpec += mContentType.get(); |
|
114 } |
|
115 |
|
116 return NS_OK; |
|
117 } |
|
118 |
|
119 NS_IMETHODIMP |
|
120 nsMozIconURI::GetSpecIgnoringRef(nsACString &result) |
|
121 { |
|
122 return GetSpec(result); |
|
123 } |
|
124 |
|
125 NS_IMETHODIMP |
|
126 nsMozIconURI::GetHasRef(bool *result) |
|
127 { |
|
128 *result = false; |
|
129 return NS_OK; |
|
130 } |
|
131 |
|
132 // takes a string like ?size=32&contentType=text/html and returns a new string |
|
133 // containing just the attribute value. i.e you could pass in this string with |
|
134 // an attribute name of 'size=', this will return 32 |
|
135 // Assumption: attribute pairs in the string are separated by '&'. |
|
136 void extractAttributeValue(const char * searchString, const char * attributeName, nsCString& result) |
|
137 { |
|
138 //NS_ENSURE_ARG_POINTER(extractAttributeValue); |
|
139 |
|
140 result.Truncate(); |
|
141 |
|
142 if (searchString && attributeName) |
|
143 { |
|
144 // search the string for attributeName |
|
145 uint32_t attributeNameSize = strlen(attributeName); |
|
146 const char * startOfAttribute = PL_strcasestr(searchString, attributeName); |
|
147 if (startOfAttribute && |
|
148 ( *(startOfAttribute-1) == '?' || *(startOfAttribute-1) == '&') ) |
|
149 { |
|
150 startOfAttribute += attributeNameSize; // skip over the attributeName |
|
151 if (*startOfAttribute) // is there something after the attribute name |
|
152 { |
|
153 const char * endofAttribute = strchr(startOfAttribute, '&'); |
|
154 if (endofAttribute) |
|
155 result.Assign(Substring(startOfAttribute, endofAttribute)); |
|
156 else |
|
157 result.Assign(startOfAttribute); |
|
158 } // if we have a attribute value |
|
159 } // if we have a attribute name |
|
160 } // if we got non-null search string and attribute name values |
|
161 } |
|
162 |
|
163 NS_IMETHODIMP |
|
164 nsMozIconURI::SetSpec(const nsACString &aSpec) |
|
165 { |
|
166 // Reset everything to default values. |
|
167 mIconURL = nullptr; |
|
168 mSize = DEFAULT_IMAGE_SIZE; |
|
169 mContentType.Truncate(); |
|
170 mFileName.Truncate(); |
|
171 mStockIcon.Truncate(); |
|
172 mIconSize = -1; |
|
173 mIconState = -1; |
|
174 |
|
175 nsAutoCString iconSpec(aSpec); |
|
176 if (!Substring(iconSpec, 0, MOZICON_SCHEME_LEN).EqualsLiteral(MOZICON_SCHEME)) |
|
177 return NS_ERROR_MALFORMED_URI; |
|
178 |
|
179 int32_t questionMarkPos = iconSpec.Find("?"); |
|
180 if (questionMarkPos != -1 && static_cast<int32_t>(iconSpec.Length()) > (questionMarkPos + 1)) |
|
181 { |
|
182 extractAttributeValue(iconSpec.get(), "contentType=", mContentType); |
|
183 |
|
184 nsAutoCString sizeString; |
|
185 extractAttributeValue(iconSpec.get(), "size=", sizeString); |
|
186 if (!sizeString.IsEmpty()) |
|
187 { |
|
188 const char *sizeStr = sizeString.get(); |
|
189 for (uint32_t i = 0; i < ArrayLength(kSizeStrings); i++) |
|
190 { |
|
191 if (PL_strcasecmp(sizeStr, kSizeStrings[i]) == 0) |
|
192 { |
|
193 mIconSize = i; |
|
194 break; |
|
195 } |
|
196 } |
|
197 |
|
198 int32_t sizeValue = atoi(sizeString.get()); |
|
199 if (sizeValue) |
|
200 mSize = sizeValue; |
|
201 } |
|
202 |
|
203 nsAutoCString stateString; |
|
204 extractAttributeValue(iconSpec.get(), "state=", stateString); |
|
205 if (!stateString.IsEmpty()) |
|
206 { |
|
207 const char *stateStr = stateString.get(); |
|
208 for (uint32_t i = 0; i < ArrayLength(kStateStrings); i++) |
|
209 { |
|
210 if (PL_strcasecmp(stateStr, kStateStrings[i]) == 0) |
|
211 { |
|
212 mIconState = i; |
|
213 break; |
|
214 } |
|
215 } |
|
216 } |
|
217 } |
|
218 |
|
219 int32_t pathLength = iconSpec.Length() - MOZICON_SCHEME_LEN; |
|
220 if (questionMarkPos != -1) |
|
221 pathLength = questionMarkPos - MOZICON_SCHEME_LEN; |
|
222 if (pathLength < 3) |
|
223 return NS_ERROR_MALFORMED_URI; |
|
224 |
|
225 nsAutoCString iconPath(Substring(iconSpec, MOZICON_SCHEME_LEN, pathLength)); |
|
226 |
|
227 // Icon URI path can have three forms: |
|
228 // (1) //stock/<icon-identifier> |
|
229 // (2) //<some dummy file with an extension> |
|
230 // (3) a valid URL |
|
231 |
|
232 if (!strncmp("//stock/", iconPath.get(), 8)) |
|
233 { |
|
234 mStockIcon.Assign(Substring(iconPath, 8)); |
|
235 // An icon identifier must always be specified. |
|
236 if (mStockIcon.IsEmpty()) |
|
237 return NS_ERROR_MALFORMED_URI; |
|
238 return NS_OK; |
|
239 } |
|
240 |
|
241 if (StringBeginsWith(iconPath, NS_LITERAL_CSTRING("//"))) |
|
242 { |
|
243 // Sanity check this supposed dummy file name. |
|
244 if (iconPath.Length() > SANE_FILE_NAME_LEN) |
|
245 return NS_ERROR_MALFORMED_URI; |
|
246 iconPath.Cut(0, 2); |
|
247 mFileName.Assign(iconPath); |
|
248 } |
|
249 |
|
250 nsresult rv; |
|
251 nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); |
|
252 NS_ENSURE_SUCCESS(rv, rv); |
|
253 |
|
254 nsCOMPtr<nsIURI> uri; |
|
255 ioService->NewURI(iconPath, nullptr, nullptr, getter_AddRefs(uri)); |
|
256 mIconURL = do_QueryInterface(uri); |
|
257 if (mIconURL) |
|
258 mFileName.Truncate(); |
|
259 else if (mFileName.IsEmpty()) |
|
260 return NS_ERROR_MALFORMED_URI; |
|
261 |
|
262 return NS_OK; |
|
263 } |
|
264 |
|
265 NS_IMETHODIMP |
|
266 nsMozIconURI::GetPrePath(nsACString &prePath) |
|
267 { |
|
268 prePath = MOZICON_SCHEME; |
|
269 return NS_OK; |
|
270 } |
|
271 |
|
272 NS_IMETHODIMP |
|
273 nsMozIconURI::GetScheme(nsACString &aScheme) |
|
274 { |
|
275 aScheme = "moz-icon"; |
|
276 return NS_OK; |
|
277 } |
|
278 |
|
279 NS_IMETHODIMP |
|
280 nsMozIconURI::SetScheme(const nsACString &aScheme) |
|
281 { |
|
282 // doesn't make sense to set the scheme of a moz-icon URL |
|
283 return NS_ERROR_FAILURE; |
|
284 } |
|
285 |
|
286 NS_IMETHODIMP |
|
287 nsMozIconURI::GetUsername(nsACString &aUsername) |
|
288 { |
|
289 return NS_ERROR_FAILURE; |
|
290 } |
|
291 |
|
292 NS_IMETHODIMP |
|
293 nsMozIconURI::SetUsername(const nsACString &aUsername) |
|
294 { |
|
295 return NS_ERROR_FAILURE; |
|
296 } |
|
297 |
|
298 NS_IMETHODIMP |
|
299 nsMozIconURI::GetPassword(nsACString &aPassword) |
|
300 { |
|
301 return NS_ERROR_FAILURE; |
|
302 } |
|
303 |
|
304 NS_IMETHODIMP |
|
305 nsMozIconURI::SetPassword(const nsACString &aPassword) |
|
306 { |
|
307 return NS_ERROR_FAILURE; |
|
308 } |
|
309 |
|
310 NS_IMETHODIMP |
|
311 nsMozIconURI::GetUserPass(nsACString &aUserPass) |
|
312 { |
|
313 return NS_ERROR_FAILURE; |
|
314 } |
|
315 |
|
316 NS_IMETHODIMP |
|
317 nsMozIconURI::SetUserPass(const nsACString &aUserPass) |
|
318 { |
|
319 return NS_ERROR_FAILURE; |
|
320 } |
|
321 |
|
322 NS_IMETHODIMP |
|
323 nsMozIconURI::GetHostPort(nsACString &aHostPort) |
|
324 { |
|
325 return NS_ERROR_FAILURE; |
|
326 } |
|
327 |
|
328 NS_IMETHODIMP |
|
329 nsMozIconURI::SetHostPort(const nsACString &aHostPort) |
|
330 { |
|
331 return NS_ERROR_FAILURE; |
|
332 } |
|
333 |
|
334 NS_IMETHODIMP |
|
335 nsMozIconURI::GetHost(nsACString &aHost) |
|
336 { |
|
337 return NS_ERROR_FAILURE; |
|
338 } |
|
339 |
|
340 NS_IMETHODIMP |
|
341 nsMozIconURI::SetHost(const nsACString &aHost) |
|
342 { |
|
343 return NS_ERROR_FAILURE; |
|
344 } |
|
345 |
|
346 NS_IMETHODIMP |
|
347 nsMozIconURI::GetPort(int32_t *aPort) |
|
348 { |
|
349 return NS_ERROR_FAILURE; |
|
350 } |
|
351 |
|
352 NS_IMETHODIMP |
|
353 nsMozIconURI::SetPort(int32_t aPort) |
|
354 { |
|
355 return NS_ERROR_FAILURE; |
|
356 } |
|
357 |
|
358 NS_IMETHODIMP |
|
359 nsMozIconURI::GetPath(nsACString &aPath) |
|
360 { |
|
361 aPath.Truncate(); |
|
362 return NS_OK; |
|
363 } |
|
364 |
|
365 NS_IMETHODIMP |
|
366 nsMozIconURI::SetPath(const nsACString &aPath) |
|
367 { |
|
368 return NS_ERROR_FAILURE; |
|
369 } |
|
370 |
|
371 NS_IMETHODIMP |
|
372 nsMozIconURI::GetRef(nsACString &aRef) |
|
373 { |
|
374 aRef.Truncate(); |
|
375 return NS_OK; |
|
376 } |
|
377 |
|
378 NS_IMETHODIMP |
|
379 nsMozIconURI::SetRef(const nsACString &aRef) |
|
380 { |
|
381 return NS_ERROR_FAILURE; |
|
382 } |
|
383 |
|
384 NS_IMETHODIMP |
|
385 nsMozIconURI::Equals(nsIURI *other, bool *result) |
|
386 { |
|
387 NS_ENSURE_ARG_POINTER(other); |
|
388 NS_PRECONDITION(result, "null pointer"); |
|
389 |
|
390 nsAutoCString spec1; |
|
391 nsAutoCString spec2; |
|
392 |
|
393 other->GetSpec(spec2); |
|
394 GetSpec(spec1); |
|
395 if (!PL_strcasecmp(spec1.get(), spec2.get())) |
|
396 *result = true; |
|
397 else |
|
398 *result = false; |
|
399 return NS_OK; |
|
400 } |
|
401 |
|
402 NS_IMETHODIMP |
|
403 nsMozIconURI::EqualsExceptRef(nsIURI *other, bool *result) |
|
404 { |
|
405 // GetRef/SetRef not supported by nsMozIconURI, so |
|
406 // EqualsExceptRef() is the same as Equals(). |
|
407 return Equals(other, result); |
|
408 } |
|
409 |
|
410 NS_IMETHODIMP |
|
411 nsMozIconURI::SchemeIs(const char *i_Scheme, bool *o_Equals) |
|
412 { |
|
413 NS_ENSURE_ARG_POINTER(o_Equals); |
|
414 if (!i_Scheme) return NS_ERROR_INVALID_ARG; |
|
415 |
|
416 *o_Equals = PL_strcasecmp("moz-icon", i_Scheme) ? false : true; |
|
417 return NS_OK; |
|
418 } |
|
419 |
|
420 NS_IMETHODIMP |
|
421 nsMozIconURI::Clone(nsIURI **result) |
|
422 { |
|
423 nsCOMPtr<nsIURL> newIconURL; |
|
424 if (mIconURL) |
|
425 { |
|
426 nsCOMPtr<nsIURI> newURI; |
|
427 nsresult rv = mIconURL->Clone(getter_AddRefs(newURI)); |
|
428 if (NS_FAILED(rv)) |
|
429 return rv; |
|
430 newIconURL = do_QueryInterface(newURI, &rv); |
|
431 if (NS_FAILED(rv)) |
|
432 return rv; |
|
433 } |
|
434 |
|
435 nsMozIconURI *uri = new nsMozIconURI(); |
|
436 newIconURL.swap(uri->mIconURL); |
|
437 uri->mSize = mSize; |
|
438 uri->mContentType = mContentType; |
|
439 uri->mFileName = mFileName; |
|
440 uri->mStockIcon = mStockIcon; |
|
441 uri->mIconSize = mIconSize; |
|
442 uri->mIconState = mIconState; |
|
443 NS_ADDREF(*result = uri); |
|
444 |
|
445 return NS_OK; |
|
446 } |
|
447 |
|
448 NS_IMETHODIMP |
|
449 nsMozIconURI::CloneIgnoringRef(nsIURI **result) |
|
450 { |
|
451 // GetRef/SetRef not supported by nsMozIconURI, so |
|
452 // CloneIgnoringRef() is the same as Clone(). |
|
453 return Clone(result); |
|
454 } |
|
455 |
|
456 NS_IMETHODIMP |
|
457 nsMozIconURI::Resolve(const nsACString &relativePath, nsACString &result) |
|
458 { |
|
459 return NS_ERROR_NOT_IMPLEMENTED; |
|
460 } |
|
461 |
|
462 NS_IMETHODIMP |
|
463 nsMozIconURI::GetAsciiSpec(nsACString &aSpecA) |
|
464 { |
|
465 return GetSpec(aSpecA); |
|
466 } |
|
467 |
|
468 NS_IMETHODIMP |
|
469 nsMozIconURI::GetAsciiHost(nsACString &aHostA) |
|
470 { |
|
471 return GetHost(aHostA); |
|
472 } |
|
473 |
|
474 NS_IMETHODIMP |
|
475 nsMozIconURI::GetOriginCharset(nsACString &result) |
|
476 { |
|
477 result.Truncate(); |
|
478 return NS_OK; |
|
479 } |
|
480 |
|
481 //////////////////////////////////////////////////////////////////////////////// |
|
482 // nsIIconUri methods: |
|
483 |
|
484 NS_IMETHODIMP |
|
485 nsMozIconURI::GetIconURL(nsIURL* * aFileUrl) |
|
486 { |
|
487 *aFileUrl = mIconURL; |
|
488 NS_IF_ADDREF(*aFileUrl); |
|
489 return NS_OK; |
|
490 } |
|
491 |
|
492 NS_IMETHODIMP |
|
493 nsMozIconURI::SetIconURL(nsIURL* aFileUrl) |
|
494 { |
|
495 // this isn't called anywhere, needs to go through SetSpec parsing |
|
496 return NS_ERROR_NOT_IMPLEMENTED; |
|
497 } |
|
498 |
|
499 NS_IMETHODIMP |
|
500 nsMozIconURI::GetImageSize(uint32_t * aImageSize) // measured by # of pixels in a row. defaults to 16. |
|
501 { |
|
502 *aImageSize = mSize; |
|
503 return NS_OK; |
|
504 } |
|
505 |
|
506 NS_IMETHODIMP |
|
507 nsMozIconURI::SetImageSize(uint32_t aImageSize) // measured by # of pixels in a row. defaults to 16. |
|
508 { |
|
509 mSize = aImageSize; |
|
510 return NS_OK; |
|
511 } |
|
512 |
|
513 NS_IMETHODIMP |
|
514 nsMozIconURI::GetContentType(nsACString &aContentType) |
|
515 { |
|
516 aContentType = mContentType; |
|
517 return NS_OK; |
|
518 } |
|
519 |
|
520 NS_IMETHODIMP |
|
521 nsMozIconURI::SetContentType(const nsACString &aContentType) |
|
522 { |
|
523 mContentType = aContentType; |
|
524 return NS_OK; |
|
525 } |
|
526 |
|
527 NS_IMETHODIMP |
|
528 nsMozIconURI::GetFileExtension(nsACString &aFileExtension) |
|
529 { |
|
530 // First, try to get the extension from mIconURL if we have one |
|
531 if (mIconURL) |
|
532 { |
|
533 nsAutoCString fileExt; |
|
534 if (NS_SUCCEEDED(mIconURL->GetFileExtension(fileExt))) |
|
535 { |
|
536 if (!fileExt.IsEmpty()) |
|
537 { |
|
538 // unfortunately, this code doesn't give us the required '.' in front of the extension |
|
539 // so we have to do it ourselves.. |
|
540 aFileExtension.Assign('.'); |
|
541 aFileExtension.Append(fileExt); |
|
542 } |
|
543 } |
|
544 return NS_OK; |
|
545 } |
|
546 |
|
547 if (!mFileName.IsEmpty()) |
|
548 { |
|
549 // truncate the extension out of the file path... |
|
550 const char * chFileName = mFileName.get(); // get the underlying buffer |
|
551 const char * fileExt = strrchr(chFileName, '.'); |
|
552 if (!fileExt) |
|
553 return NS_OK; |
|
554 aFileExtension = fileExt; |
|
555 } |
|
556 |
|
557 return NS_OK; |
|
558 } |
|
559 |
|
560 NS_IMETHODIMP |
|
561 nsMozIconURI::GetStockIcon(nsACString &aStockIcon) |
|
562 { |
|
563 aStockIcon = mStockIcon; |
|
564 return NS_OK; |
|
565 } |
|
566 |
|
567 NS_IMETHODIMP |
|
568 nsMozIconURI::GetIconSize(nsACString &aSize) |
|
569 { |
|
570 if (mIconSize >= 0) |
|
571 aSize = kSizeStrings[mIconSize]; |
|
572 else |
|
573 aSize.Truncate(); |
|
574 return NS_OK; |
|
575 } |
|
576 |
|
577 NS_IMETHODIMP |
|
578 nsMozIconURI::GetIconState(nsACString &aState) |
|
579 { |
|
580 if (mIconState >= 0) |
|
581 aState = kStateStrings[mIconState]; |
|
582 else |
|
583 aState.Truncate(); |
|
584 return NS_OK; |
|
585 } |
|
586 //////////////////////////////////////////////////////////////////////////////// |