VirtualBox

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

Last change on this file since 95259 was 49491, checked in by vboxsync, 11 years ago

libs/xpcom: fixed a bunch of pointer size vs. integer size warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.2 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#ifndef VBOX
398 mChecksumTable.Put(&key, NS_INT32_TO_PTR(checksum));
399#else /* VBOX */
400 mChecksumTable.Put(&key, (void *)(uintptr_t)checksum);
401#endif /* VBOX */
402 *aChecksum = checksum;
403 return NS_OK;
404}
405
406NS_IMETHODIMP
407nsFastLoadService::CacheChecksum(nsIFile* aFile, nsIObjectOutputStream *aStream)
408{
409 nsCOMPtr<nsIFastLoadFileControl> control(do_QueryInterface(aStream));
410 if (!control)
411 return NS_ERROR_FAILURE;
412
413 PRUint32 checksum;
414 nsresult rv = control->GetChecksum(&checksum);
415 if (NS_FAILED(rv))
416 return rv;
417
418 nsCAutoString path;
419 rv = aFile->GetNativePath(path);
420 if (NS_FAILED(rv))
421 return rv;
422
423 nsCStringKey key(path);
424#ifndef VBOX
425 mChecksumTable.Put(&key, NS_INT32_TO_PTR(checksum));
426#else /* VBOX */
427 mChecksumTable.Put(&key, (void *)(uintptr_t)checksum);
428#endif /* VBOX */
429 return NS_OK;
430}
431
432struct nsFastLoadPtrEntry : public PLDHashEntryHdr {
433 nsISupports** mPtrAddr; // key, must come first for PL_DHashGetStubOps
434 PRUint32 mOffset;
435};
436
437NS_IMETHODIMP
438nsFastLoadService::GetFastLoadReferent(nsISupports* *aPtrAddr)
439{
440 NS_ASSERTION(*aPtrAddr == nsnull,
441 "aPtrAddr doesn't point to null nsFastLoadPtr<T>::mRawAddr?");
442
443 nsAutoLock lock(mLock);
444 if (!mFastLoadPtrMap || !mInputStream)
445 return NS_OK;
446
447 nsFastLoadPtrEntry* entry =
448 NS_STATIC_CAST(nsFastLoadPtrEntry*,
449 PL_DHashTableOperate(mFastLoadPtrMap, aPtrAddr,
450 PL_DHASH_LOOKUP));
451 if (PL_DHASH_ENTRY_IS_FREE(entry))
452 return NS_OK;
453
454 nsresult rv;
455 nsCOMPtr<nsISeekableStream> seekable(do_QueryInterface(mInputStream));
456
457 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, entry->mOffset);
458 if (NS_FAILED(rv))
459 return rv;
460
461 rv = mInputStream->ReadObject(PR_TRUE, aPtrAddr);
462 if (NS_FAILED(rv))
463 return rv;
464
465 // Shrink the table if half the entries are removed sentinels.
466 PRUint32 size = PL_DHASH_TABLE_SIZE(mFastLoadPtrMap);
467 if (mFastLoadPtrMap->removedCount >= (size >> 2))
468 PL_DHashTableOperate(mFastLoadPtrMap, entry, PL_DHASH_REMOVE);
469 else
470 PL_DHashTableRawRemove(mFastLoadPtrMap, entry);
471
472 return NS_OK;
473}
474
475NS_IMETHODIMP
476nsFastLoadService::ReadFastLoadPtr(nsIObjectInputStream* aInputStream,
477 nsISupports* *aPtrAddr)
478{
479 // nsFastLoadPtrs self-construct to null, so if we have a non-null value
480 // in our inout parameter, we must have been read already, alright!
481 if (*aPtrAddr)
482 return NS_OK;
483
484 nsresult rv;
485 PRUint32 nextOffset;
486 nsAutoLock lock(mLock);
487
488 rv = aInputStream->Read32(&nextOffset);
489 if (NS_FAILED(rv))
490 return rv;
491
492 nsCOMPtr<nsISeekableStream> seekable(do_QueryInterface(aInputStream));
493 if (!seekable)
494 return NS_ERROR_FAILURE;
495
496 PRInt64 thisOffset;
497 rv = seekable->Tell(&thisOffset);
498 if (NS_FAILED(rv))
499 return rv;
500
501 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, nextOffset);
502 if (NS_FAILED(rv))
503 return rv;
504
505 if (!mFastLoadPtrMap) {
506 mFastLoadPtrMap = PL_NewDHashTable(PL_DHashGetStubOps(), this,
507 sizeof(nsFastLoadPtrEntry),
508 PL_DHASH_MIN_SIZE);
509 if (!mFastLoadPtrMap)
510 return NS_ERROR_OUT_OF_MEMORY;
511 }
512
513 nsFastLoadPtrEntry* entry =
514 NS_STATIC_CAST(nsFastLoadPtrEntry*,
515 PL_DHashTableOperate(mFastLoadPtrMap, aPtrAddr,
516 PL_DHASH_ADD));
517 NS_ASSERTION(entry->mPtrAddr == nsnull, "duplicate nsFastLoadPtr?!");
518
519 entry->mPtrAddr = aPtrAddr;
520
521 LL_L2UI(entry->mOffset, thisOffset);
522 return NS_OK;
523}
524
525NS_IMETHODIMP
526nsFastLoadService::WriteFastLoadPtr(nsIObjectOutputStream* aOutputStream,
527 nsISupports* aObject)
528{
529 NS_ASSERTION(aObject != nsnull, "writing an unread nsFastLoadPtr?!");
530 if (!aObject)
531 return NS_ERROR_UNEXPECTED;
532
533 nsresult rv;
534 nsAutoLock lock(mLock); // serialize writes to aOutputStream
535
536 nsCOMPtr<nsISeekableStream> seekable(do_QueryInterface(aOutputStream));
537 if (!seekable)
538 return NS_ERROR_FAILURE;
539
540 PRInt64 saveOffset;
541 rv = seekable->Tell(&saveOffset);
542 if (NS_FAILED(rv))
543 return rv;
544
545 rv = aOutputStream->Write32(0); // nextOffset placeholder
546 if (NS_FAILED(rv))
547 return rv;
548
549 rv = aOutputStream->WriteObject(aObject, PR_TRUE);
550 if (NS_FAILED(rv))
551 return rv;
552
553 PRInt64 nextOffset;
554 rv = seekable->Tell(&nextOffset);
555 if (NS_FAILED(rv))
556 return rv;
557
558 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset);
559 if (NS_FAILED(rv))
560 return rv;
561
562 rv = aOutputStream->Write32(nextOffset);
563 if (NS_FAILED(rv))
564 return rv;
565
566 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, nextOffset);
567 if (NS_FAILED(rv))
568 return rv;
569
570 return NS_OK;
571}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette