Fix smoketest blocker 180452. If the buffer is not even-sized, we have

to carry a byte around with us.  Patch mostly by alecf, partly by me;
sr=me, r=dmose, a=dmose (sheriff hat).
This commit is contained in:
bzbarsky%mit.edu 2002-11-19 02:57:30 +00:00
Родитель d318d5e4c2
Коммит 77bbd97f7f
1 изменённых файлов: 75 добавлений и 3 удалений

Просмотреть файл

@ -463,6 +463,30 @@ nsBinaryInputStream::ReadCString(nsACString& aString)
return NS_OK;
}
// sometimes, WriteSegmentToString will be handed an odd-number of
// bytes, which means we only have half of the last PRUnichar
struct WriteStringClosure {
nsAString* mString;
PRPackedBool mHasCarryoverByte;
char mCarryoverByte;
};
// there are a few cases we have to account for here:
// * even length buffer, no carryover - easy, just append
// * odd length buffer, no carryover - the last byte needs to be saved
// for carryover
// * odd length buffer, with carryover - first byte needs to be used
// with the carryover byte, and
// the rest of the even length
// buffer is appended as normal
// * even length buffer, with carryover - the first byte needs to be
// used with the previous carryover byte.
// this gives you an odd length buffer,
// so you have to save the last byte for
// the next carryover
// same version of the above, but with correct casting and endian swapping
static NS_METHOD
WriteSegmentToString(nsIInputStream* aStream,
@ -472,7 +496,38 @@ WriteSegmentToString(nsIInputStream* aStream,
PRUint32 aCount,
PRUint32 *aWriteCount)
{
nsAString* outString = NS_STATIC_CAST(nsAString*,aClosure);
NS_PRECONDITION(aCount > 0, "Why are we being told to write 0 bytes?");
NS_PRECONDITION(sizeof(PRUnichar) == 2, "We can't handle other sizes!");
WriteStringClosure* closure = NS_STATIC_CAST(WriteStringClosure*,aClosure);
nsAString* outString = closure->mString;
// we're always going to consume the whole buffer no matter what
// happens, so take care of that right now.. that allows us to
// tweak aCount later. Do NOT move this!
*aWriteCount = aCount;
// if the last Write had an odd-number of bytes read, then
if (closure->mHasCarryoverByte) {
// re-create the two-byte sequence we want to work with
char bytes[2] = { closure->mCarryoverByte, *aFromSegment };
PRUnichar unichar = *(PRUnichar*)bytes;
// Now the little endianness dance
#ifdef IS_LITTLE_ENDIAN
outString->Append(PRUnichar(NS_SWAP16(unichar)));
#else
outString->Append(newByte);
#endif
// now skip past the first byte of the buffer.. code from here
// can assume normal operations, but should not assume aCount
// is relative to the ORIGINAL buffer
++aFromSegment;
--aCount;
closure->mHasCarryoverByte = PR_FALSE;
}
const PRUnichar *unicodeSegment =
NS_REINTERPRET_CAST(const PRUnichar*, aFromSegment);
PRUint32 segmentLength = aCount / sizeof(PRUnichar);
@ -485,7 +540,16 @@ WriteSegmentToString(nsIInputStream* aStream,
outString->Append(unicodeSegment, segmentLength);
#endif
*aWriteCount = aCount;
// remember this is the modifed aCount and aFromSegment,
// so that will take into account the fact that we might have
// skipped the first byte in the buffer
if (aCount % sizeof(PRUnichar) != 0) {
// we must have had a carryover byte, that we'll need the next
// time around
closure->mCarryoverByte = aFromSegment[aCount - 1];
closure->mHasCarryoverByte = PR_TRUE;
}
return NS_OK;
}
@ -500,8 +564,16 @@ nsBinaryInputStream::ReadString(nsAString& aString)
if (NS_FAILED(rv)) return rv;
aString.Truncate();
rv = ReadSegments(WriteSegmentToString, &aString, length*sizeof(PRUnichar), &bytesRead);
WriteStringClosure closure;
closure.mString = &aString;
closure.mHasCarryoverByte = PR_FALSE;
rv = ReadSegments(WriteSegmentToString, &closure,
length*sizeof(PRUnichar), &bytesRead);
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(!closure.mHasCarryoverByte, "some strange stream corruption!");
if (bytesRead != length*sizeof(PRUnichar))
return NS_ERROR_FAILURE;