static inline uint32 sReadCount(const ZStreamR& iStreamR) { uint8 firstByte = iStreamR.ReadUInt8(); if (firstByte < 0xFF) return firstByte; return iStreamR.ReadUInt32(); }
static bool sTryGIF(const ZStreamR& iStream) { if ('G' != iStream.ReadUInt8() || 'I' != iStream.ReadUInt8() || 'F' != iStream.ReadUInt8() || '8' != iStream.ReadUInt8()) { return false; } return true; }
static bool sTryBMP(const ZStreamR& iStream) { if (0x42 != iStream.ReadUInt8() || 0x4D != iStream.ReadUInt8()) { return false; } return true; }
static void sReadRLE8(const ZStreamR& iStream, ZCoord iWidth, ZCoord iHeight, size_t iRowBytes, bool iFlip, uint8* iBuffer) { ZCoord currentRow = 0; ZCoord currentCol = 0; bool done = false; while (!done) { uint8 count = iStream.ReadUInt8(); uint8 command = iStream.ReadUInt8(); if (count == 0) { switch (command) { case 0: // Move to start of next row { currentRow += 1; currentCol = 0; break; } case 1: // All done { done = true; break; } case 2: // Offset by some relative amount { currentCol += iStream.ReadUInt8(); currentRow += iStream.ReadUInt8(); break; } default: // Absolute data follows -- the length is the value of 'command' { uint8* destAddress = iBuffer + iRowBytes * (iFlip ? iHeight - currentRow - 1 : currentRow) + currentCol; iStream.Read(destAddress, command); currentCol += command; // An odd number of bytes is followed by a pad byte. if ((command & 1) != 0) iStream.Skip(1); break; } } } else { // Store a run of bytes. The count is in 'count', the value is in 'command'. uint8* destAddress = iBuffer + iRowBytes * (iFlip ? iHeight - currentRow - 1 : currentRow) + currentCol; for (int x = 0; x < count; ++x) *destAddress++ = command; currentCol += count; } } }
static bool sTryPNG(const ZStreamR& iStream) { if (0x89 != iStream.ReadUInt8() || 0x50 != iStream.ReadUInt8() || 0x4E != iStream.ReadUInt8() || 0x47 != iStream.ReadUInt8() || 0x0D != iStream.ReadUInt8() || 0x0A != iStream.ReadUInt8() || 0x1A != iStream.ReadUInt8() || 0x0A != iStream.ReadUInt8()) { return false; } return true; }
static bool sTryKF(const ZStreamR& iStream) { iStream.Skip(8); if ('P' != iStream.ReadUInt8() || 'N' != iStream.ReadUInt8() || 'T' != iStream.ReadUInt8() || 'R' != iStream.ReadUInt8()) { return false; } return true; }
void ZStreamWPos_Memory::pCopyFrom(const ZStreamR& iStreamR, uint64 iCount, uint64* oCountRead, uint64* oCountWritten) { if (oCountRead) *oCountRead = 0; if (oCountWritten) *oCountWritten = 0; while (iCount) { size_t countToRead = ZStream::sClampedSize(iCount, fCapacity, fPosition); size_t countRead; iStreamR.Read(fAddress + fPosition, countToRead, &countRead); if (countRead == 0) break; fPosition += countRead; if (fSize < fPosition) fSize = fPosition; iCount -= countRead; if (oCountRead) *oCountRead += countRead; if (oCountWritten) *oCountWritten += countRead; } }
bool ZBlackBerryServer::Handler_ManagerChanged::Read(const ZStreamR& r) { const bool req = r.ReadBool(); ZGuardRMtxR locker(fMutex); if (!req) { fState = eState_SendClosed; locker.Release(); //##ZStreamerWriter::Wake(); return false; } switch (fState) { case eState_Quiet: { fState = eState_Waiting; return true; } case eState_Changed: { fState = eState_SendChanged; locker.Release(); //##ZStreamerWriter::Wake(); return true; } } ZUnimplemented(); return false; }
static void sReadString(const ZStreamR& iStreamR, string& oString) { uint32 theCount = sReadCount(iStreamR); oString.resize(theCount); if (theCount) iStreamR.Read(const_cast<char*>(oString.data()), theCount); }
void ZASParser::ParseHandler_Prettify::ParsedBinary(const ZStreamR& iStream) { if (fDumpBinaries) { if (fInBlock) spWriteIndent(fStrimW, fIndent); // Let's see if we've got more than 16 bytes. We only have a read // stream, so we can't _ask_ how many bytes would be physically // readable (CountReadable only provides a lower limit, and // can return zero even when there's data available). So we // have to actually suck it and see. We use a ZStreamR_DynamicBuffered, // which lets us read the stream, then return the read bytes to // be re-read if it turns out we've got enough to warrant doing // indentation. ZStreamRWPos_RAM theStreamRAM; ZStreamR_DynamicBuffered theStream(iStream, theStreamRAM); uint64 countSkipped; theStream.Skip(17, &countSkipped); theStream.Rewind(); theStream.Commit(); if (countSkipped <= 16) { // We've got 16 or fewer bytes, emit them on the same line. fStrimW.Write("binary { "); ZStreamW_HexStrim(" ", "", 16, fStrimW).CopyAllFrom(theStream, nullptr, nullptr); fStrimW.Write(" }\n"); } else { // We've got more than 16 bytes, break them up into nice lines. fStrimW.Write("binary\n"); spWriteIndent(fStrimW, fIndent + 1); fStrimW.Write("{"); uint64 size; string chunkSeparator = "\n" + string(fIndent + 1, '\t'); ZStreamW_HexStrim(" ", chunkSeparator, 16, fStrimW) .CopyAllFrom(theStream, &size, nullptr); fStrimW.Write("\n"); spWriteIndent(fStrimW, fIndent + 1); fStrimW.Writef("} // %lld bytes\n", size); } } else { uint64 size; iStream.SkipAll(&size); if (fInBlock) spWriteIndent(fStrimW, fIndent); fStrimW.Writef("binary { /* content not shown */ } // %d bytes\n", size); } }
ZTBQueryNode_ID_Constant::ZTBQueryNode_ID_Constant(const ZStreamR& iStreamR) { if (uint32 theCount = sReadCount(iStreamR)) { fIDs.reserve(theCount); while (theCount--) fIDs.push_back(iStreamR.ReadUInt64()); } }
static bool spReadMore(vector<char>& ioBuf, const ZStreamR& r) { const size_t priorSize = ioBuf.size(); const size_t newSize = priorSize + 4096; ioBuf.resize(newSize); size_t countRead; r.Read(&ioBuf[priorSize], newSize - priorSize, &countRead); ioBuf.resize(priorSize + countRead); return countRead != 0; }
void ZStreamW_Null::Internal_CopyFrom(const ZStreamR& iStreamR, uint64 iCount, uint64* oCountRead, uint64* oCountWritten) { uint64 countSkipped; iStreamR.Skip(iCount, &countSkipped); if (oCountRead) *oCountRead = countSkipped; if (oCountWritten) *oCountWritten = countSkipped; }
/// \sa ZBlackBerry::Device_Client::Read bool ZBlackBerryServer::Handler_DeviceFinished::Read(const ZStreamR& r) { ZLOGFUNCTION(eDebug + 2); const bool req = r.ReadBool(); ZAssert(!req); fOpen = false; //##ZStreamerWriter::Wake(); return false; }
static string spReadZeroTerminatedString(const ZStreamR& iStream) { string theString; while (true) { char theChar = iStream.ReadInt8(); if (theChar == 0) break; theString += theChar; } return theString; }
void ZStreamWPos_Null::Internal_CopyFrom(const ZStreamR& iStreamR, uint64 iCount, uint64* oCountRead, uint64* oCountWritten) { uint64 countSkipped; iStreamR.Skip(iCount, &countSkipped); if (oCountRead) *oCountRead = countSkipped; if (oCountWritten) *oCountWritten = countSkipped; fPosition += countSkipped; fSize = max(fSize, fPosition); }
static ZRef<ZTBQueryNode> sNodeFromStream(const ZStreamR& iStreamR) { uint8 theType = iStreamR.ReadUInt8(); switch (theType) { case 0: return ZRef<ZTBQueryNode>(); case 1: return new ZTBQueryNode_All(iStreamR); case 2: return new ZTBQueryNode_Combo(iStreamR); case 3: return new ZTBQueryNode_Difference(iStreamR); case 4: return new ZTBQueryNode_First(iStreamR); case 5: return new ZTBQueryNode_ID_Constant(iStreamR); case 6: return new ZTBQueryNode_ID_FromSource(iStreamR); case 7: return new ZTBQueryNode_Property(iStreamR); } throw runtime_error("ZTBQuery, sNodeFromStream, unknown node type"); }
static void sReadImageData(const ZStreamR& iStream, bool iInterlaced, const ZRect& iBounds, ZRef<ZDCPixmapRaster> ioRaster) { uint8 initialCodeSize = iStream.ReadUInt8(); StreamR_Chunk theSIC(iStream); ZStreamR_LZWDecode theSILZW(initialCodeSize, theSIC); ZDCPixmapNS::PixvalDesc sourcePixvalDesc(8, true); void* destBaseAddress = ioRaster->GetBaseAddress(); ZDCPixmapNS::RasterDesc destRasterDesc = ioRaster->GetRasterDesc(); vector<uint8> theRowBufferVector(iBounds.Width()); void* theRowBuffer = &theRowBufferVector[0]; if (iInterlaced) { for (int pass = 0; pass < 4; ++pass) { for (ZCoord currentY = iBounds.top + sInterlaceStart[pass]; currentY < iBounds.bottom; currentY += sInterlaceIncrement[pass]) { theSILZW.Read(theRowBuffer, iBounds.Width()); void* destRowAddress = destRasterDesc.CalcRowAddress(destBaseAddress, currentY); ZDCPixmapNS::sBlitRowPixvals(theRowBuffer, sourcePixvalDesc, 0, destRowAddress, destRasterDesc.fPixvalDesc, iBounds.left, iBounds.Width()); } } } else { for (ZCoord currentY = iBounds.top; currentY < iBounds.bottom; ++currentY) { theSILZW.Read(theRowBuffer, iBounds.Width()); void* destRowAddress = destRasterDesc.CalcRowAddress(destBaseAddress, currentY); ZDCPixmapNS::sBlitRowPixvals(theRowBuffer, sourcePixvalDesc, 0, destRowAddress, destRasterDesc.fPixvalDesc, iBounds.left, iBounds.Width()); } } }
static void sReadColorTable(const ZStreamR& iStream, size_t iCount, vector<ZRGBColorPOD>& oColorTable) { oColorTable.resize(iCount); vector<uint8> readColorTable(iCount * 3); iStream.Read(&readColorTable[0], readColorTable.size()); const uint8* readColor = &readColorTable[0]; ZRGBColorPOD* oColor = &oColorTable[0]; for (size_t x = 0; x < iCount; ++x) { oColor->red = (*readColor++) * 0x101; oColor->green = (*readColor++) * 0x101; oColor->blue = (*readColor++) * 0x101; oColor->alpha = 0xFFFFU; ++oColor; } }
void ZStreamW_Memory::pCopyFrom(const ZStreamR& iStreamR, uint64 iCount, uint64* oCountRead, uint64* oCountWritten) { if (oCountRead) *oCountRead = 0; if (oCountWritten) *oCountWritten = 0; while (iCount) { size_t countRead; iStreamR.Read(fAddress, iCount, &countRead); if (countRead == 0) break; fAddress += countRead; iCount -= countRead; if (oCountRead) *oCountRead += countRead; if (oCountWritten) *oCountWritten += countRead; } }
static void sReadRLE4(const ZStreamR& iStream, ZCoord iWidth, ZCoord iHeight, size_t iRowBytes, bool iFlip, uint8* iBuffer) { ZCoord currentRow = 0; ZCoord currentCol = 0; bool done = false; while (!done) { uint8 count = iStream.ReadUInt8(); uint8 command = iStream.ReadUInt8(); if (count == 0) { switch (command) { case 0: // Move to start of next row { currentRow += 1; currentCol = 0; break; } case 1: // All done { done = true; break; } case 2: // Offset by some relative amount { currentCol += iStream.ReadUInt8(); currentRow += iStream.ReadUInt8(); break; } default: // Absolute data follows -- the length is the value of 'command' { uint8* rowStart = iBuffer + iRowBytes * (iFlip ? iHeight - currentRow - 1 : currentRow); uint8 hi, lo; for (int i = 0; i < command; ++i) { if ((i & 1) == 0) { uint8 data = iStream.ReadUInt8(); hi = data >> 4; lo = data & 0x0f; } if ((currentCol & 1) == 0) { if ((i & 1) == 0) rowStart[currentCol / 2] = hi << 4; else rowStart[currentCol / 2] = lo << 4; } else { if ((i & 1) == 0) rowStart[currentCol / 2] |= hi; else rowStart[currentCol / 2] |= lo; } ++currentCol; } switch (command & 0x03) { case 1: case 2: iStream.Skip(1); break; } break; } } } else {
ZTBSpec::Comparator::Comparator(const ZStreamR& iStreamR) { fRel = (ERel)iStreamR.ReadUInt8(); fStrength = iStreamR.ReadUInt8(); }
static void sReadPixmap(const ZStreamR& inStream, ZDCPixmap& outPixmap) { uint16 rowBytes = inStream.ReadUInt16(); if (!(rowBytes & 0x8000)) ::sThrowBadFormat(); rowBytes &= 0x7FFF; ZRect bounds; bounds.top = inStream.ReadInt16(); bounds.left = inStream.ReadInt16(); bounds.bottom = inStream.ReadInt16(); bounds.right = inStream.ReadInt16(); inStream.ReadInt16(); // version inStream.ReadInt16(); // packType inStream.ReadInt32(); // packSize inStream.ReadInt32(); // hRes inStream.ReadInt32(); //vRes short pixelType = inStream.ReadInt16(); // pixelType short pixelSize = inStream.ReadInt16(); // pixelSize short cmpCount = inStream.ReadInt16(); // cmpCount short cmpSize = inStream.ReadInt16(); // cmpSize inStream.ReadInt32(); // planeBytes inStream.ReadInt32(); // pmTable inStream.ReadInt32(); // pmReserved // We only deal with pixel type of 0 (indexed pixels) if (pixelType != 0) ::sThrowUnsupportedFormat(); // indexed pixels have a cmpCount of 1 if (cmpCount != 1) ::sThrowBadFormat(); // pixelSize and cmpSize should be equal for indexed pixels if (pixelSize != cmpSize) ::sThrowBadFormat(); // Next on the stream is the color table vector<ZRGBColor> theColorTable; inStream.ReadInt32(); // ctSeed inStream.ReadInt16(); // ctFlags short ctSize = inStream.ReadInt16(); for (int i = 0; i <= ctSize; ++i) { inStream.ReadInt16(); // colorSpecIndex ZRGBColor theColor; theColor.red = inStream.ReadUInt16(); theColor.green = inStream.ReadUInt16(); theColor.blue = inStream.ReadUInt16(); theColorTable.push_back(theColor); } // Now we have the source rect inStream.Skip(8); // and the destination rect inStream.Skip(8); // Penultimately we have the mode inStream.ReadUInt16(); // The remaining data is the packed pixels. Allocate our ZDCPixmap // using the size we read in, but with no initialized data. ZDCPixmap thePixmap(bounds.Size(), ZDCPixmapNS::eFormatEfficient_Color_32); void* baseAddress = thePixmap.GetBaseAddress(); ZDCPixmapNS::RasterDesc theRasterDesc = thePixmap.GetRasterDesc(); ZDCPixmapNS::PixelDesc thePixelDesc = thePixmap.GetPixelDesc(); ::sUnpackFromStream(inStream, bounds.Width(), bounds.Height(), rowBytes, pixelSize, &theColorTable[0], theColorTable.size(), baseAddress, theRasterDesc, thePixelDesc); outPixmap = thePixmap; }
static string spReadString(const ZStreamR& r) { if (size_t theLength = r.ReadCount()) return r.ReadString(theLength); return string(); }
void ZDCPixmapDecoder_GIF::Imp_Read(const ZStreamR& iStream, ZDCPixmap& oPixmap) { oPixmap = ZDCPixmap(); if (fReadEnd) return; if (!fReadHeader) { fReadHeader = true; if ('G' != iStream.ReadUInt8() || 'I' != iStream.ReadUInt8() || 'F' != iStream.ReadUInt8() || '8' != iStream.ReadUInt8()) { spThrowBadFormat(); } uint8 version = iStream.ReadUInt8(); if ('7' != version && '9' != version) spThrowBadFormat(); if ('a' != iStream.ReadUInt8()) spThrowBadFormat(); fIs89a = version == '9'; fSize.h = iStream.ReadUInt16LE(); fSize.v = iStream.ReadUInt16LE(); uint8 strmFlags = iStream.ReadUInt8(); bool strmHasGlobalColorTable = (strmFlags & 0x80) != 0; //uint8 strmColorResolution = (strmFlags & 0x7) >> 4; //bool strmSortFlag = (strmFlags & 0x08) != 0; uint8 strmGlobalColorTableSize = (strmFlags & 0x7); uint8 strmBackgroundColorIndex = iStream.ReadUInt8(); /*uint8 strmPixelAspectRatio = */iStream.ReadUInt8(); if (strmHasGlobalColorTable) { vector<ZRGBA_POD> theColors; spReadColorTable(iStream, 1 << (strmGlobalColorTableSize + 1), theColors); fPixelDesc = PixelDesc(&theColors[0], theColors.size()); } static int sPhysicalDepths[] = { 1, // 0 2, // 1 4, // 2 4, // 3 8, // 4 8, // 5 8, // 6 8, // 7 }; int rowBytes = sCalcRowBytes(sPhysicalDepths[strmGlobalColorTableSize], fSize.h, 4); RasterDesc theRasterDesc( PixvalDesc(strmGlobalColorTableSize + 1, true), rowBytes, fSize.v, false); fRaster = new ZDCPixmapRaster_Simple(theRasterDesc); fRaster->Fill(strmBackgroundColorIndex); } else { // Clone our existing raster which contains the pixels // making up the pixmap we last returned. fRaster = new ZDCPixmapRaster_Simple(fRaster); } for (;;) { uint8 blockType = iStream.ReadUInt8(); if (blockType == ';') { // We've reached the end of the GIF stream. fReadEnd = true; return; } else if (blockType == '!') { // It's an extension. // Ignore the extension type iStream.ReadUInt8(); // Skip any data blocks. StreamR_Chunk(iStream).SkipAll(); } else if (blockType == ',') { // It's an image. ZRectPOD curBounds; curBounds.left = iStream.ReadUInt16LE(); curBounds.top = iStream.ReadUInt16LE(); curBounds.right = curBounds.left + iStream.ReadUInt16LE(); curBounds.bottom = curBounds.top + iStream.ReadUInt16LE(); uint8 strmFlags = iStream.ReadUInt8(); bool strmHasLocalColorTable = (strmFlags & 0x80) != 0; bool strmIsInterlaced = (strmFlags & 0x40) != 0; //bool strmSortFlag = (strmFlags & 0x20) != 0; uint8 strmLocalColorTableSize = (strmFlags & 0x7); PixelDesc thePixelDesc = fPixelDesc; if (strmHasLocalColorTable) { vector<ZRGBA_POD> theColors; spReadColorTable(iStream, 1 << (strmLocalColorTableSize + 1), theColors); thePixelDesc = PixelDesc(&theColors[0], theColors.size()); } spReadImageData(iStream, strmIsInterlaced, curBounds, fRaster); oPixmap = new ZDCPixmapRep(fRaster, sRect(fSize), thePixelDesc); return; } } }
void NPainter_FromPICT(const ZStreamR& inStream, ZDCPixmap& outPixmap) { inStream.ReadInt16(); // picSize. This field has been obsolete since 1987. inStream.ReadInt16(); // picFrame.top inStream.ReadInt16(); // picFrame.left inStream.ReadInt16(); // picFrame.bottom inStream.ReadInt16(); // picFrame.right uint8 ch; // skip any empty bytes while ((ch = inStream.ReadUInt8()) == 0) {} if (ch != 0x11) throw runtime_error("NPainter_FromPICT, expected version opcode"); if ((ch = inStream.ReadUInt8()) != 0x02) throw runtime_error("NPainter_FromPICT, expected version number 2"); if ((ch = inStream.ReadUInt8()) != 0xFF) throw runtime_error("NPainter_FromPICT, expected subcode 0xFF"); // The order of remaining opcodes is not always the same, hence we use a loop to consume them. uint16 opcode; while (true) { opcode = inStream.ReadUInt16(); if (opcode == 0x0C00) // Header, followed by 24 bytes of data we don't need inStream.Skip(24); else if (opcode == 0x01) // Clip rgn { unsigned short clipBytes = inStream.ReadUInt16() - sizeof(short); inStream.Skip(clipBytes); } else if (opcode != 0x1E) // Hilite break; } if (opcode != 0x98) throw runtime_error("NPainter_FromPICT, expected packbits opcode"); // Do the actual read ::sReadPixmap(inStream, outPixmap); // Suck up remaining data while ((ch = inStream.ReadUInt8()) == 0x00) {} if (ch != 0xFF) throw runtime_error("NPainter_FromPICT, expected end of picture opcode"); }
void ZASParser::ParseHandler::ParsedBinary(const ZStreamR& iStream) { // Just suck up and ignore the data iStream.SkipAll(nil); }
void ZDCPixmapDecoder_GIF::Imp_Read(const ZStreamR& iStream, ZDCPixmap& oPixmap) { oPixmap = ZDCPixmap(); if (fReadEnd) return; if (!fReadHeader) { fReadHeader = true; if ('G' != iStream.ReadUInt8() || 'I' != iStream.ReadUInt8() || 'F' != iStream.ReadUInt8() || '8' != iStream.ReadUInt8()) { sThrowBadFormat(); } uint8 version = iStream.ReadUInt8(); if ('7' != version && '9' != version) sThrowBadFormat(); if ('a' != iStream.ReadUInt8()) sThrowBadFormat(); fIs89a = version == '9'; fSize.h = iStream.ReadUInt16LE(); fSize.v = iStream.ReadUInt16LE(); uint8 strmFlags = iStream.ReadUInt8(); bool strmHasGlobalColorTable = (strmFlags & 0x80) != 0; uint8 strmColorResolution = (strmFlags & 0x7) >> 4; bool strmSortFlag = (strmFlags & 0x08) != 0; uint8 strmGlobalColorTableSize = (strmFlags & 0x7); uint8 strmBackgroundColorIndex = iStream.ReadUInt8(); uint8 strmPixelAspectRatio = iStream.ReadUInt8(); if (strmHasGlobalColorTable) { vector<ZRGBColorPOD> theColors; sReadColorTable(iStream, 1 << (strmGlobalColorTableSize + 1), theColors); fPixelDesc = ZDCPixmapNS::PixelDesc(&theColors[0], theColors.size()); } static int sPhysicalDepths[] = { 1, // 0 2, // 1 4, // 2 4, // 3 8, // 4 8, // 5 8, // 6 8, // 7 }; int rowBytes = ZDCPixmapNS::sCalcRowBytes(sPhysicalDepths[strmGlobalColorTableSize], fSize.h); ZDCPixmapNS::RasterDesc theRasterDesc( ZDCPixmapNS::PixvalDesc(strmGlobalColorTableSize + 1, true), rowBytes, fSize.v, false); fRaster = new ZDCPixmapRaster_Simple(theRasterDesc); fRaster->Fill(strmBackgroundColorIndex); }
ZTBQuery::SortSpec::SortSpec(const ZStreamR& iStreamR) : fPropName(iStreamR), fAscending(iStreamR.ReadBool()), fStrength(iStreamR.ReadUInt8()) {}
/** Copy data from \a iStreamR to \a iStreamW by reading it into a buffer and writing from that buffer. If more than 8K is to be copied we try to allocate an 8K buffer in the heap. If less than 8K is to be copied, or the heap buffer could not be allocated, we use a 1K buffer on the stack. */ void sCopyReadToWrite(const ZStreamR& iStreamR, const ZStreamW& iStreamW, uint64 iCount, uint64* oCountRead, uint64* oCountWritten) { if (oCountRead) *oCountRead = 0; if (oCountWritten) *oCountWritten = 0; if (iCount == 0) return; if (iCount > 8192) { // Try to allocate and use an 8K heap-based buffer. if (uint8* heapBuffer = new(nothrow) uint8[8192]) { try { uint64 countRemaining = iCount; while (countRemaining > 0) { size_t countRead; iStreamR.Read(heapBuffer, min(countRemaining, uint64(8192)), &countRead); if (countRead == 0) break; if (oCountRead) *oCountRead += countRead; countRemaining -= countRead; uint8* tempSource = heapBuffer; while (countRead > 0) { size_t countWritten; iStreamW.Write(tempSource, countRead, &countWritten); if (countWritten == 0) { countRemaining = 0; break; } tempSource += countWritten; countRead -= countWritten; if (oCountWritten) *oCountWritten += countWritten; } } } catch (...) { delete[] heapBuffer; throw; } delete[] heapBuffer; return; } } // We'll get to here if we need to move 8192 bytes or less, or if // allocation of the heap buffer failed. // Use a stack-based 1024 byte buffer if we're moving less than 8K and thus will iterate // fewer than 8 times. Previously we'd unconditionally used one of size 4096, but that's // fairly large and can contribute to blowing the stack on MacOS. uint8 localBuffer[1024]; uint64 countRemaining = iCount; while (countRemaining > 0) { size_t countRead; iStreamR.Read(localBuffer, min(countRemaining, uint64(sizeof(localBuffer))), &countRead); if (countRead == 0) break; if (oCountRead) *oCountRead += countRead; countRemaining -= countRead; uint8* tempSource = localBuffer; while (countRead > 0) { size_t countWritten; iStreamW.Write(tempSource, countRead, &countWritten); if (countWritten == 0) { countRemaining = 0; break; } tempSource += countWritten; countRead -= countWritten; if (oCountWritten) *oCountWritten += countWritten; } } }