~ubuntu-branches/ubuntu/gutsy/virtualbox-ose/gutsy

« back to all changes in this revision

Viewing changes to src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-09-08 16:44:58 UTC
  • Revision ID: james.westby@ubuntu.com-20070908164458-wao29470vqtr8ksy
Tags: upstream-1.5.0-dfsg2
ImportĀ upstreamĀ versionĀ 1.5.0-dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
61
PR_IMPLEMENT_DATA(nsIFastLoadService*) gFastLoadService_ = nsnull;
 
62
 
 
63
NS_IMPL_THREADSAFE_ISUPPORTS1(nsFastLoadService, nsIFastLoadService)
 
64
 
 
65
nsFastLoadService::nsFastLoadService()
 
66
  : mLock(nsnull),
 
67
    mFastLoadPtrMap(nsnull),
 
68
    mDirection(0)
 
69
{
 
70
    NS_ASSERTION(gFastLoadService_ == nsnull, "double FastLoadService init?");
 
71
    gFastLoadService_ = this;
 
72
}
 
73
 
 
74
nsFastLoadService::~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
 
 
89
NS_IMETHODIMP
 
90
nsFastLoadService::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
 
 
134
nsresult
 
135
nsFastLoadService::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
 
 
157
NS_IMETHODIMP
 
158
nsFastLoadService::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
 
 
173
NS_IMETHODIMP
 
174
nsFastLoadService::NewOutputStream(nsIOutputStream* aDestStream,
 
175
                                   nsIObjectOutputStream* *aResult)
 
176
{
 
177
    nsAutoLock lock(mLock);
 
178
 
 
179
    return NS_NewFastLoadFileWriter(aResult, aDestStream, mFileIO);
 
180
}
 
181
 
 
182
NS_IMETHODIMP
 
183
nsFastLoadService::GetInputStream(nsIObjectInputStream* *aResult)
 
184
{
 
185
    NS_IF_ADDREF(*aResult = mInputStream);
 
186
    return NS_OK;
 
187
}
 
188
 
 
189
NS_IMETHODIMP
 
190
nsFastLoadService::SetInputStream(nsIObjectInputStream* aStream)
 
191
{
 
192
    nsAutoLock lock(mLock);
 
193
    mInputStream = aStream;
 
194
    return NS_OK;
 
195
}
 
196
 
 
197
NS_IMETHODIMP
 
198
nsFastLoadService::GetOutputStream(nsIObjectOutputStream* *aResult)
 
199
{
 
200
    NS_IF_ADDREF(*aResult = mOutputStream);
 
201
    return NS_OK;
 
202
}
 
203
 
 
204
NS_IMETHODIMP
 
205
nsFastLoadService::SetOutputStream(nsIObjectOutputStream* aStream)
 
206
{
 
207
    nsAutoLock lock(mLock);
 
208
    mOutputStream = aStream;
 
209
    return NS_OK;
 
210
}
 
211
 
 
212
NS_IMETHODIMP
 
213
nsFastLoadService::GetFileIO(nsIFastLoadFileIO* *aResult)
 
214
{
 
215
    NS_IF_ADDREF(*aResult = mFileIO);
 
216
    return NS_OK;
 
217
}
 
218
 
 
219
NS_IMETHODIMP
 
220
nsFastLoadService::SetFileIO(nsIFastLoadFileIO* aFileIO)
 
221
{
 
222
    nsAutoLock lock(mLock);
 
223
    mFileIO = aFileIO;
 
224
    return NS_OK;
 
225
}
 
226
 
 
227
NS_IMETHODIMP
 
228
nsFastLoadService::GetDirection(PRInt32 *aResult)
 
229
{
 
230
    *aResult = mDirection;
 
231
    return NS_OK;
 
232
}
 
233
 
 
234
NS_IMETHODIMP
 
235
nsFastLoadService::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
 
 
258
NS_IMETHODIMP
 
259
nsFastLoadService::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
 
 
309
NS_IMETHODIMP
 
310
nsFastLoadService::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
 
 
339
NS_IMETHODIMP
 
340
nsFastLoadService::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
 
 
364
NS_IMETHODIMP
 
365
nsFastLoadService::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
 
 
376
NS_IMETHODIMP
 
377
nsFastLoadService::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
 
 
402
NS_IMETHODIMP
 
403
nsFastLoadService::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
 
 
424
struct nsFastLoadPtrEntry : public PLDHashEntryHdr {
 
425
    nsISupports** mPtrAddr;     // key, must come first for PL_DHashGetStubOps
 
426
    PRUint32      mOffset;
 
427
};
 
428
 
 
429
NS_IMETHODIMP
 
430
nsFastLoadService::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
 
 
467
NS_IMETHODIMP
 
468
nsFastLoadService::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
 
 
517
NS_IMETHODIMP
 
518
nsFastLoadService::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
}