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

« back to all changes in this revision

Viewing changes to src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.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.org 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) 1998
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *   Pierre Phaneuf <pp@ludusdesign.com>
 
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 "nsIFileStream.h"
 
40
#include "nsFileSpec.h"
 
41
#include "nsCOMPtr.h"
 
42
 
 
43
#include "prerror.h"
 
44
 
 
45
#include "nsSegmentedBuffer.h"
 
46
#include "nsInt64.h"
 
47
 
 
48
#ifdef XP_MAC
 
49
#include "pprio.h" // To get PR_ImportFile
 
50
#else
 
51
#include "prio.h"
 
52
#endif
 
53
 
 
54
#ifdef XP_MAC
 
55
#include <Errors.h>
 
56
#include <iostream>
 
57
#endif
 
58
 
 
59
//========================================================================================
 
60
class FileImpl
 
61
    : public nsIRandomAccessStore
 
62
    , public nsIFileSpecOutputStream
 
63
    , public nsIFileSpecInputStream
 
64
    , public nsIOpenFile
 
65
//========================================================================================
 
66
{
 
67
    public:
 
68
                                        FileImpl(PRFileDesc* inDesc);
 
69
                                        FileImpl(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode);
 
70
 
 
71
        // nsISupports interface
 
72
                                        NS_DECL_ISUPPORTS
 
73
 
 
74
        // nsIOpenFile interface
 
75
        NS_IMETHOD                      Open(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode);
 
76
        NS_IMETHOD                      Close();
 
77
        NS_IMETHOD                      GetIsOpen(PRBool* outOpen);
 
78
 
 
79
        // nsIInputStream interface
 
80
        NS_IMETHOD                      Available(PRUint32 *aLength);
 
81
        NS_IMETHOD                      Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount);
 
82
        NS_IMETHOD                      ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval);
 
83
        NS_IMETHOD                      IsNonBlocking(PRBool *aNonBlocking);
 
84
 
 
85
        // nsIOutputStream interface
 
86
        NS_IMETHOD                      Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount);
 
87
        NS_IMETHOD                      Flush();
 
88
        NS_IMETHOD                      WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval);
 
89
        NS_IMETHOD                      WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval);
 
90
 
 
91
        // nsIRandomAccessStore interface
 
92
        NS_DECL_NSISEEKABLESTREAM
 
93
        NS_IMETHOD                      GetAtEOF(PRBool* outAtEOF);
 
94
        NS_IMETHOD                      SetAtEOF(PRBool inAtEOF);
 
95
 
 
96
    private:
 
97
 
 
98
                                        ~FileImpl();        
 
99
 
 
100
    protected:
 
101
    
 
102
        enum {
 
103
            kOuputBufferSegmentSize    = 4096,
 
104
            kOuputBufferMaxSize        = 4096
 
105
        };
 
106
        
 
107
        nsresult                        InternalFlush(PRBool syncFile);
 
108
        nsresult                        AllocateBuffers(PRUint32 segmentSize, PRUint32 maxSize);
 
109
 
 
110
        PRFileDesc*                     mFileDesc;
 
111
        int                             mNSPRMode;
 
112
        PRBool                          mFailed;
 
113
        PRBool                          mEOF;
 
114
        PRInt32                         mLength;
 
115
 
 
116
        PRBool                          mGotBuffers;
 
117
        nsSegmentedBuffer               mOutBuffer;
 
118
        char*                           mWriteCursor;
 
119
        char*                           mWriteLimit;
 
120
 
 
121
}; // class FileImpl
 
122
 
 
123
NS_IMPL_RELEASE(FileImpl)
 
124
NS_IMPL_ADDREF(FileImpl)
 
125
 
 
126
NS_IMPL_QUERY_HEAD(FileImpl)
 
127
  NS_IMPL_QUERY_BODY(nsIOpenFile)
 
128
  NS_IMPL_QUERY_BODY(nsISeekableStream)
 
129
  NS_IMPL_QUERY_BODY(nsIRandomAccessStore)
 
130
  NS_IMPL_QUERY_BODY(nsIOutputStream)
 
131
  NS_IMPL_QUERY_BODY(nsIInputStream)
 
132
  NS_IMPL_QUERY_BODY(nsIFileSpecInputStream)
 
133
  NS_IMPL_QUERY_BODY(nsIFileSpecOutputStream)
 
