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 Communicator client code, released
16 : * March 31, 1998.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998-1999
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
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 : /**
40 : * This file contains implementations of the nsIBinaryInputStream and
41 : * nsIBinaryOutputStream interfaces. Together, these interfaces allows reading
42 : * and writing of primitive data types (integers, floating-point values,
43 : * booleans, etc.) to a stream in a binary, untagged, fixed-endianness format.
44 : * This might be used, for example, to implement network protocols or to
45 : * produce architecture-neutral binary disk files, i.e. ones that can be read
46 : * and written by both big-endian and little-endian platforms. Output is
47 : * written in big-endian order (high-order byte first), as this is traditional
48 : * network order.
49 : *
50 : * @See nsIBinaryInputStream
51 : * @See nsIBinaryOutputStream
52 : */
53 : #include <string.h>
54 : #include "nsBinaryStream.h"
55 : #include "nsCRT.h"
56 : #include "nsIStreamBufferAccess.h"
57 : #include "prlong.h"
58 : #include "nsString.h"
59 : #include "nsISerializable.h"
60 : #include "nsIClassInfo.h"
61 : #include "nsComponentManagerUtils.h"
62 : #include "nsIURI.h" // for NS_IURI_IID
63 :
64 110771 : NS_IMPL_ISUPPORTS3(nsBinaryOutputStream, nsIObjectOutputStream, nsIBinaryOutputStream, nsIOutputStream)
65 :
66 : NS_IMETHODIMP
67 0 : nsBinaryOutputStream::Flush()
68 : {
69 0 : NS_ENSURE_STATE(mOutputStream);
70 0 : return mOutputStream->Flush();
71 : }
72 :
73 : NS_IMETHODIMP
74 7383 : nsBinaryOutputStream::Close()
75 : {
76 7383 : NS_ENSURE_STATE(mOutputStream);
77 7383 : return mOutputStream->Close();
78 : }
79 :
80 : NS_IMETHODIMP
81 15662 : nsBinaryOutputStream::Write(const char *aBuf, PRUint32 aCount, PRUint32 *aActualBytes)
82 : {
83 15662 : NS_ENSURE_STATE(mOutputStream);
84 15662 : return mOutputStream->Write(aBuf, aCount, aActualBytes);
85 : }
86 :
87 : NS_IMETHODIMP
88 0 : nsBinaryOutputStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
89 : {
90 0 : NS_NOTREACHED("WriteFrom");
91 0 : return NS_ERROR_NOT_IMPLEMENTED;
92 : }
93 :
94 : NS_IMETHODIMP
95 0 : nsBinaryOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
96 : {
97 0 : NS_NOTREACHED("WriteSegments");
98 0 : return NS_ERROR_NOT_IMPLEMENTED;
99 : }
100 :
101 : NS_IMETHODIMP
102 0 : nsBinaryOutputStream::IsNonBlocking(bool *aNonBlocking)
103 : {
104 0 : NS_ENSURE_STATE(mOutputStream);
105 0 : return mOutputStream->IsNonBlocking(aNonBlocking);
106 : }
107 :
108 : nsresult
109 177762 : nsBinaryOutputStream::WriteFully(const char *aBuf, PRUint32 aCount)
110 : {
111 177762 : NS_ENSURE_STATE(mOutputStream);
112 :
113 : nsresult rv;
114 : PRUint32 bytesWritten;
115 :
116 177762 : rv = mOutputStream->Write(aBuf, aCount, &bytesWritten);
117 177762 : if (NS_FAILED(rv)) return rv;
118 177761 : if (bytesWritten != aCount)
119 0 : return NS_ERROR_FAILURE;
120 177761 : return NS_OK;
121 : }
122 :
123 : NS_IMETHODIMP
124 8253 : nsBinaryOutputStream::SetOutputStream(nsIOutputStream *aOutputStream)
125 : {
126 8253 : NS_ENSURE_ARG_POINTER(aOutputStream);
127 8253 : mOutputStream = aOutputStream;
128 8253 : mBufferAccess = do_QueryInterface(aOutputStream);
129 8253 : return NS_OK;
130 : }
131 :
132 : NS_IMETHODIMP
133 46 : nsBinaryOutputStream::WriteBoolean(bool aBoolean)
134 : {
135 46 : return Write8(aBoolean);
136 : }
137 :
138 : NS_IMETHODIMP
139 118432 : nsBinaryOutputStream::Write8(PRUint8 aByte)
140 : {
141 118432 : return WriteFully((const char*)&aByte, sizeof aByte);
142 : }
143 :
144 : NS_IMETHODIMP
145 29600 : nsBinaryOutputStream::Write16(PRUint16 a16)
146 : {
147 29600 : a16 = NS_SWAP16(a16);
148 29600 : return WriteFully((const char*)&a16, sizeof a16);
149 : }
150 :
151 : NS_IMETHODIMP
152 29712 : nsBinaryOutputStream::Write32(PRUint32 a32)
153 : {
154 29712 : a32 = NS_SWAP32(a32);
155 29712 : return WriteFully((const char*)&a32, sizeof a32);
156 : }
157 :
158 : NS_IMETHODIMP
159 6 : nsBinaryOutputStream::Write64(PRUint64 a64)
160 : {
161 : nsresult rv;
162 : PRUint32 bytesWritten;
163 :
164 6 : a64 = NS_SWAP64(a64);
165 6 : rv = Write(reinterpret_cast<char*>(&a64), sizeof a64, &bytesWritten);
166 6 : if (NS_FAILED(rv)) return rv;
167 6 : if (bytesWritten != sizeof a64)
168 0 : return NS_ERROR_FAILURE;
169 6 : return rv;
170 : }
171 :
172 : NS_IMETHODIMP
173 2 : nsBinaryOutputStream::WriteFloat(float aFloat)
174 : {
175 : NS_ASSERTION(sizeof(float) == sizeof (PRUint32),
176 : "False assumption about sizeof(float)");
177 2 : return Write32(*reinterpret_cast<PRUint32*>(&aFloat));
178 : }
179 :
180 : NS_IMETHODIMP
181 0 : nsBinaryOutputStream::WriteDouble(double aDouble)
182 : {
183 : NS_ASSERTION(sizeof(double) == sizeof(PRUint64),
184 : "False assumption about sizeof(double)");
185 0 : return Write64(*reinterpret_cast<PRUint64*>(&aDouble));
186 : }
187 :
188 : NS_IMETHODIMP
189 18 : nsBinaryOutputStream::WriteStringZ(const char *aString)
190 : {
191 : PRUint32 length;
192 : nsresult rv;
193 :
194 18 : length = strlen(aString);
195 18 : rv = Write32(length);
196 18 : if (NS_FAILED(rv)) return rv;
197 18 : return WriteFully(aString, length);
198 : }
199 :
200 : NS_IMETHODIMP
201 10 : nsBinaryOutputStream::WriteWStringZ(const PRUnichar* aString)
202 : {
203 : PRUint32 length, byteCount;
204 : nsresult rv;
205 :
206 10 : length = nsCRT::strlen(aString);
207 10 : rv = Write32(length);
208 10 : if (NS_FAILED(rv)) return rv;
209 :
210 10 : if (length == 0)
211 4 : return NS_OK;
212 6 : byteCount = length * sizeof(PRUnichar);
213 :
214 : #ifdef IS_BIG_ENDIAN
215 : rv = WriteBytes(reinterpret_cast<const char*>(aString), byteCount);
216 : #else
217 : // XXX use WriteSegments here to avoid copy!
218 : PRUnichar *copy, temp[64];
219 6 : if (length <= 64) {
220 6 : copy = temp;
221 : } else {
222 0 : copy = reinterpret_cast<PRUnichar*>(moz_malloc(byteCount));
223 0 : if (!copy)
224 0 : return NS_ERROR_OUT_OF_MEMORY;
225 : }
226 6 : NS_ASSERTION((PRUptrdiff(aString) & 0x1) == 0, "aString not properly aligned");
227 140 : for (PRUint32 i = 0; i < length; i++)
228 134 : copy[i] = NS_SWAP16(aString[i]);
229 6 : rv = WriteBytes(reinterpret_cast<const char*>(copy), byteCount);
230 6 : if (copy != temp)
231 0 : moz_free(copy);
232 : #endif
233 :
234 6 : return rv;
235 : }
236 :
237 : NS_IMETHODIMP
238 0 : nsBinaryOutputStream::WriteUtf8Z(const PRUnichar* aString)
239 : {
240 0 : return WriteStringZ(NS_ConvertUTF16toUTF8(aString).get());
241 : }
242 :
243 : NS_IMETHODIMP
244 15656 : nsBinaryOutputStream::WriteBytes(const char *aString, PRUint32 aLength)
245 : {
246 : nsresult rv;
247 : PRUint32 bytesWritten;
248 :
249 15656 : rv = Write(aString, aLength, &bytesWritten);
250 15656 : if (NS_FAILED(rv)) return rv;
251 15656 : if (bytesWritten != aLength)
252 0 : return NS_ERROR_FAILURE;
253 15656 : return rv;
254 : }
255 :
256 : NS_IMETHODIMP
257 898 : nsBinaryOutputStream::WriteByteArray(PRUint8 *aBytes, PRUint32 aLength)
258 : {
259 898 : return WriteBytes(reinterpret_cast<char *>(aBytes), aLength);
260 : }
261 :
262 : NS_IMETHODIMP
263 7376 : nsBinaryOutputStream::WriteObject(nsISupports* aObject, bool aIsStrongRef)
264 : {
265 : return WriteCompoundObject(aObject, NS_GET_IID(nsISupports),
266 7376 : aIsStrongRef);
267 : }
268 :
269 : NS_IMETHODIMP
270 0 : nsBinaryOutputStream::WriteSingleRefObject(nsISupports* aObject)
271 : {
272 : return WriteCompoundObject(aObject, NS_GET_IID(nsISupports),
273 0 : true);
274 : }
275 :
276 : NS_IMETHODIMP
277 7393 : nsBinaryOutputStream::WriteCompoundObject(nsISupports* aObject,
278 : const nsIID& aIID,
279 : bool aIsStrongRef)
280 : {
281 : // Can't deal with weak refs
282 7393 : NS_ENSURE_TRUE(aIsStrongRef, NS_ERROR_UNEXPECTED);
283 :
284 14786 : nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aObject);
285 7393 : NS_ENSURE_TRUE(classInfo, NS_ERROR_NOT_AVAILABLE);
286 :
287 14786 : nsCOMPtr<nsISerializable> serializable = do_QueryInterface(aObject);
288 7393 : NS_ENSURE_TRUE(serializable, NS_ERROR_NOT_AVAILABLE);
289 :
290 : nsCID cid;
291 7393 : classInfo->GetClassIDNoAlloc(&cid);
292 :
293 7393 : nsresult rv = WriteID(cid);
294 7393 : NS_ENSURE_SUCCESS(rv, rv);
295 :
296 7393 : rv = WriteID(aIID);
297 7393 : NS_ENSURE_SUCCESS(rv, rv);
298 :
299 7393 : return serializable->Write(this);
300 : }
301 :
302 : NS_IMETHODIMP
303 14798 : nsBinaryOutputStream::WriteID(const nsIID& aIID)
304 : {
305 14798 : nsresult rv = Write32(aIID.m0);
306 14798 : NS_ENSURE_SUCCESS(rv, rv);
307 :
308 14798 : rv = Write16(aIID.m1);
309 14798 : NS_ENSURE_SUCCESS(rv, rv);
310 :
311 14798 : rv = Write16(aIID.m2);
312 14798 : NS_ENSURE_SUCCESS(rv, rv);
313 :
314 133182 : for (int i = 0; i < 8; ++i) {
315 118384 : rv = Write8(aIID.m3[i]);
316 118384 : NS_ENSURE_SUCCESS(rv, rv);
317 : }
318 :
319 14798 : return NS_OK;
320 : }
321 :
322 : NS_IMETHODIMP_(char*)
323 0 : nsBinaryOutputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask)
324 : {
325 0 : if (mBufferAccess)
326 0 : return mBufferAccess->GetBuffer(aLength, aAlignMask);
327 0 : return nsnull;
328 : }
329 :
330 : NS_IMETHODIMP_(void)
331 0 : nsBinaryOutputStream::PutBuffer(char* aBuffer, PRUint32 aLength)
332 : {
333 0 : if (mBufferAccess)
334 0 : mBufferAccess->PutBuffer(aBuffer, aLength);
335 0 : }
336 :
337 287113 : NS_IMPL_ISUPPORTS3(nsBinaryInputStream, nsIObjectInputStream, nsIBinaryInputStream, nsIInputStream)
338 :
339 : NS_IMETHODIMP
340 12026 : nsBinaryInputStream::Available(PRUint32* aResult)
341 : {
342 12026 : NS_ENSURE_STATE(mInputStream);
343 12026 : return mInputStream->Available(aResult);
344 : }
345 :
346 : NS_IMETHODIMP
347 35389 : nsBinaryInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aNumRead)
348 : {
349 35389 : NS_ENSURE_STATE(mInputStream);
350 :
351 : // mInputStream might give us short reads, so deal with that.
352 35389 : PRUint32 totalRead = 0;
353 :
354 : PRUint32 bytesRead;
355 35398 : do {
356 35399 : nsresult rv = mInputStream->Read(aBuffer, aCount, &bytesRead);
357 35399 : if (rv == NS_BASE_STREAM_WOULD_BLOCK && totalRead != 0) {
358 : // We already read some data. Return it.
359 0 : break;
360 : }
361 :
362 35399 : if (NS_FAILED(rv)) {
363 1 : return rv;
364 : }
365 :
366 35398 : totalRead += bytesRead;
367 35398 : aBuffer += bytesRead;
368 35398 : aCount -= bytesRead;
369 : } while (aCount != 0 && bytesRead != 0);
370 :
371 35388 : *aNumRead = totalRead;
372 :
373 35388 : return NS_OK;
374 : }
375 :
376 :
377 : // when forwarding ReadSegments to mInputStream, we need to make sure
378 : // 'this' is being passed to the writer each time. To do this, we need
379 : // a thunking function which keeps the real input stream around.
380 :
381 : // the closure wrapper
382 : struct ReadSegmentsClosure {
383 : nsIInputStream* mRealInputStream;
384 : void* mRealClosure;
385 : nsWriteSegmentFun mRealWriter;
386 : nsresult mRealResult;
387 : PRUint32 mBytesRead; // to properly implement aToOffset
388 : };
389 :
390 : // the thunking function
391 : static NS_METHOD
392 13 : ReadSegmentForwardingThunk(nsIInputStream* aStream,
393 : void *aClosure,
394 : const char* aFromSegment,
395 : PRUint32 aToOffset,
396 : PRUint32 aCount,
397 : PRUint32 *aWriteCount)
398 : {
399 : ReadSegmentsClosure* thunkClosure =
400 13 : reinterpret_cast<ReadSegmentsClosure*>(aClosure);
401 :
402 13 : NS_ASSERTION(NS_SUCCEEDED(thunkClosure->mRealResult),
403 : "How did this get to be a failure status?");
404 :
405 : thunkClosure->mRealResult =
406 : thunkClosure->mRealWriter(thunkClosure->mRealInputStream,
407 : thunkClosure->mRealClosure,
408 : aFromSegment,
409 : thunkClosure->mBytesRead + aToOffset,
410 13 : aCount, aWriteCount);
411 :
412 13 : return thunkClosure->mRealResult;
413 : }
414 :
415 :
416 : NS_IMETHODIMP
417 16 : nsBinaryInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval)
418 : {
419 16 : NS_ENSURE_STATE(mInputStream);
420 :
421 16 : ReadSegmentsClosure thunkClosure = { this, closure, writer, NS_OK, 0 };
422 :
423 : // mInputStream might give us short reads, so deal with that.
424 : PRUint32 bytesRead;
425 16 : do {
426 16 : nsresult rv = mInputStream->ReadSegments(ReadSegmentForwardingThunk,
427 : &thunkClosure,
428 16 : count, &bytesRead);
429 :
430 16 : if (rv == NS_BASE_STREAM_WOULD_BLOCK && thunkClosure.mBytesRead != 0) {
431 : // We already read some data. Return it.
432 0 : break;
433 : }
434 :
435 16 : if (NS_FAILED(rv)) {
436 0 : return rv;
437 : }
438 :
439 16 : thunkClosure.mBytesRead += bytesRead;
440 16 : count -= bytesRead;
441 : } while (count != 0 && bytesRead != 0 &&
442 0 : NS_SUCCEEDED(thunkClosure.mRealResult));
443 :
444 16 : *_retval = thunkClosure.mBytesRead;
445 :
446 16 : return NS_OK;
447 : }
448 :
449 : NS_IMETHODIMP
450 0 : nsBinaryInputStream::IsNonBlocking(bool *aNonBlocking)
451 : {
452 0 : NS_ENSURE_STATE(mInputStream);
453 0 : return mInputStream->IsNonBlocking(aNonBlocking);
454 : }
455 :
456 : NS_IMETHODIMP
457 58 : nsBinaryInputStream::Close()
458 : {
459 58 : NS_ENSURE_STATE(mInputStream);
460 58 : return mInputStream->Close();
461 : }
462 :
463 : NS_IMETHODIMP
464 17110 : nsBinaryInputStream::SetInputStream(nsIInputStream *aInputStream)
465 : {
466 17110 : NS_ENSURE_ARG_POINTER(aInputStream);
467 17110 : mInputStream = aInputStream;
468 17110 : mBufferAccess = do_QueryInterface(aInputStream);
469 17110 : return NS_OK;
470 : }
471 :
472 : NS_IMETHODIMP
473 22 : nsBinaryInputStream::ReadBoolean(bool* aBoolean)
474 : {
475 : PRUint8 byteResult;
476 22 : nsresult rv = Read8(&byteResult);
477 22 : if (NS_FAILED(rv)) return rv;
478 21 : *aBoolean = !!byteResult;
479 21 : return rv;
480 : }
481 :
482 : NS_IMETHODIMP
483 17198 : nsBinaryInputStream::Read8(PRUint8* aByte)
484 : {
485 : nsresult rv;
486 : PRUint32 bytesRead;
487 :
488 17198 : rv = Read(reinterpret_cast<char*>(aByte), sizeof(*aByte), &bytesRead);
489 17198 : if (NS_FAILED(rv)) return rv;
490 17198 : if (bytesRead != 1)
491 10 : return NS_ERROR_FAILURE;
492 17188 : return rv;
493 : }
494 :
495 : NS_IMETHODIMP
496 2598 : nsBinaryInputStream::Read16(PRUint16* a16)
497 : {
498 : nsresult rv;
499 : PRUint32 bytesRead;
500 :
501 2598 : rv = Read(reinterpret_cast<char*>(a16), sizeof *a16, &bytesRead);
502 2598 : if (NS_FAILED(rv)) return rv;
503 2598 : if (bytesRead != sizeof *a16)
504 0 : return NS_ERROR_FAILURE;
505 2598 : *a16 = NS_SWAP16(*a16);
506 2598 : return rv;
507 : }
508 :
509 : NS_IMETHODIMP
510 2692 : nsBinaryInputStream::Read32(PRUint32* a32)
511 : {
512 : nsresult rv;
513 : PRUint32 bytesRead;
514 :
515 2692 : rv = Read(reinterpret_cast<char*>(a32), sizeof *a32, &bytesRead);
516 2692 : if (NS_FAILED(rv)) return rv;
517 2692 : if (bytesRead != sizeof *a32)
518 0 : return NS_ERROR_FAILURE;
519 2692 : *a32 = NS_SWAP32(*a32);
520 2692 : return rv;
521 : }
522 :
523 : NS_IMETHODIMP
524 6 : nsBinaryInputStream::Read64(PRUint64* a64)
525 : {
526 : nsresult rv;
527 : PRUint32 bytesRead;
528 :
529 6 : rv = Read(reinterpret_cast<char*>(a64), sizeof *a64, &bytesRead);
530 6 : if (NS_FAILED(rv)) return rv;
531 6 : if (bytesRead != sizeof *a64)
532 0 : return NS_ERROR_FAILURE;
533 6 : *a64 = NS_SWAP64(*a64);
534 6 : return rv;
535 : }
536 :
537 : NS_IMETHODIMP
538 2 : nsBinaryInputStream::ReadFloat(float* aFloat)
539 : {
540 : NS_ASSERTION(sizeof(float) == sizeof (PRUint32),
541 : "False assumption about sizeof(float)");
542 2 : return Read32(reinterpret_cast<PRUint32*>(aFloat));
543 : }
544 :
545 : NS_IMETHODIMP
546 0 : nsBinaryInputStream::ReadDouble(double* aDouble)
547 : {
548 : NS_ASSERTION(sizeof(double) == sizeof(PRUint64),
549 : "False assumption about sizeof(double)");
550 0 : return Read64(reinterpret_cast<PRUint64*>(aDouble));
551 : }
552 :
553 : static NS_METHOD
554 11 : WriteSegmentToCString(nsIInputStream* aStream,
555 : void *aClosure,
556 : const char* aFromSegment,
557 : PRUint32 aToOffset,
558 : PRUint32 aCount,
559 : PRUint32 *aWriteCount)
560 : {
561 11 : nsACString* outString = static_cast<nsACString*>(aClosure);
562 :
563 11 : outString->Append(aFromSegment, aCount);
564 :
565 11 : *aWriteCount = aCount;
566 :
567 11 : return NS_OK;
568 : }
569 :
570 : NS_IMETHODIMP
571 14 : nsBinaryInputStream::ReadCString(nsACString& aString)
572 : {
573 : nsresult rv;
574 : PRUint32 length, bytesRead;
575 :
576 14 : rv = Read32(&length);
577 14 : if (NS_FAILED(rv)) return rv;
578 :
579 14 : aString.Truncate();
580 14 : rv = ReadSegments(WriteSegmentToCString, &aString, length, &bytesRead);
581 14 : if (NS_FAILED(rv)) return rv;
582 :
583 14 : if (bytesRead != length)
584 0 : return NS_ERROR_FAILURE;
585 :
586 14 : return NS_OK;
587 : }
588 :
589 :
590 : // sometimes, WriteSegmentToString will be handed an odd-number of
591 : // bytes, which means we only have half of the last PRUnichar
592 : struct WriteStringClosure {
593 : PRUnichar *mWriteCursor;
594 : bool mHasCarryoverByte;
595 : char mCarryoverByte;
596 : };
597 :
598 : // there are a few cases we have to account for here:
599 : // * even length buffer, no carryover - easy, just append
600 : // * odd length buffer, no carryover - the last byte needs to be saved
601 : // for carryover
602 : // * odd length buffer, with carryover - first byte needs to be used
603 : // with the carryover byte, and
604 : // the rest of the even length
605 : // buffer is appended as normal
606 : // * even length buffer, with carryover - the first byte needs to be
607 : // used with the previous carryover byte.
608 : // this gives you an odd length buffer,
609 : // so you have to save the last byte for
610 : // the next carryover
611 :
612 :
613 : // same version of the above, but with correct casting and endian swapping
614 : static NS_METHOD
615 2 : WriteSegmentToString(nsIInputStream* aStream,
616 : void *aClosure,
617 : const char* aFromSegment,
618 : PRUint32 aToOffset,
619 : PRUint32 aCount,
620 : PRUint32 *aWriteCount)
621 : {
622 2 : NS_PRECONDITION(aCount > 0, "Why are we being told to write 0 bytes?");
623 : NS_PRECONDITION(sizeof(PRUnichar) == 2, "We can't handle other sizes!");
624 :
625 2 : WriteStringClosure* closure = static_cast<WriteStringClosure*>(aClosure);
626 2 : PRUnichar *cursor = closure->mWriteCursor;
627 :
628 : // we're always going to consume the whole buffer no matter what
629 : // happens, so take care of that right now.. that allows us to
630 : // tweak aCount later. Do NOT move this!
631 2 : *aWriteCount = aCount;
632 :
633 : // if the last Write had an odd-number of bytes read, then
634 2 : if (closure->mHasCarryoverByte) {
635 : // re-create the two-byte sequence we want to work with
636 0 : char bytes[2] = { closure->mCarryoverByte, *aFromSegment };
637 0 : *cursor = *(PRUnichar*)bytes;
638 : // Now the little endianness dance
639 : #ifdef IS_LITTLE_ENDIAN
640 0 : *cursor = (PRUnichar) NS_SWAP16(*cursor);
641 : #endif
642 0 : ++cursor;
643 :
644 : // now skip past the first byte of the buffer.. code from here
645 : // can assume normal operations, but should not assume aCount
646 : // is relative to the ORIGINAL buffer
647 0 : ++aFromSegment;
648 0 : --aCount;
649 :
650 0 : closure->mHasCarryoverByte = false;
651 : }
652 :
653 : // this array is possibly unaligned... be careful how we access it!
654 : const PRUnichar *unicodeSegment =
655 2 : reinterpret_cast<const PRUnichar*>(aFromSegment);
656 :
657 : // calculate number of full characters in segment (aCount could be odd!)
658 2 : PRUint32 segmentLength = aCount / sizeof(PRUnichar);
659 :
660 : // copy all data into our aligned buffer. byte swap if necessary.
661 2 : memcpy(cursor, unicodeSegment, segmentLength * sizeof(PRUnichar));
662 2 : PRUnichar *end = cursor + segmentLength;
663 : #ifdef IS_LITTLE_ENDIAN
664 12 : for (; cursor < end; ++cursor)
665 10 : *cursor = (PRUnichar) NS_SWAP16(*cursor);
666 : #endif
667 2 : closure->mWriteCursor = end;
668 :
669 : // remember this is the modifed aCount and aFromSegment,
670 : // so that will take into account the fact that we might have
671 : // skipped the first byte in the buffer
672 2 : if (aCount % sizeof(PRUnichar) != 0) {
673 : // we must have had a carryover byte, that we'll need the next
674 : // time around
675 0 : closure->mCarryoverByte = aFromSegment[aCount - 1];
676 0 : closure->mHasCarryoverByte = true;
677 : }
678 :
679 2 : return NS_OK;
680 : }
681 :
682 :
683 : NS_IMETHODIMP
684 2 : nsBinaryInputStream::ReadString(nsAString& aString)
685 : {
686 : nsresult rv;
687 : PRUint32 length, bytesRead;
688 :
689 2 : rv = Read32(&length);
690 2 : if (NS_FAILED(rv)) return rv;
691 :
692 2 : if (length == 0) {
693 0 : aString.Truncate();
694 0 : return NS_OK;
695 : }
696 :
697 : // pre-allocate output buffer, and get direct access to buffer...
698 2 : if (!EnsureStringLength(aString, length))
699 0 : return NS_ERROR_OUT_OF_MEMORY;
700 :
701 2 : nsAString::iterator start;
702 2 : aString.BeginWriting(start);
703 :
704 : WriteStringClosure closure;
705 2 : closure.mWriteCursor = start.get();
706 2 : closure.mHasCarryoverByte = false;
707 :
708 : rv = ReadSegments(WriteSegmentToString, &closure,
709 2 : length*sizeof(PRUnichar), &bytesRead);
710 2 : if (NS_FAILED(rv)) return rv;
711 :
712 2 : NS_ASSERTION(!closure.mHasCarryoverByte, "some strange stream corruption!");
713 :
714 2 : if (bytesRead != length*sizeof(PRUnichar))
715 0 : return NS_ERROR_FAILURE;
716 :
717 2 : return NS_OK;
718 : }
719 :
720 : NS_IMETHODIMP
721 12895 : nsBinaryInputStream::ReadBytes(PRUint32 aLength, char* *_rval)
722 : {
723 : nsresult rv;
724 : PRUint32 bytesRead;
725 : char* s;
726 :
727 12895 : s = reinterpret_cast<char*>(moz_malloc(aLength));
728 12895 : if (!s)
729 0 : return NS_ERROR_OUT_OF_MEMORY;
730 :
731 12895 : rv = Read(s, aLength, &bytesRead);
732 12895 : if (NS_FAILED(rv)) {
733 1 : moz_free(s);
734 1 : return rv;
735 : }
736 12894 : if (bytesRead != aLength) {
737 25 : moz_free(s);
738 25 : return NS_ERROR_FAILURE;
739 : }
740 :
741 12869 : *_rval = s;
742 12869 : return NS_OK;
743 : }
744 :
745 : NS_IMETHODIMP
746 10945 : nsBinaryInputStream::ReadByteArray(PRUint32 aLength, PRUint8* *_rval)
747 : {
748 10945 : return ReadBytes(aLength, reinterpret_cast<char **>(_rval));
749 : }
750 :
751 : NS_IMETHODIMP
752 648 : nsBinaryInputStream::ReadObject(bool aIsStrongRef, nsISupports* *aObject)
753 : {
754 : nsCID cid;
755 : nsIID iid;
756 648 : nsresult rv = ReadID(&cid);
757 648 : NS_ENSURE_SUCCESS(rv, rv);
758 :
759 648 : rv = ReadID(&iid);
760 648 : NS_ENSURE_SUCCESS(rv, rv);
761 :
762 : // HACK: Intercept old (pre-gecko6) nsIURI IID, and replace with
763 : // the updated IID, so that we're QI'ing to an actual interface.
764 : // (As soon as we drop support for upgrading from pre-gecko6, we can
765 : // remove this chunk.)
766 : static const nsIID oldURIiid =
767 : { 0x7a22cc0, 0xce5, 0x11d3,
768 : { 0x93, 0x31, 0x0, 0x10, 0x4b, 0xa0, 0xfd, 0x40 }};
769 :
770 : // hackaround for bug 670542
771 : static const nsIID oldURIiid2 =
772 : { 0xd6d04c36, 0x0fa4, 0x4db3,
773 : { 0xbe, 0x05, 0x4a, 0x18, 0x39, 0x71, 0x03, 0xe2 }};
774 :
775 : // hackaround for bug 682031
776 : static const nsIID oldURIiid3 =
777 : { 0x12120b20, 0x0929, 0x40e9,
778 : { 0x88, 0xcf, 0x6e, 0x08, 0x76, 0x6e, 0x8b, 0x23 }};
779 :
780 1944 : if (iid.Equals(oldURIiid) ||
781 648 : iid.Equals(oldURIiid2) ||
782 648 : iid.Equals(oldURIiid3)) {
783 0 : const nsIID newURIiid = NS_IURI_IID;
784 0 : iid = newURIiid;
785 : }
786 : // END HACK
787 :
788 1296 : nsCOMPtr<nsISupports> object = do_CreateInstance(cid, &rv);
789 648 : NS_ENSURE_SUCCESS(rv, rv);
790 :
791 1296 : nsCOMPtr<nsISerializable> serializable = do_QueryInterface(object);
792 648 : NS_ENSURE_TRUE(serializable, NS_ERROR_UNEXPECTED);
793 :
794 648 : rv = serializable->Read(this);
795 648 : NS_ENSURE_SUCCESS(rv, rv);
796 :
797 648 : return object->QueryInterface(iid, reinterpret_cast<void**>(aObject));
798 : }
799 :
800 : NS_IMETHODIMP
801 1296 : nsBinaryInputStream::ReadID(nsID *aResult)
802 : {
803 1296 : nsresult rv = Read32(&aResult->m0);
804 1296 : NS_ENSURE_SUCCESS(rv, rv);
805 :
806 1296 : rv = Read16(&aResult->m1);
807 1296 : NS_ENSURE_SUCCESS(rv, rv);
808 :
809 1296 : rv = Read16(&aResult->m2);
810 1296 : NS_ENSURE_SUCCESS(rv, rv);
811 :
812 11664 : for (int i = 0; i < 8; ++i) {
813 10368 : rv = Read8(&aResult->m3[i]);
814 10368 : NS_ENSURE_SUCCESS(rv, rv);
815 : }
816 :
817 1296 : return NS_OK;
818 : }
819 :
820 : NS_IMETHODIMP_(char*)
821 0 : nsBinaryInputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask)
822 : {
823 0 : if (mBufferAccess)
824 0 : return mBufferAccess->GetBuffer(aLength, aAlignMask);
825 0 : return nsnull;
826 : }
827 :
828 : NS_IMETHODIMP_(void)
829 0 : nsBinaryInputStream::PutBuffer(char* aBuffer, PRUint32 aLength)
830 : {
831 0 : if (mBufferAccess)
832 0 : mBufferAccess->PutBuffer(aBuffer, aLength);
833 0 : }
|