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 |
|
---|