134
NS_IMPL_QUERY_TAIL(nsIOutputStream)
 
135
 
 
136
 
 
137
//----------------------------------------------------------------------------------------
 
138
FileImpl::FileImpl(PRFileDesc* inDesc)
 
139
//----------------------------------------------------------------------------------------
 
140
: mFileDesc(inDesc)
 
141
, mNSPRMode(0)
 
142
, mFailed(PR_FALSE)
 
143
, mEOF(PR_FALSE)
 
144
, mLength(-1)
 
145
, mGotBuffers(PR_FALSE)
 
146
{
 
147
    mWriteCursor = nsnull;
 
148
    mWriteLimit  = nsnull;
 
149
}
 
150
 
 
151
 
 
152
//----------------------------------------------------------------------------------------
 
153
FileImpl::FileImpl(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode)
 
154
//----------------------------------------------------------------------------------------
 
155
: mFileDesc(nsnull)
 
156
, mNSPRMode(-1)
 
157
, mEOF(PR_FALSE)
 
158
, mLength(-1)
 
159
, mGotBuffers(PR_FALSE)
 
160
{
 
161
    mWriteCursor = nsnull;
 
162
    mWriteLimit  = nsnull;
 
163
 
 
164
    nsresult rv = Open(inFile, nsprMode, accessMode);           // this sets nsprMode
 
165
    
 
166
    if (NS_FAILED(rv))
 
167
    {
 
168
        mFailed = PR_TRUE;
 
169
#if DEBUG
 
170
        char *fileName = inFile.GetLeafName();
 
171
        printf("Opening file %s failed\n", fileName);
 
172
        nsCRT::free(fileName);
 
173
#endif
 
174
    }
 
175
    else
 
176
    {
 
177
        mFailed = PR_FALSE;
 
178
    }
 
179
}
 
180
 
 
181
//----------------------------------------------------------------------------------------
 
182
FileImpl::~FileImpl()
 
183
//----------------------------------------------------------------------------------------
 
184
{
 
185
    nsresult  rv = Close();
 
186
    NS_ASSERTION(NS_SUCCEEDED(rv), "Close failed");
 
187
}
 
188
 
 
189
 
 
190
//----------------------------------------------------------------------------------------
 
191
NS_IMETHODIMP FileImpl::Open(
 
192
    const nsFileSpec& inFile,
 
193
    int nsprMode,
 
194
    PRIntn accessMode)
 
195
//----------------------------------------------------------------------------------------
 
196
{
 
197
    if (mFileDesc)
 
198
        if ((nsprMode & mNSPRMode) == nsprMode)
 
199
            return NS_OK;
 
200
        else
 
201
            return NS_FILE_RESULT(PR_ILLEGAL_ACCESS_ERROR);
 
202
        
 
203
    const int nspr_modes[]={
 
204
        PR_WRONLY | PR_CREATE_FILE,
 
205
        PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
 
206
        PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
 
207
        PR_RDONLY,
 
208
        PR_RDONLY | PR_APPEND,
 
209
        PR_RDWR | PR_CREATE_FILE,
 
210
        PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE,
 
211
//      "wb",
 
212
//      "ab", 
 
213
//      "wb",
 
214
//      "rb",
 
215
//      "r+b",
 
216
//      "w+b",
 
217
        0 };
 
218
    const int* currentLegalMode = nspr_modes;
 
219
    while (*currentLegalMode && nsprMode != *currentLegalMode)
 
220
        ++currentLegalMode;
 
221
    if (!*currentLegalMode) 
 
222
        return NS_FILE_RESULT(PR_ILLEGAL_ACCESS_ERROR);
 
223
 
 
224
#ifdef XP_MAC
 
225
     // Use the file spec to open the file, because one path can be common to
 
226
     // several files on the Macintosh (you can have several volumes with the
 
227
     // same name, see).
 
228
    mFileDesc = 0;
 
229
    OSErr err = inFile.Error();
 
230
    if (err != noErr)
 
231
      if (err != fnfErr || !(nsprMode & PR_CREATE_FILE))
 
232
          return NS_FILE_RESULT(inFile.Error());
 
233
    err = noErr;
 
234
#if DEBUG
 
235
    const OSType kCreator = 'CWIE';
 
236
#else
 
237
    const OSType kCreator = 'MOSS';
 
238
#endif
 
239
    // Resolve the alias to the original file.
 
240
    nsFileSpec original = inFile;
 
241
    PRBool ignoredResult;
 
242
    original.ResolveSymlink(ignoredResult);
 
243
    const FSSpec& spec = original.operator const FSSpec&();
 
244
    if (nsprMode & PR_CREATE_FILE) {
 
245
        // In order to get the right file type/creator, do it with an nsILocalFileMac
 
246
        // Don't propagate any errors in doing this. If any error, just use FSpCreate.
 
247
        FSSpec nonConstSpec = spec;
 
248
        nsCOMPtr<nsILocalFileMac> macFile;
 
249
        nsresult res = NS_NewLocalFileWithFSSpec(&nonConstSpec, PR_FALSE, getter_AddRefs(macFile));
 
250
        if (NS_SUCCEEDED(res)) {
 
251
            nsCOMPtr<nsIFile> asFile(do_QueryInterface(macFile, &res));
 
252
            if (NS_SUCCEEDED(res)) {
 
253
                res = asFile->Create(nsIFile::NORMAL_FILE_TYPE, 0);
 
254
                if (res == NS_ERROR_FILE_ALREADY_EXISTS)
 
255
                    res = NS_OK;
 
256
            }
 
257
        }
 
258
        if (NS_FAILED(res))
 
259
            err = FSpCreate(&spec, kCreator, 'TEXT', 0);
 
260
    }
 
261
 
 
262
    if (err == dupFNErr)
 
263
        err = noErr;
 
264
    if (err != noErr)
 
265
        return NS_FILE_RESULT(err);
 
266
    
 
267
    SInt8 perm;
 
268
    if (nsprMode & PR_RDWR)
 
269
       perm = fsRdWrPerm;
 
270
    else if (nsprMode & PR_WRONLY)
 
271
       perm = fsWrPerm;
 
272
    else
 
273
       perm = fsRdPerm;
 
274
 
 
275
    short refnum;
 
276
    err = FSpOpenDF(&spec, perm, &refnum);
 
277
 
 
278
    if (err == noErr && (nsprMode & PR_TRUNCATE))
 
279
        err = ::SetEOF(refnum, 0);
 
280
    if (err == noErr && (nsprMode & PR_APPEND))
 
281
        err = SetFPos(refnum, fsFromLEOF, 0);
 
282
    if (err != noErr)
 
283
        return NS_FILE_RESULT(err);
 
284
 
 
285
    if ((mFileDesc = PR_ImportFile(refnum)) == 0)
 
286
        return NS_FILE_RESULT(PR_GetError());
 
287
#else
 
288
    //    Platforms other than Macintosh...
 
289
    //  Another bug in NSPR: Mac PR_Open assumes a unix style path, but Win PR_Open assumes
 
290
    //  a windows path.
 
291
    if ((mFileDesc = PR_Open((const char*)nsFileSpec(inFile), nsprMode, accessMode)) == 0)
 
292
        return NS_FILE_RESULT(PR_GetError());
 
293
#endif
 
294
     mNSPRMode = nsprMode;
 
295
     mLength = PR_Available(mFileDesc);
 
296
     return NS_OK;
 
297
} // FileImpl::Open
 
298
 
 
299
 
 
300
//----------------------------------------------------------------------------------------
 
301
NS_IMETHODIMP FileImpl::Available(PRUint32 *aLength)
 
302
//----------------------------------------------------------------------------------------
 
303
{
 
304
    NS_PRECONDITION(aLength != nsnull, "null ptr");
 
305
    if (!aLength)
 
306
        return NS_ERROR_NULL_POINTER;
 
307
    if (mLength < 0)
 
308
        return NS_ERROR_UNEXPECTED;
 
309
    *aLength = mLength;
 
310
    return NS_OK;
 
311
}
 
312
 
 
313
//----------------------------------------------------------------------------------------
 
314
NS_IMETHODIMP FileImpl::GetIsOpen(PRBool* outOpen)
 
315
//----------------------------------------------------------------------------------------
 
316
{
 
317
    *outOpen = (mFileDesc != nsnull && !mFailed);
 
318
    return NS_OK;
 
319
}
 
320
 
 
321
//----------------------------------------------------------------------------------------
 
