VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp@ 4837

Last change on this file since 4837 was 1, checked in by vboxsync, 54 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
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
4 *
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/
9 *
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.
14 *
15 * The Original Code is Mozilla FastLoad code.
16 *
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.
21 *
22 * Contributor(s):
23 * Brendan Eich <brendan@mozilla.org> (original author)
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
39#include "prtypes.h"
40#include "prio.h"
41#include "prtime.h"
42#include "pldhash.h"
43
44#include "nsAppDirectoryServiceDefs.h"
45#include "nsAutoLock.h"
46#include "nsCOMPtr.h"
47#include "nsFastLoadFile.h"
48#include "nsFastLoadPtr.h"
49#include "nsFastLoadService.h"
50#include "nsString.h"
51
52#include "nsIComponentManager.h"
53#include "nsIEnumerator.h"
54#include "nsIFastLoadFileControl.h"
55#include "nsIFile.h"
56#include "nsIObjectInputStream.h"
57#include "nsIObjectOutputStream.h"
58#include "nsISeekableStream.h"
59#include "nsISupports.h"
60
61PR_IMPLEMENT_DATA(nsIFastLoadService*) gFastLoadService_ = nsnull;
62
63NS_IMPL_THREADSAFE_ISUPPORTS1(nsFastLoadService, nsIFastLoadService)
64
65nsFastLoadService::nsFastLoadService()
66 : mLock(nsnull),
67 mFastLoadPtrMap(nsnull),
68 mDirection(0)
69{
70 NS_ASSERTION(gFastLoadService_ == nsnull, "double FastLoadService init?");
71 gFastLoadService_ = this;
72}
73
74nsFastLoadService::~nsFastLoadService()
75{
76 gFastLoadService_ = nsnull;
77
78 if (mInputStream)
79 mInputStream->Close();
80 if (mOutputStream)
81 mOutputStream->Close();
82
83 if (mFastLoadPtrMap)
84 PL_DHashTableDestroy(mFastLoadPtrMap);
85 if (mLock)
86 PR_DestroyLock(mLock);
87}
88
89NS_IMETHODIMP
90nsFastLoadService::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
91{
92 *aResult = nsnull;
93 if (aOuter)
94 return NS_ERROR_NO_AGGREGATION;
95
96 nsFastLoadService* fastLoadService = new nsFastLoadService();
97 if (!fastLoadService)
98 return NS_ERROR_OUT_OF_MEMORY;
99
100 fastLoadService->mLock = PR_NewLock();
101 if (!fastLoadService->mLock) {
102 delete fastLoadService;
103 return NS_ERROR_OUT_OF_MEMORY;
104 }
105
106 NS_ADDREF(fastLoadService);
107 nsresult rv = fastLoadService->QueryInterface(aIID, aResult);
108 NS_RELEASE(fastLoadService);
109 return rv;
110}
111
112#if defined XP_MAC
113
114// Mac format: "<Basename> FastLoad File" with <basename> capitalized.
115# include "nsCRT.h"
116
117# define MASSAGE_BASENAME(bn) (bn.SetCharAt(nsCRT::ToUpper(bn.CharAt(0)), 0))
118# define PLATFORM_FASL_SUFFIX " FastLoad File"
119
120#elif defined(XP_UNIX) || defined(XP_BEOS)
121
122// Unix format: "<basename>.mfasl".
123# define MASSAGE_BASENAME(bn) /* nothing */
124# define PLATFORM_FASL_SUFFIX ".mfasl"
125
126#elif defined(XP_WIN) || defined(XP_OS2)
127
128// Windows format: "<basename>.mfl".
129# define MASSAGE_BASENAME(bn) /* nothing */
130# define PLATFORM_FASL_SUFFIX ".mfl"
131
132#endif
133
134nsresult
135nsFastLoadService::NewFastLoadFile(const char* aBaseName, nsIFile* *aResult)
136{
137 nsresult rv;
138 nsCOMPtr<nsIFile> file;
139
140 rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
141 getter_AddRefs(file));
142 if (NS_FAILED(rv))
143 return rv;
144
145 nsCAutoString name(aBaseName);
146 MASSAGE_BASENAME(name);
147 name += PLATFORM_FASL_SUFFIX;
148 rv = file->AppendNative(name);
149 if (NS_FAILED(rv))
150 return rv;
151
152 *aResult = file;
153 NS_ADDREF(*aResult);
154 return NS_OK;
155}
156
157NS_IMETHODIMP
158nsFastLoadService::NewInputStream(nsIInputStream* aSrcStream,
159 nsIObjectInputStream* *aResult)
160{
161 nsAutoLock lock(mLock);
162
163 nsCOMPtr<nsIObjectInputStream> stream;
164 nsresult rv = NS_NewFastLoadFileReader(getter_AddRefs(stream), aSrcStream);
165 if (NS_FAILED(rv))
166 return rv;
167
168 *aResult = stream;
169 NS_ADDREF(*aResult);
170 return NS_OK;
171}
172
173NS_IMETHODIMP
174nsFastLoadService::NewOutputStream(nsIOutputStream* aDestStream,
175 nsIObjectOutputStream* *aResult)
176{
177 nsAutoLock lock(mLock);
178
179 return NS_NewFastLoadFileWriter(aResult, aDestStream, mFileIO);
180}
181
182NS_IMETHODIMP
183nsFastLoadService::GetInputStream(nsIObjectInputStream* *aResult)
184{
185 NS_IF_ADDREF(*aResult = mInputStream);
186 return NS_OK;
187}
188
189NS_IMETHODIMP
190nsFastLoadService::SetInputStream(nsIObjectInputStream* aStream)
191{
192 nsAutoLock lock(mLock);
193 mInputStream = aStream;
194 return NS_OK;
195}
196
197NS_IMETHODIMP
198nsFastLoadService::GetOutputStream(nsIObjectOutputStream* *aResult)
199{
200 NS_IF_ADDREF(*aResult = mOutputStream);
201 return NS_OK;
202}
203
204NS_IMETHODIMP
205nsFastLoadService::SetOutputStream(nsIObjectOutputStream* aStream)
206{
207 nsAutoLock lock(mLock);
208 mOutputStream = aStream;
209 return NS_OK;
210}
211
212NS_IMETHODIMP
213nsFastLoadService::GetFileIO(nsIFastLoadFileIO* *aResult)
214{
215 NS_IF_ADDREF(*aResult = mFileIO);
216 return NS_OK;
217}
218
219NS_IMETHODIMP
220nsFastLoadService::SetFileIO(nsIFastLoadFileIO* aFileIO)
221{
222 nsAutoLock lock(mLock);
223 mFileIO = aFileIO;
224 return NS_OK;
225}
226
227NS_IMETHODIMP
228nsFastLoadService::GetDirection(PRInt32 *aResult)
229{
230 *aResult = mDirection;
231 return NS_OK;
232}
233
234NS_IMETHODIMP
235nsFastLoadService::HasMuxedDocument(const char* aURISpec, PRBool *aResult)
236{
237 nsresult rv = NS_ERROR_NOT_AVAILABLE;
238 nsCOMPtr<nsIFastLoadFileControl> control;
239
240 *aResult = PR_FALSE;
241 nsAutoLock lock(mLock);
242
243 if (mInputStream) {
244 control = do_QueryInterface(mInputStream);
245 if (control)
246 rv = control->HasMuxedDocument(aURISpec, aResult);
247 }
248
249 if (! *aResult && mOutputStream) {
250 control = do_QueryInterface(mOutputStream);
251 if (control)
252 rv = control->HasMuxedDocument(aURISpec, aResult);
253 }
254
255 return rv;
256}
257
258NS_IMETHODIMP
259nsFastLoadService::StartMuxedDocument(nsISupports* aURI, const char* aURISpec,
260 PRInt32 aDirectionFlags)
261{
262 nsresult rv = NS_ERROR_NOT_AVAILABLE;
263 nsCOMPtr<nsIFastLoadFileControl> control;
264 nsAutoLock lock(mLock);
265
266 // Try for an input stream first, in case aURISpec's data is multiplexed
267 // in the current FastLoad file.
268 if ((aDirectionFlags & NS_FASTLOAD_READ) && mInputStream) {
269 control = do_QueryInterface(mInputStream);
270 if (control) {
271 // If aURISpec is not in the multiplex, control->StartMuxedDocument
272 // will return NS_ERROR_NOT_AVAILABLE.
273 rv = control->StartMuxedDocument(aURI, aURISpec);
274 if (NS_SUCCEEDED(rv) || rv != NS_ERROR_NOT_AVAILABLE)
275 return rv;
276
277 // Ok, aURISpec is not in the existing mux. If we have no output
278 // stream yet, wrap the reader with a FastLoad file updater.
279 if (!mOutputStream && mFileIO) {
280 nsCOMPtr<nsIOutputStream> output;
281 rv = mFileIO->GetOutputStream(getter_AddRefs(output));
282 if (NS_FAILED(rv))
283 return rv;
284
285 // NB: mInputStream must be an nsFastLoadFileReader!
286 rv = NS_NewFastLoadFileUpdater(getter_AddRefs(mOutputStream),
287 output,
288 mInputStream);
289 if (NS_FAILED(rv))
290 return rv;
291 }
292
293 if (aDirectionFlags == NS_FASTLOAD_READ) {
294 // Tell our caller to re-start multiplexing, rather than attempt
295 // to select and deserialize now.
296 return NS_ERROR_NOT_AVAILABLE;
297 }
298 }
299 }
300
301 if ((aDirectionFlags & NS_FASTLOAD_WRITE) && mOutputStream) {
302 control = do_QueryInterface(mOutputStream);
303 if (control)
304 rv = control->StartMuxedDocument(aURI, aURISpec);
305 }
306 return rv;
307}
308
309NS_IMETHODIMP
310nsFastLoadService::SelectMuxedDocument(nsISupports* aURI, nsISupports** aResult)
311{
312 nsresult rv = NS_ERROR_NOT_AVAILABLE;
313 nsCOMPtr<nsIFastLoadFileControl> control;
314 nsAutoLock lock(mLock);
315
316 // Try to select the reader, if any; then only if the URI was not in the
317 // file already, select the writer/updater.
318 if (mInputStream) {
319 control = do_QueryInterface(mInputStream);
320 if (control) {
321 rv = control->SelectMuxedDocument(aURI, aResult);
322 if (NS_SUCCEEDED(rv))
323 mDirection = NS_FASTLOAD_READ;
324 }
325 }
326
327 if (rv == NS_ERROR_NOT_AVAILABLE && mOutputStream) {
328 control = do_QueryInterface(mOutputStream);
329 if (control) {
330 rv = control->SelectMuxedDocument(aURI, aResult);
331 if (NS_SUCCEEDED(rv))
332 mDirection = NS_FASTLOAD_WRITE;
333 }
334 }
335
336 return rv;
337}
338
339NS_IMETHODIMP
340nsFastLoadService::EndMuxedDocument(nsISupports* aURI)
341{
342 nsresult rv = NS_ERROR_NOT_AVAILABLE;
343 nsCOMPtr<nsIFastLoadFileControl> control;
344 nsAutoLock lock(mLock);
345
346 // Try to end the document identified by aURI in the reader, if any; then
347 // only if the URI was not in the file already, end the writer/updater.
348 if (mInputStream) {
349 control = do_QueryInterface(mInputStream);
350 if (control)
351 rv = control->EndMuxedDocument(aURI);
352 }
353
354 if (rv == NS_ERROR_NOT_AVAILABLE && mOutputStream) {
355 control = do_QueryInterface(mOutputStream);
356 if (control)
357 rv = control->EndMuxedDocument(aURI);
358 }
359
360 mDirection = 0;
361 return rv;
362}
363
364NS_IMETHODIMP
365nsFastLoadService::AddDependency(nsIFile* aFile)
366{
367 nsAutoLock lock(mLock);
368
369 nsCOMPtr<nsIFastLoadWriteControl> control(do_QueryInterface(mOutputStream));
370 if (!control)
371 return NS_ERROR_NOT_AVAILABLE;
372
373 return control->AddDependency(aFile);
374}
375
376NS_IMETHODIMP
377nsFastLoadService::ComputeChecksum(nsIFile* aFile,
378 nsIFastLoadReadControl* aControl,
379 PRUint32 *aChecksum)
380{
381 nsCAutoString path;
382 nsresult rv = aFile->GetNativePath(path);
383 if (NS_FAILED(rv))
384 return rv;
385
386 nsCStringKey key(path);
387 PRUint32 checksum = NS_PTR_TO_INT32(mChecksumTable.Get(&key));
388 if (checksum) {
389 *aChecksum = checksum;
390 return NS_OK;
391 }
392
393 rv = aControl->ComputeChecksum(&checksum);
394 if (NS_FAILED(rv))
395 return rv;
396
397 mChecksumTable.Put(&key, NS_INT32_TO_PTR(checksum));
398 *aChecksum = checksum;
399 return NS_OK;
400}
401
402NS_IMETHODIMP
403nsFastLoadService::CacheChecksum(nsIFile* aFile, nsIObjectOutputStream *aStream)
404{
405 nsCOMPtr<nsIFastLoadFileControl> control(do_QueryInterface(aStream));
406 if (!control)
407 return NS_ERROR_FAILURE;
408
409 PRUint32 checksum;
410 nsresult rv = control->GetChecksum(&checksum);
411 if (NS_FAILED(rv))
412 return rv;
413
414 nsCAutoString path;
415 rv = aFile->GetNativePath(path);
416 if (NS_FAILED(rv))
417 return rv;
418
419 nsCStringKey key(path);
420 mChecksumTable.Put(&key, NS_INT32_TO_PTR(checksum));
421 return NS_OK;
422}
423
424struct nsFastLoadPtrEntry : public PLDHashEntryHdr {
425 nsISupports** mPtrAddr; // key, must come first for PL_DHashGetStubOps
426 PRUint32 mOffset;
427};
428
429NS_IMETHODIMP
430nsFastLoadService::GetFastLoadReferent(nsISupports* *aPtrAddr)
431{
432 NS_ASSERTION(*aPtrAddr == nsnull,
433 "aPtrAddr doesn't point to null nsFastLoadPtr<T>::mRawAddr?");
434
435 nsAutoLock lock(mLock);
436 if (!mFastLoadPtrMap || !mInputStream)
437 return NS_OK;
438
439 nsFastLoadPtrEntry* entry =
440 NS_STATIC_CAST(nsFastLoadPtrEntry*,
441 PL_DHashTableOperate(mFastLoadPtrMap, aPtrAddr,
442 PL_DHASH_LOOKUP));
443 if (PL_DHASH_ENTRY_IS_FREE(entry))
444 return NS_OK;
445
446 nsresult rv;
447 nsCOMPtr<nsISeekableStream> seekable(do_QueryInterface(mInputStream));
448
449 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, entry->mOffset);
450 if (NS_FAILED(rv))
451 return rv;
452
453 rv = mInputStream->ReadObject(PR_TRUE, aPtrAddr);
454 if (NS_FAILED(rv))
455 return rv;
456
457 // Shrink the table if half the entries are removed sentinels.
458 PRUint32 size = PL_DHASH_TABLE_SIZE(mFastLoadPtrMap);
459 if (mFastLoadPtrMap->removedCount >= (size >> 2))
460 PL_DHashTableOperate(mFastLoadPtrMap, entry, PL_DHASH_REMOVE);
461 else
462 PL_DHashTableRawRemove(mFastLoadPtrMap, entry);
463
464 return NS_OK;
465}
466
467NS_IMETHODIMP
468nsFastLoadService::ReadFastLoadPtr(nsIObjectInputStream* aInputStream,
469 nsISupports* *aPtrAddr)
470{
471 // nsFastLoadPtrs self-construct to null, so if we have a non-null value
472 // in our inout parameter, we must have been read already, alright!
473 if (*aPtrAddr)
474 return NS_OK;
475
476 nsresult rv;
477 PRUint32 nextOffset;
478 nsAutoLock lock(mLock);
479
480 rv = aInputStream->Read32(&nextOffset);
481 if (NS_FAILED(rv))
482 return rv;
483
484 nsCOMPtr<nsISeekableStream> seekable(do_QueryInterface(aInputStream));
485 if (!seekable)
486 return NS_ERROR_FAILURE;
487
488 PRInt64 thisOffset;
489 rv = seekable->Tell(&thisOffset);
490 if (NS_FAILED(rv))
491 return rv;
492
493 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, nextOffset);
494 if (NS_FAILED(rv))
495 return rv;
496
497 if (!mFastLoadPtrMap) {
498 mFastLoadPtrMap = PL_NewDHashTable(PL_DHashGetStubOps(), this,
499 sizeof(nsFastLoadPtrEntry),
500 PL_DHASH_MIN_SIZE);
501 if (!mFastLoadPtrMap)
502 return NS_ERROR_OUT_OF_MEMORY;
503 }
504
505 nsFastLoadPtrEntry* entry =
506 NS_STATIC_CAST(nsFastLoadPtrEntry*,
507 PL_DHashTableOperate(mFastLoadPtrMap, aPtrAddr,
508 PL_DHASH_ADD));
509 NS_ASSERTION(entry->mPtrAddr == nsnull, "duplicate nsFastLoadPtr?!");
510
511 entry->mPtrAddr = aPtrAddr;
512
513 LL_L2UI(entry->mOffset, thisOffset);
514 return NS_OK;
515}
516
517NS_IMETHODIMP
518nsFastLoadService::WriteFastLoadPtr(nsIObjectOutputStream* aOutputStream,
519 nsISupports* aObject)
520{
521 NS_ASSERTION(aObject != nsnull, "writing an unread nsFastLoadPtr?!");
522 if (!aObject)
523 return NS_ERROR_UNEXPECTED;
524
525 nsresult rv;
526 nsAutoLock lock(mLock); // serialize writes to aOutputStream
527
528 nsCOMPtr<nsISeekableStream> seekable(do_QueryInterface(aOutputStream));
529 if (!seekable)
530 return NS_ERROR_FAILURE;
531
532 PRInt64 saveOffset;
533 rv = seekable->Tell(&saveOffset);
534 if (NS_FAILED(rv))
535 return rv;
536
537 rv = aOutputStream->Write32(0); // nextOffset placeholder
538 if (NS_FAILED(rv))
539 return rv;
540
541 rv = aOutputStream->WriteObject(aObject, PR_TRUE);
542 if (NS_FAILED(rv))
543 return rv;
544
545 PRInt64 nextOffset;
546 rv = seekable->Tell(&nextOffset);
547 if (NS_FAILED(rv))
548 return rv;
549
550 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset);
551 if (NS_FAILED(rv))
552 return rv;
553
554 rv = aOutputStream->Write32(nextOffset);
555 if (NS_FAILED(rv))
556 return rv;
557
558 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, nextOffset);
559 if (NS_FAILED(rv))
560 return rv;
561
562 return NS_OK;
563}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use