1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsIInputStream.h"
7 #include "nsIStringStream.h"
10 #include "nsIResProtocolHandler.h"
11 #include "nsIChromeRegistry.h"
12 #include "nsAutoPtr.h"
13 #include "StartupCacheUtils.h"
14 #include "mozilla/scache/StartupCache.h"
15 #include "mozilla/Omnijar.h"
21 NewObjectInputStreamFromBuffer(char* buffer
, uint32_t len
,
22 nsIObjectInputStream
** stream
)
24 nsCOMPtr
<nsIStringInputStream
> stringStream
25 = do_CreateInstance("@mozilla.org/io/string-input-stream;1");
26 nsCOMPtr
<nsIObjectInputStream
> objectInput
27 = do_CreateInstance("@mozilla.org/binaryinputstream;1");
29 stringStream
->AdoptData(buffer
, len
);
30 objectInput
->SetInputStream(stringStream
);
32 objectInput
.forget(stream
);
37 NewObjectOutputWrappedStorageStream(nsIObjectOutputStream
**wrapperStream
,
38 nsIStorageStream
** stream
,
41 nsCOMPtr
<nsIStorageStream
> storageStream
;
43 nsresult rv
= NS_NewStorageStream(256, UINT32_MAX
, getter_AddRefs(storageStream
));
44 NS_ENSURE_SUCCESS(rv
, rv
);
46 nsCOMPtr
<nsIObjectOutputStream
> objectOutput
47 = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
48 nsCOMPtr
<nsIOutputStream
> outputStream
49 = do_QueryInterface(storageStream
);
51 objectOutput
->SetOutputStream(outputStream
);
54 if (wantDebugStream
) {
55 // Wrap in debug stream to detect unsupported writes of
56 // multiply-referenced non-singleton objects
57 StartupCache
* sc
= StartupCache::GetSingleton();
58 NS_ENSURE_TRUE(sc
, NS_ERROR_UNEXPECTED
);
59 nsCOMPtr
<nsIObjectOutputStream
> debugStream
;
60 sc
->GetDebugObjectOutputStream(objectOutput
, getter_AddRefs(debugStream
));
61 debugStream
.forget(wrapperStream
);
63 objectOutput
.forget(wrapperStream
);
66 objectOutput
.forget(wrapperStream
);
69 storageStream
.forget(stream
);
74 NewBufferFromStorageStream(nsIStorageStream
*storageStream
,
75 char** buffer
, uint32_t* len
)
78 nsCOMPtr
<nsIInputStream
> inputStream
;
79 rv
= storageStream
->NewInputStream(0, getter_AddRefs(inputStream
));
80 NS_ENSURE_SUCCESS(rv
, rv
);
83 rv
= inputStream
->Available(&avail64
);
84 NS_ENSURE_SUCCESS(rv
, rv
);
85 NS_ENSURE_TRUE(avail64
<= UINT32_MAX
, NS_ERROR_FILE_TOO_BIG
);
87 uint32_t avail
= (uint32_t)avail64
;
88 nsAutoArrayPtr
<char> temp (new char[avail
]);
90 rv
= inputStream
->Read(temp
, avail
, &read
);
91 if (NS_SUCCEEDED(rv
) && avail
!= read
)
92 rv
= NS_ERROR_UNEXPECTED
;
99 *buffer
= temp
.forget();
103 static const char baseName
[2][5] = { "gre/", "app/" };
106 canonicalizeBase(nsAutoCString
&spec
,
109 nsAutoCString greBase
, appBase
;
110 nsresult rv
= mozilla::Omnijar::GetURIString(mozilla::Omnijar::GRE
, greBase
);
111 if (NS_FAILED(rv
) || !greBase
.Length())
114 rv
= mozilla::Omnijar::GetURIString(mozilla::Omnijar::APP
, appBase
);
118 bool underGre
= !greBase
.Compare(spec
.get(), false, greBase
.Length());
119 bool underApp
= appBase
.Length() &&
120 !appBase
.Compare(spec
.get(), false, appBase
.Length());
122 if (!underGre
&& !underApp
)
126 * At this point, if both underGre and underApp are true, it can be one
127 * of the two following cases:
128 * - the GRE directory points to a subdirectory of the APP directory,
129 * meaning spec points under GRE.
130 * - the APP directory points to a subdirectory of the GRE directory,
131 * meaning spec points under APP.
132 * Checking the GRE and APP path length is enough to know in which case
135 if (underGre
&& underApp
&& greBase
.Length() < appBase
.Length())
138 out
.Append("/resource/");
139 out
.Append(baseName
[underGre
? mozilla::Omnijar::GRE
: mozilla::Omnijar::APP
]);
140 out
.Append(Substring(spec
, underGre
? greBase
.Length() : appBase
.Length()));
145 * PathifyURI transforms uris into useful zip paths
146 * to make it easier to manipulate startup cache entries
147 * using standard zip tools.
148 * Transformations applied:
149 * * resource:// URIs are resolved to their corresponding file/jar URI to
150 * canonicalize resources URIs other than gre and app.
151 * * Paths under GRE or APP directory have their base path replaced with
152 * resource/gre or resource/app to avoid depending on install location.
153 * * jar:file:///path/to/file.jar!/sub/path urls are replaced with
154 * /path/to/file.jar/sub/path
156 * The result is appended to the string passed in. Adding a prefix before
157 * calling is recommended to avoid colliding with other cache users.
159 * For example, in the js loader (string is prefixed with jsloader by caller):
160 * resource://gre/modules/XPCOMUtils.jsm or
161 * file://$GRE_DIR/modules/XPCOMUtils.jsm or
162 * jar:file://$GRE_DIR/omni.jar!/modules/XPCOMUtils.jsm becomes
163 * jsloader/resource/gre/modules/XPCOMUtils.jsm
164 * file://$PROFILE_DIR/extensions/{uuid}/components/component.js becomes
165 * jsloader/$PROFILE_DIR/extensions/%7Buuid%7D/components/component.js
166 * jar:file://$PROFILE_DIR/extensions/some.xpi!/components/component.js becomes
167 * jsloader/$PROFILE_DIR/extensions/some.xpi/components/component.js
170 PathifyURI(nsIURI
*in
, nsACString
&out
)
174 nsCOMPtr
<nsIURI
> uri
= in
;
177 // Resolve resource:// URIs. At the end of this if/else block, we
178 // have both spec and uri variables identifying the same URI.
179 if (NS_SUCCEEDED(in
->SchemeIs("resource", &equals
)) && equals
) {
180 nsCOMPtr
<nsIIOService
> ioService
= do_GetIOService(&rv
);
181 NS_ENSURE_SUCCESS(rv
, rv
);
183 nsCOMPtr
<nsIProtocolHandler
> ph
;
184 rv
= ioService
->GetProtocolHandler("resource", getter_AddRefs(ph
));
185 NS_ENSURE_SUCCESS(rv
, rv
);
187 nsCOMPtr
<nsIResProtocolHandler
> irph(do_QueryInterface(ph
, &rv
));
188 NS_ENSURE_SUCCESS(rv
, rv
);
190 rv
= irph
->ResolveURI(in
, spec
);
191 NS_ENSURE_SUCCESS(rv
, rv
);
193 rv
= ioService
->NewURI(spec
, nullptr, nullptr, getter_AddRefs(uri
));
194 NS_ENSURE_SUCCESS(rv
, rv
);
196 if (NS_SUCCEEDED(in
->SchemeIs("chrome", &equals
)) && equals
) {
197 nsCOMPtr
<nsIChromeRegistry
> chromeReg
=
198 mozilla::services::GetChromeRegistryService();
200 return NS_ERROR_UNEXPECTED
;
202 rv
= chromeReg
->ConvertChromeURL(in
, getter_AddRefs(uri
));
203 NS_ENSURE_SUCCESS(rv
, rv
);
206 rv
= uri
->GetSpec(spec
);
207 NS_ENSURE_SUCCESS(rv
, rv
);
210 if (!canonicalizeBase(spec
, out
)) {
211 if (NS_SUCCEEDED(uri
->SchemeIs("file", &equals
)) && equals
) {
212 nsCOMPtr
<nsIFileURL
> baseFileURL
;
213 baseFileURL
= do_QueryInterface(uri
, &rv
);
214 NS_ENSURE_SUCCESS(rv
, rv
);
217 rv
= baseFileURL
->GetPath(path
);
218 NS_ENSURE_SUCCESS(rv
, rv
);
221 } else if (NS_SUCCEEDED(uri
->SchemeIs("jar", &equals
)) && equals
) {
222 nsCOMPtr
<nsIJARURI
> jarURI
= do_QueryInterface(uri
, &rv
);
223 NS_ENSURE_SUCCESS(rv
, rv
);
225 nsCOMPtr
<nsIURI
> jarFileURI
;
226 rv
= jarURI
->GetJARFile(getter_AddRefs(jarFileURI
));
227 NS_ENSURE_SUCCESS(rv
, rv
);
229 rv
= PathifyURI(jarFileURI
, out
);
230 NS_ENSURE_SUCCESS(rv
, rv
);
233 rv
= jarURI
->GetJAREntry(path
);
234 NS_ENSURE_SUCCESS(rv
, rv
);
237 } else { // Very unlikely
239 rv
= uri
->GetSpec(spec
);
240 NS_ENSURE_SUCCESS(rv
, rv
);