322
NS_IMETHODIMP FileImpl::Seek(PRInt32 whence, PRInt64 offset)
 
323
//----------------------------------------------------------------------------------------
 
324
{
 
325
    if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) 
 
326
       return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
 
327
    mFailed = PR_FALSE; // reset on a seek.
 
328
    mEOF = PR_FALSE; // reset on a seek.
 
329
    
 
330
    // To avoid corruption, we flush during a seek. see bug number 18949
 
331
    InternalFlush(PR_FALSE);
 
332
 
 
333
    nsInt64 position = PR_Seek64(mFileDesc, 0, PR_SEEK_CUR);
 
334
    nsInt64 available = PR_Available64(mFileDesc);
 
335
    nsInt64 fileSize = position + available;
 
336
    nsInt64 newPosition = offset;
 
337
    switch (whence)
 
338
    {
 
339
        case NS_SEEK_CUR: newPosition += position; break;
 
340
        case NS_SEEK_SET: ; break;
 
341
        case NS_SEEK_END: newPosition += fileSize; break;
 
342
    }
 
343
    const nsInt64 zero = 0;
 
344
    if (newPosition < zero)
 
345
    {
 
346
        newPosition = 0;
 
347
        mFailed = PR_TRUE;
 
348
    }
 
349
    if (newPosition >= fileSize) // nb: not "else if".
 
350
    {
 
351
        newPosition = fileSize;
 
352
        mEOF = PR_TRUE;
 
353
    }
 
354
    if (PR_Seek64(mFileDesc, newPosition, PR_SEEK_SET) < 0)
 
355
        mFailed = PR_TRUE;
 
356
    return NS_OK;
 
357
} // FileImpl::Seek
 
358
 
 
359
 
 
360
//----------------------------------------------------------------------------------------
 
361
NS_IMETHODIMP FileImpl::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount)
 
362
//----------------------------------------------------------------------------------------
 
363
{
 
364
    NS_PRECONDITION(aBuf != nsnull, "null ptr");
 
365
    if (!aBuf)
 
366
        return NS_ERROR_NULL_POINTER;
 
367
    NS_PRECONDITION(aReadCount != nsnull, "null ptr");
 
368
    if (!aReadCount)
 
369
        return NS_ERROR_NULL_POINTER;
 
370
    if (!mFileDesc)
 
371
        return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
 
372
    if (mFailed)
 
373
        return NS_ERROR_FAILURE;
 
374
    PRInt32 bytesRead = PR_Read(mFileDesc, aBuf, aCount);
 
375
    if (bytesRead < 0)
 
376
    {
 
377
        *aReadCount = 0;
 
378
        mFailed = PR_TRUE;
 
379
        return NS_FILE_RESULT(PR_GetError());
 
380
    }
 
381
    else if (bytesRead == 0)
 
382
    {
 
383
        mEOF = PR_TRUE;
 
384
    }
 
385
    *aReadCount = bytesRead;
 
386
    return NS_OK;
 
387
}
 
388
 
 
389
NS_IMETHODIMP
 
390
FileImpl::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval)
 
391
{
 
392
    NS_NOTREACHED("ReadSegments");
 
393
    return NS_ERROR_NOT_IMPLEMENTED;
 
394
}
 
395
 
 
396
//----------------------------------------------------------------------------------------
 
397
NS_IMETHODIMP FileImpl::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount)
 
398
//----------------------------------------------------------------------------------------
 
399
{
 
400
    NS_PRECONDITION(aBuf != nsnull, "null ptr");
 
401
    NS_PRECONDITION(aWriteCount != nsnull, "null ptr");
 
402
                    
 
403
    *aWriteCount = 0;
 
404
 
 
405
#ifdef XP_MAC
 
406
    // Calling PR_Write on stdout is sure suicide.
 
407
    if (mFileDesc == PR_STDOUT || mFileDesc == PR_STDERR)
 
408
    {
 
409
        std::cout.write(aBuf, aCount);
 
410
        *aWriteCount = aCount;
 
411
        return NS_OK;
 
412
    }
 
413
#endif
 
414
    if (!mFileDesc)
 
415
        return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
 
416
    if (mFailed)
 
417
       return NS_ERROR_FAILURE;
 
418
 
 
419
    if (!mGotBuffers)
 
420
    {
 
421
        nsresult rv = AllocateBuffers(kOuputBufferSegmentSize, kOuputBufferMaxSize);
 
422
        if (NS_FAILED(rv))
 
423
          return rv;        // try to write non-buffered?
 
424
    }
 
425
    
 
426
    PRUint32 bufOffset = 0;
 
427
    PRUint32 currentWrite = 0;
 
428
    while (aCount > 0) 
 
429
    {
 
430
        if (mWriteCursor == nsnull || mWriteCursor == mWriteLimit)
 
431
        {
 
432
            char* seg = mOutBuffer.AppendNewSegment();
 
433
            if (seg == nsnull) 
 
434
            {
 
435
                // buffer is full, try again
 
436
                InternalFlush(PR_FALSE);
 
437
                seg = mOutBuffer.AppendNewSegment();
 
438
                if (seg == nsnull)
 
439
                    return NS_ERROR_OUT_OF_MEMORY;
 
440
            }
 
441
            mWriteCursor = seg;
 
442
            mWriteLimit  = seg + mOutBuffer.GetSegmentSize();
 
443
        }
 
444
        
 
445
        // move
 
446
        currentWrite = mWriteLimit - mWriteCursor;
 
447
        
 
448
        if (aCount < currentWrite)
 
449
            currentWrite = aCount;
 
450
 
 
451
        memcpy(mWriteCursor, (aBuf + bufOffset), currentWrite);
 
452
        
 
453
        mWriteCursor += currentWrite;  
 
454
        
 
455
        aCount    -= currentWrite;
 
456
        bufOffset += currentWrite;
 
457
        *aWriteCount += currentWrite;
 
458
    }
 
459
    
 
460
    return NS_OK;
 
461
}
 
462
 
 
463
static NS_METHOD
 
464
nsWriteSegmentToFile(nsIInputStream* in,
 
465
                     void* closure,
 
466
                     const char* fromRawSegment,
 
467
                     PRUint32 toOffset,
 
468
                     PRUint32 count,
 
469
                     PRUint32 *writeCount)
 
470
{
 
471
    NS_NOTREACHED("nsWriteSegmentToFile");
 
472
    return NS_ERROR_NOT_IMPLEMENTED;
 
473
}
 
474
 
 
475
NS_IMETHODIMP 
 
476
FileImpl::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *result)
 
477
{
 
478
    return inStr->ReadSegments(nsWriteSegmentToFile, nsnull, count, result);
 
479
}
 
480
 
 
481
NS_IMETHODIMP 
 
482
FileImpl::WriteSegments(nsReadSegmentFun reader, void * closure, 
 
483
                        PRUint32 count, PRUint32 *result)
 
484
{
 
485
    NS_NOTREACHED("WriteSegments");
 
486
    return NS_ERROR_NOT_IMPLEMENTED;
 
487
}
 
488
 
 
489
NS_IMETHODIMP
 
490
FileImpl::IsNonBlocking(PRBool *aNonBlocking)
 
491
{
 
492
    *aNonBlocking = PR_FALSE;
 
493
    return NS_OK;
 
494
}
 
495
 
 
496
//----------------------------------------------------------------------------------------
 
497
NS_IMETHODIMP FileImpl::Tell(PRInt64* outWhere)
 
498
//----------------------------------------------------------------------------------------
 
499
{
 
500
    if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) 
 
501
       return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
 
502
    *outWhere = PR_Seek64(mFileDesc, 0, PR_SEEK_CUR);
 
503
    return NS_OK;
 
504
} // FileImpl::Tell
 
505
 
 
506
//----------------------------------------------------------------------------------------
 
507
NS_IMETHODIMP FileImpl::Close()
 
508
//----------------------------------------------------------------------------------------
 
509
{
 
510
    if ((mNSPRMode & PR_RDONLY) == 0)
 
511
        InternalFlush(PR_FALSE);
 
512
 
 
513
    if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) 
 
514
       return NS_OK;
 
515
    if (PR_Close(mFileDesc) == PR_SUCCESS)
 
516
        mFileDesc = 0;
 
517
    else
 
518
        return NS_FILE_RESULT(PR_GetError());
 
519
    return NS_OK;
 
520
} // FileImpl::close
 
521
 
 
522
//----------------------------------------------------------------------------------------
 
523
NS_IMETHODIMP FileImpl::Flush()
 
524
//----------------------------------------------------------------------------------------
 
525
{
 
526
  // for external callers, this will do a Sync as well as flush buffers.
 
527
  return InternalFlush(PR_TRUE);
 
528
} // FileImpl::flush
 
529
 
 
530
 
 
531
//----------------------------------------------------------------------------------------
 
532
NS_IMETHODIMP FileImpl::GetAtEOF(PRBool* outAtEOF)
 
533
//----------------------------------------------------------------------------------------
 
534
{
 
535
  *outAtEOF = mEOF;
 
536
  return NS_OK;
 
537
}
 
538
 
 
539
 
 
540
//----------------------------------------------------------------------------------------
 
541
NS_IMETHODIMP FileImpl::SetAtEOF(PRBool inAtEOF)
 
542
//----------------------------------------------------------------------------------------
 
543
{
 
544
    mEOF = inAtEOF;
 
545
    return NS_OK;
 
546
}
 
547
 
 
548
//----------------------------------------------------------------------------------------
 
549
NS_IMETHODIMP FileImpl::SetEOF()
 
550
//----------------------------------------------------------------------------------------
 
551
{
 
552
    NS_NOTYETIMPLEMENTED("FileImpl::SetEOF");
 
553
    return NS_ERROR_NOT_IMPLEMENTED;
 
554
}
 
555
 
 
556
//----------------------------------------------------------------------------------------
 
557
nsresult FileImpl::AllocateBuffers(PRUint32 segmentSize, PRUint32 maxBufSize)
 
558
//----------------------------------------------------------------------------------------
 
559
{
 
560
    nsresult rv = mOutBuffer.Init(segmentSize, maxBufSize);
 
561
    if (NS_SUCCEEDED(rv))
 
562
      mGotBuffers = PR_TRUE;
 
563
 
 
564
    return rv;
 
565
}
 
566
 
 
567
// external callers of Flush will have sync get called,
 
568
// but internal callers just want to flush the buffers to disk.
 
569
nsresult FileImpl::InternalFlush(PRBool syncFile)
 
570
{
 
571
#ifdef XP_MAC
 
572
    if (mFileDesc == PR_STDOUT || mFileDesc == PR_STDERR)
 
573
    {
 
574
        std::cout.flush();
 
575
        return NS_OK;
 
576
    }
 
577
#endif
 
578
    if (!mFileDesc) 
 
579
        return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
 
580
    
 
581
    PRInt32 segCount = mOutBuffer.GetSegmentCount();
 
582
    PRUint32 segSize = mOutBuffer.GetSegmentSize();
 
583
 
 
584
    for (PRInt32 i = 0; i < segCount; i++) 
 
585
    {
 
586
        char* seg = mOutBuffer.GetSegment(i);
 
587
 
 
588
        // if it is the last buffer, it may not be completely full.  
 
589
        if(i == (segCount-1))
 
590
            segSize = (mWriteCursor - seg);
 
591
 
 
592
        PRInt32 bytesWrit = PR_Write(mFileDesc, seg, segSize);
 
593
        if (bytesWrit != (PRInt32)segSize)
 
594
        {
 
595
          mFailed = PR_TRUE;
 
596
          return NS_FILE_RESULT(PR_GetError());
 
597
        }
 
598
    }
 
599
 
 
600
    if (mGotBuffers)
 
601
        mOutBuffer.Empty();
 
602
    mWriteCursor = nsnull;
 
603
    mWriteLimit  = nsnull;
 
604
 
 
605
    // On unix, it seems to fail always.
 
606
    if (syncFile && PR_Sync(mFileDesc) != PR_SUCCESS)
 
607
        mFailed = PR_TRUE;
 
608
                                                
 
609
    return NS_OK;
 
610
}
 
611
//----------------------------------------------------------------------------------------
 
612
nsresult NS_NewTypicalInputFileStream(
 
613
    nsISupports** aResult,
 
614
    const nsFileSpec& inFile
 
615
    /*Default nsprMode == PR_RDONLY*/
 
616
    /*Default accessmode = 0666 (octal)*/)
 
617
// Factory method to get an nsInputStream from a file, using most common options
 
618
//----------------------------------------------------------------------------------------
 
619
{
 
620
  // This QueryInterface was needed because NS_NewIOFileStream
 
621
  // does a cast from (void *) to (nsISupports *) thus causing a 
 
622
  // vtable problem on Windows, where we really didn't have the proper pointer
 
623
  // to an nsIInputStream, this ensures that we do 
 
624
    nsISupports    * supports;
 
625
    nsIInputStream * inStr;
 
626
 
 
627
    nsresult rv = NS_NewIOFileStream(&supports, inFile, PR_RDONLY, 0666);
 
628
 
 
629
    *aResult = nsnull;
 
630
    if (NS_SUCCEEDED(rv)) {
 
631
      if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIInputStream), (void**)&inStr))) {
 
632
        *aResult = inStr;
 
633
      }
 
634
      NS_RELEASE(supports);
 
635
    }
 
636
    return rv;
 
637
}
 
638
 
 
639
//----------------------------------------------------------------------------------------
 
640
nsresult NS_NewTypicalOutputFileStream(
 
641
    nsISupports** aResult,
 
642
    const nsFileSpec& inFile
 
643
    /*default nsprMode= (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/
 
644
    /*Default accessMode= 0666 (octal)*/)
 
645
// Factory method to get an nsOutputStream to a file - most common case.
 
646
//----------------------------------------------------------------------------------------
 
647
{
 
648
  // This QueryInterface was needed because NS_NewIOFileStream
 
649
  // does a cast from (void *) to (nsISupports *) thus causing a 
 
650
  // vtable problem on Windows, where we really didn't have the proper pointer
 
651
  // to an nsIOutputStream, this ensures that we do 
 
652
#if 1
 
653
/*    nsISupports     * supports;
 
654
    nsIOutputStream * outStr;
 
655
 
 
656
    nsresult rv = NS_NewIOFileStream(
 
657
        &supports,
 
658
        inFile,
 
659
        (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
 
660
        0666);
 
661
 
 
662
    *aResult = nsnull;
 
663
    if (NS_SUCCEEDED(rv)) { 
 
664
      if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIOutputStream), (void**)&outStr))) {
 
665
        *aResult = outStr;
 
666
      }
 
667
      NS_RELEASE(supports);
 
668
    }
 
669
    return rv;
 
670
    */
 
671
 
 
672
    nsCOMPtr<nsISupports> supports;
 
673
    nsIOutputStream * outStr;
 
674
 
 
675
    nsresult rv = NS_NewIOFileStream(
 
676
        getter_AddRefs(supports),
 
677
        inFile,
 
678
        (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
 
679
        0666);
 
680
 
 
681
    *aResult = nsnull;
 
682
    if (NS_SUCCEEDED(rv)) { 
 
683
      if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIOutputStream), (void**)&outStr))) {
 
684
        *aResult = outStr;
 
685
      }
 
686
    }
 
687
    return rv;
 
688
#else
 
689
    return NS_NewIOFileStream(
 
690
        aResult,
 
691
        inFile,
 
692
        (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
 
693
        0666);
 
694
#endif
 
695
}
 
696
 
 
697
//----------------------------------------------------------------------------------------
 
698
NS_COM_OBSOLETE nsresult NS_NewIOFileStream(
 
699
    nsISupports** aResult,
 
700
    const nsFileSpec& inFile,
 
701
    PRInt32 nsprMode /*default = (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/,
 
702
    PRInt32 accessMode /*Default = 0666 (octal)*/)
 
703
    // Factory method to get an object that implements both nsIInputStream
 
704
    // and nsIOutputStream, associated with a file.
 
705
//----------------------------------------------------------------------------------------
 
706
{
 
707
    NS_PRECONDITION(aResult != nsnull, "null ptr");
 
708
    if (!aResult)
 
709
        return NS_ERROR_NULL_POINTER;
 
710
 
 
711
    FileImpl* stream = new FileImpl(inFile, nsprMode, accessMode);
 
712
    if (! stream)
 
713
        return NS_ERROR_OUT_OF_MEMORY;
 
714
 
 
715
    NS_ADDREF(stream);
 
716
    PRBool isOpened = PR_FALSE;
 
717
    stream->GetIsOpen(&isOpened);
 
718
    if (!isOpened)
 
719
    {
 
720
        NS_RELEASE(stream);
 
721
        return NS_ERROR_FAILURE;
 
722
    }
 
723
 
 
724
    *aResult = (nsISupports*)(void*)stream;
 
725
    return NS_OK;
 
726
}
 
727