Microsoft-3D-Movie-Maker/kauai/SRC/STREAM.CPP

974 lines
23 KiB
C++

/* Copyright (c) Microsoft Corporation.
Licensed under the MIT License. */
/***************************************************************************
Author: ShonK
Project: Kauai
Reviewed:
Copyright (c) Microsoft Corporation
Stream classes. BSM is totally in memory. BSF allows a stream
to have pieces in files and other pieces in memory.
***************************************************************************/
#include "util.h"
ASSERTNAME
//min size of initial piece on file
const long kcbMinFloFile = 2048;
RTCLASS(BSM)
RTCLASS(BSF)
/***************************************************************************
Constructor for an in-memory byte stream.
***************************************************************************/
BSM::BSM(void)
{
_hqrgb = hqNil;
_ibMac = 0;
_cbMinGrow = 0;
AssertThis(fobjAssertFull);
}
/***************************************************************************
Destructor for an in-memory byte stream.
***************************************************************************/
BSM::~BSM(void)
{
AssertThis(fobjAssertFull);
FreePhq(&_hqrgb);
}
/***************************************************************************
Set the amount to grow by.
***************************************************************************/
void BSM::SetMinGrow(long cb)
{
AssertThis(0);
AssertIn(cb, 0, kcbMax);
_cbMinGrow = cb;
}
/***************************************************************************
Make sure there is at least cb bytes of space. If fShrink is true,
the amount of memory allocated by the BSM may decrease.
***************************************************************************/
bool BSM::FEnsureSpace(long cb, bool fShrink)
{
AssertThis(0);
return _FEnsureSize(_ibMac + cb, fShrink);
}
/***************************************************************************
Return a locked pointer into the byte stream. The stream is stored
contiguously.
***************************************************************************/
void *BSM::PvLock(long ib)
{
AssertThis(0);
AssertIn(ib, 0, _ibMac + 1);
if (hqNil == _hqrgb)
return pvNil;
return PvAddBv(PvLockHq(_hqrgb), ib);
}
/***************************************************************************
Unlock the stream.
***************************************************************************/
void BSM::Unlock(void)
{
AssertThis(0);
if (hqNil != _hqrgb)
UnlockHq(_hqrgb);
}
/***************************************************************************
Fetch some bytes from the stream.
***************************************************************************/
void BSM::FetchRgb(long ib, long cb, void *prgb)
{
AssertThis(0);
AssertIn(ib, 0, _ibMac + 1);
AssertIn(cb, 0, _ibMac + 1 - ib);
AssertPvCb(prgb, cb);
if (cb > 0)
CopyPb(PvAddBv(QvFromHq(_hqrgb), ib), prgb, cb);
}
/***************************************************************************
Replace the range [ib,ib + cbDel) with cbIns bytes from prgb. If cbIns
is zero, prgb may be nil.
***************************************************************************/
bool BSM::FReplace(void *prgb, long cbIns, long ib, long cbDel)
{
AssertThis(fobjAssertFull);
AssertIn(cbIns, 0, kcbMax);
AssertPvCb(prgb, cbIns);
AssertIn(ib, 0, _ibMac + 1);
AssertIn(cbDel, 0, _ibMac + 1 - ib);
byte *qrgb;
if (!_FEnsureSize(_ibMac + cbIns - cbDel, fFalse))
return fFalse;
qrgb = (byte *)QvFromHq(_hqrgb);
if (ib < _ibMac - cbDel && cbDel != cbIns)
BltPb(qrgb + ib + cbDel, qrgb + ib + cbIns, _ibMac - cbDel - ib);
if (cbIns > 0)
CopyPb(prgb, qrgb + ib, cbIns);
_ibMac += cbIns - cbDel;
AssertThis(fobjAssertFull);
return fTrue;
}
/***************************************************************************
Write the byte stream to a file.
***************************************************************************/
bool BSM::FWriteRgb(PFLO pflo, long ib)
{
AssertThis(0);
AssertPo(pflo, 0);
BLCK blck(pflo);
return FWriteRgb(&blck, ib);
}
/***************************************************************************
Write the byte stream to a block.
***************************************************************************/
bool BSM::FWriteRgb(PBLCK pblck, long ib)
{
AssertThis(fobjAssertFull);
AssertPo(pblck, 0);
AssertIn(ib, 0, CbOfHq(_hqrgb) - pblck->Cb() + 1);
bool fRet;
if (ib + pblck->Cb() > _ibMac)
{
Bug("blck is too big");
return fFalse;
}
if (pblck->Cb() == 0)
return fTrue;
fRet = pblck->FWrite(PvAddBv(PvLockHq(_hqrgb), ib));
UnlockHq(_hqrgb);
return fRet;
}
/***************************************************************************
Make sure the hq is at least cbMin bytes. If fShrink is true, make the
hq exactly cbMin bytes long.
***************************************************************************/
bool BSM::_FEnsureSize(long cbMin, bool fShrink)
{
AssertThis(fobjAssertFull);
AssertIn(cbMin, 0, kcbMax);
long cb = hqNil == _hqrgb ? 0 : CbOfHq(_hqrgb);
if (cbMin <= cb && (!fShrink || cbMin == cb))
return fTrue;
if (cbMin == 0)
{
if (fShrink)
FreePhq(&_hqrgb);
return fTrue;
}
if (hqNil == _hqrgb)
{
return FAllocHq(&_hqrgb, LwMax(cbMin, _cbMinGrow), fmemNil, mprNormal) ||
_cbMinGrow > cbMin && FAllocHq(&_hqrgb, cbMin, fmemNil, mprNormal);
}
return FResizePhq(&_hqrgb, LwMax(cbMin, cb + _cbMinGrow), fmemNil, mprNormal) ||
cb + _cbMinGrow > cbMin && FResizePhq(&_hqrgb, cbMin, fmemNil, mprNormal);
}
#ifdef DEBUG
/***************************************************************************
Assert the validity of a byte stream (BSF).
***************************************************************************/
void BSM::AssertValid(ulong grf)
{
BSM_PAR::AssertValid(grf);
AssertIn(_ibMac, 0, kcbMax);
AssertIn(_cbMinGrow, 0, kcbMax);
if (_ibMac > 0)
{
AssertHq(_hqrgb);
AssertIn(_ibMac, 0, CbOfHq(_hqrgb) + 1);
}
else if (hqNil != _hqrgb)
AssertHq(_hqrgb);
}
/***************************************************************************
Mark memory for the BSM.
***************************************************************************/
void BSM::MarkMem(void)
{
AssertValid(fobjAssertFull);
BSM_PAR::MarkMem();
MarkHq(_hqrgb);
}
#endif //DEBUG
/***************************************************************************
Constructor for a stream.
***************************************************************************/
BSF::BSF(void)
{
_pggflo = pvNil;
_ibMac = 0;
AssertThis(fobjAssertFull);
}
/***************************************************************************
Destructor for a stream.
***************************************************************************/
BSF::~BSF(void)
{
AssertThis(fobjAssertFull);
long iflo;
FLO flo;
if (0 < _ibMac)
{
//release all our reference counts
for (iflo = _pggflo->IvMac(); iflo-- > 0; )
{
_pggflo->GetFixed(iflo, &flo);
if (pvNil != flo.pfil)
ReleasePpo(&flo.pfil);
}
}
ReleasePpo(&_pggflo);
}
/***************************************************************************
Find the flo that contains the given ib and assign *pib the postion
of the first byte in the flo and *pcb the size of the flo.
***************************************************************************/
long BSF::_IfloFind(long ib, long *pib, long *pcb)
{
AssertBaseThis(0);
AssertIn(ib, 0, _ibMac + 1);
AssertVarMem(pib);
AssertNilOrVarMem(pcb);
long iflo, cb;
FLO flo;
iflo = 0;
if (_ibMac > 0)
{
for (cb = ib; iflo < _pggflo->IvMac(); iflo++)
{
_pggflo->GetFixed(iflo, &flo);
if (flo.cb > cb)
{
*pib = ib - cb;
if (pvNil != pcb)
*pcb = flo.cb;
return iflo;
}
cb -= flo.cb;
}
}
*pib = _ibMac;
if (pvNil != pcb)
*pcb = 0;
return iflo;
}
/***************************************************************************
Make sure ib is on a piece boundary.
***************************************************************************/
bool BSF::_FEnsureSplit(long ib, long *piflo)
{
AssertBaseThis(0);
AssertIn(ib, 0, _ibMac + 1);
AssertNilOrVarMem(piflo);
long iflo, ibMin, cbT;
FLO flo;
if (pvNil == _pggflo)
{
if (pvNil == (_pggflo = GG::PggNew(size(FLO))))
return fFalse;
//REVIEW shonk: what values should we use for SetMinGrow?
//_pggflo->SetMinGrow(2, 100);
}
iflo = _IfloFind(ib, &ibMin, &cbT);
AssertIn(ib, ibMin, ibMin + cbT + (ibMin == _ibMac));
if (ib == ibMin)
{
if (pvNil != piflo)
*piflo = iflo;
return fTrue;
}
_pggflo->GetFixed(iflo, &flo);
Assert(cbT == flo.cb, 0);
cbT = ib - ibMin;
flo.cb -= cbT;
if (pvNil != flo.pfil)
flo.fp += cbT;
if (!_pggflo->FInsert(iflo + 1, 0, pvNil, &flo))
{
TrashVar(piflo);
return fFalse;
}
if (pvNil == flo.pfil && !_pggflo->FMoveRgb(iflo, cbT, iflo + 1, 0, flo.cb))
{
_pggflo->Delete(iflo + 1);
TrashVar(piflo);
return fFalse;
}
flo.cb = cbT;
if (pvNil != flo.pfil)
{
flo.fp -= cbT;
flo.pfil->AddRef();
}
_pggflo->PutFixed(iflo, &flo);
if (pvNil != piflo)
*piflo = iflo + 1;
return fTrue;
}
/***************************************************************************
Enumerate over all pieces spanning ibMin to ibLim and attempt to merge
any adjacent ones.
***************************************************************************/
void BSF::_AttemptMerge(long ibMin, long ibLim)
{
AssertBaseThis(0);
AssertIn(ibMin, 0, _ibMac + 1);
AssertIn(ibLim, ibMin, _ibMac + 1);
long iflo, ib;
FLO flo, floT;
if (pvNil == _pggflo)
return;
iflo = _IfloFind(LwMax(0, ibMin - 1), &ib);
while (ib < ibLim && iflo < _pggflo->IvMac() - 1)
{
_pggflo->GetFixed(iflo, &flo);
_pggflo->GetFixed(iflo + 1, &floT);
if (flo.pfil != floT.pfil ||
pvNil != flo.pfil && flo.fp + flo.cb != floT.fp)
{
//cant merge them, try the next
iflo++;
ib += flo.cb;
continue;
}
if (pvNil == flo.pfil)
_pggflo->Merge(iflo + 1, iflo);
else
{
//merge the two file based flo's
_pggflo->Delete(iflo + 1);
ReleasePpo(&floT.pfil);
AssertPo(flo.pfil, 0);
}
flo.cb += floT.cb;
_pggflo->PutFixed(iflo, &flo);
}
}
/***************************************************************************
Replace a range in this bsf with the range in the given bsf. This
does the complete insertion, then the deletion.
***************************************************************************/
bool BSF::FReplaceBsf(PBSF pbsfSrc, long ibSrc, long cbSrc, long ibDst, long cbDel)
{
AssertThis(fobjAssertFull);
AssertPo(pbsfSrc, 0);
AssertIn(ibSrc, 0, pbsfSrc->_ibMac + 1);
AssertIn(cbSrc, 0, pbsfSrc->_ibMac + 1 - ibSrc);
AssertIn(ibDst, 0, _ibMac + 1);
AssertIn(cbDel, 0, _ibMac + 1 - ibDst);
long ifloMinSrc, ifloLimSrc, ifloMinWhole, ifloDst, iflo;
long ibMinSrc, ibLimSrc, ibMinWhole, ib;
long cbMinFlo, cbLimFlo, cbIns, cbT;
FLO flo;
byte *pb;
bool fRet;
//REVIEW shonk: if we're only inserting a non-file piece of pbsfSrc, should
//we optimize and redirect this to FReplace?
if (cbSrc == 0 && cbDel == 0)
return fTrue;
//make sure the piece table exists and is split at ibDst
if (!_FEnsureSplit(ibDst, &ifloDst))
return fFalse;
//cbIns is the number of bytes already inserted (for cleanup)
cbIns = 0;
//get the flo's to insert
ifloMinSrc = pbsfSrc->_IfloFind(ibSrc, &ibMinSrc, &cbMinFlo);
ifloLimSrc = pbsfSrc->_IfloFind(ibSrc + cbSrc, &ibLimSrc, &cbLimFlo);
if (ifloMinSrc < ifloLimSrc)
{
//first insert the whole pieces
if (ibSrc > ibMinSrc)
{
ifloMinWhole = ifloMinSrc + 1;
ibMinWhole = ibMinSrc + cbMinFlo;
}
else
{
ifloMinWhole = ifloMinSrc;
ibMinWhole = ibMinSrc;
}
if (ifloMinWhole < ifloLimSrc)
{
if (!_pggflo->FCopyEntries(pbsfSrc->_pggflo, ifloMinWhole, ifloDst,
ifloLimSrc - ifloMinWhole))
{
goto LFail;
}
cbIns = ibLimSrc - ibMinWhole;
_ibMac += cbIns;
//adjust the usage counts on the file pieces
for (iflo = ifloDst + ifloLimSrc - ifloMinWhole; iflo-- > ifloDst; )
{
_pggflo->GetFixed(iflo, &flo);
if (pvNil != flo.pfil)
flo.pfil->AddRef();
}
}
//insert the front piece
if (ifloMinSrc < ifloMinWhole)
{
cbT = cbMinFlo - ibSrc + ibMinSrc;
pbsfSrc->_pggflo->GetFixed(ifloMinSrc, &flo);
if (pvNil == flo.pfil)
{
//a memory piece
pb = (byte *)pbsfSrc->_pggflo->PvLock(ifloMinSrc);
fRet = FReplace(pb + ibSrc - ibMinSrc, cbT, ibDst, 0);
pbsfSrc->_pggflo->Unlock();
}
else
{
//a file piece
flo.fp += ibSrc - ibMinSrc;
flo.cb = cbT;
fRet = FReplaceFlo(&flo, fFalse, ibDst, 0);
}
if (!fRet)
goto LFail;
cbIns += cbT;
}
else
_AttemptMerge(ibDst, ibDst);
}
//insert the back piece
Assert(ibLimSrc <= ibSrc + cbSrc, 0);
if (ibLimSrc < ibSrc + cbSrc || cbDel > 0)
{
ib = LwMax(ibSrc, ibLimSrc);
cbT = ibSrc + cbSrc - ib;
Assert(cbIns + cbT == cbSrc, "didn't insert the correct amount!");
if (cbT <= 0)
fRet = FReplace(pvNil, 0, ibDst + cbIns, cbDel);
else
{
pbsfSrc->_pggflo->GetFixed(ifloLimSrc, &flo);
if (pvNil == flo.pfil)
{
//a memory piece
pb = (byte *)pbsfSrc->_pggflo->PvLock(ifloLimSrc);
fRet = FReplace(pb + ib - ibLimSrc, cbT, ibDst + cbIns, cbDel);
pbsfSrc->_pggflo->Unlock();
}
else
{
//a file piece
flo.fp += ib - ibLimSrc;
flo.cb = cbT;
fRet = FReplaceFlo(&flo, fFalse, ibDst + cbIns, cbDel);
}
}
if (!fRet)
{
LFail:
if (cbIns > 0)
AssertDo(FReplace(pvNil, 0, ibDst, cbIns), "cleanup failed!");
AssertThis(fobjAssertFull);
return fFalse;
}
}
else
{
Assert(cbIns == cbSrc, "didn't insert the correct amount!");
_AttemptMerge(ibDst + cbSrc, ibDst + cbSrc);
}
AssertThis(fobjAssertFull);
return fTrue;
}
/***************************************************************************
Replace the range [ib, ib + cbDel) with cbIns bytes from prgb.
***************************************************************************/
bool BSF::FReplace(void *prgb, long cbIns, long ib, long cbDel)
{
AssertThis(fobjAssertFull);
AssertIn(ib, 0, _ibMac + 1);
AssertIn(cbDel, 0, _ibMac - ib + 1);
AssertIn(cbIns, 0, kcbMax);
AssertPvCb(prgb, cbIns);
long ibT;
long iflo, cbT;
FLO flo;
if (cbDel == 0 && cbIns == 0)
return fTrue;
//make sure the _pggflo exists
if (!_FEnsureSplit(0))
return fFalse;
//get the flo of interest and the ibMin of the flo
iflo = _IfloFind(ib, &ibT);
//from here on, ibT is the offset into the current flo (iflo)
ibT = ib - ibT;
//if ib is in a file flo, split it
if (ibT > 0)
{
_pggflo->GetFixed(iflo, &flo);
if (pvNil != flo.pfil)
{
if (!_FEnsureSplit(ib, &iflo))
goto LFail;
ibT = 0;
}
}
if (cbIns > 0 && !_pggflo->FEnsureSpace(1, cbIns))
{
LFail:
_AttemptMerge(ib, ib);
AssertThis(fobjAssertFull);
return fFalse;
}
if (ibT > 0 && cbDel > 0)
{
//we need to start deleting in the middle of a piece
_pggflo->GetFixed(iflo, &flo);
Assert(pvNil == flo.pfil, "why wasn't this flo split?");
if (ibT + cbDel < flo.cb)
{
//deleting just part of this piece and no others
_pggflo->DeleteRgb(iflo, ibT, cbDel);
flo.cb -= cbDel;
_pggflo->PutFixed(iflo, &flo);
_ibMac -= cbDel;
cbDel = 0;
}
else
{
//deleting to the end of this piece
cbT = flo.cb - ibT;
_pggflo->DeleteRgb(iflo, ibT, cbT);
flo.cb = ibT;
_pggflo->PutFixed(iflo, &flo);
_ibMac -= cbT;
cbDel -= cbT;
iflo++;
ibT = 0;
}
}
Assert(ibT == 0 || cbDel == 0, "wrong ib");
while (cbDel > 0 && iflo < _pggflo->IvMac())
{
//deleting from the beginning of the flo
_pggflo->GetFixed(iflo, &flo);
if (cbDel < flo.cb)
{
//just remove the first part
if (pvNil != flo.pfil)
flo.fp += cbDel;
else
_pggflo->DeleteRgb(iflo, 0, cbDel);
flo.cb -= cbDel;
_ibMac -= cbDel;
cbDel = 0;
_pggflo->PutFixed(iflo, &flo);
}
else
{
//delete the whole flo
ReleasePpo(&flo.pfil);
_pggflo->Delete(iflo);
cbDel -= flo.cb;
_ibMac -= flo.cb;
}
}
//now insert the new stuff
if (cbIns > 0)
{
if (iflo < _pggflo->IvMac())
{
_pggflo->GetFixed(iflo, &flo);
if (pvNil == flo.pfil)
goto LInsertInMem;
}
Assert(ibT == 0, "wrong ib 2");
if (iflo > 0)
{
//see if the previous flow is a memory one
_pggflo->GetFixed(iflo - 1, &flo);
if (pvNil == flo.pfil)
{
iflo--;
ibT = flo.cb;
LInsertInMem:
AssertDo(_pggflo->FInsertRgb(iflo, ibT, cbIns, prgb),
"this shouldn't fail!");
flo.cb += cbIns;
_pggflo->PutFixed(iflo, &flo);
_ibMac += cbIns;
goto LTryMerge;
}
}
//create a new memory flo
flo.pfil = pvNil;
flo.cb = cbIns;
flo.fp = 0;
AssertDo(_pggflo->FInsert(iflo, cbIns, prgb, &flo), "why fail?");
_ibMac += cbIns;
}
LTryMerge:
_AttemptMerge(ib, ib + cbIns);
AssertThis(fobjAssertFull);
return fTrue;
}
/***************************************************************************
Replace the range [ib, ib + cbDel) with the flo.
***************************************************************************/
bool BSF::FReplaceFlo(PFLO pflo, bool fCopy, long ib, long cbDel)
{
AssertThis(fobjAssertFull);
AssertPo(pflo, ffloReadable);
AssertIn(ib, 0, _ibMac + 1);
AssertIn(cbDel, 0, _ibMac - ib + 1);
long iflo;
FLO flo;
bool fRet;
if (pflo->cb <= 0)
return FReplace(pvNil, 0, ib, cbDel);
if (pflo->cb < kcbMinFloFile)
{
//use a memory piece
HQ hq;
if (!pflo->FReadHq(&hq))
return fFalse;
fRet = FReplace(PvLockHq(hq), pflo->cb, ib, cbDel);
UnlockHq(hq);
FreePhq(&hq);
return fRet;
}
//insert a file flo
if (fCopy)
{
if (pvNil == (flo.pfil = FIL::PfilCreateTemp()))
return fFalse;
flo.cb = pflo->cb;
flo.fp = 0;
if (!pflo->FCopy(&flo))
{
ReleasePpo(&flo.pfil);
AssertThis(fobjAssertFull);
return fFalse;
}
pflo = &flo;
}
else
pflo->pfil->AddRef();
if (!_FEnsureSplit(ib, &iflo) || !_pggflo->FInsert(iflo, 0, pvNil, pflo))
{
pflo->pfil->Release();
_AttemptMerge(ib, ib);
AssertThis(fobjAssertFull);
return fFalse;
}
_ibMac += pflo->cb;
if (cbDel > 0)
{
//this shouldn't fail because we've already ensured a split
//at ib + pflo->cb
AssertDo(FReplace(pvNil, 0, ib + pflo->cb, cbDel), 0);
}
_AttemptMerge(ib, ib + pflo->cb);
AssertThis(fobjAssertFull);
return fTrue;
}
/***************************************************************************
Fetch cb bytes from position ib into prgb.
***************************************************************************/
void BSF::FetchRgb(long ib, long cb, void *prgb)
{
AssertThis(fobjAssertFull);
AssertIn(ib, 0, _ibMac + 1);
AssertIn(cb, 0, _ibMac - ib + 1);
AssertPvCb(prgb, cb);
long iflo, cbT, ibMin;
FLO flo;
iflo = _IfloFind(ib, &ibMin);
ib -= ibMin;
for ( ; cb > 0 && iflo < _pggflo->IvMac(); iflo++)
{
_pggflo->GetFixed(iflo, &flo);
Assert(flo.cb > ib, "_IfloFind messed up");
//get min(cb, flo.cb - ib) bytes from position ib
//then set ib to 0 and update cb
cbT = LwMin(cb, flo.cb - ib);
if (pvNil == flo.pfil)
{
//the data is in the GG
Assert(_pggflo->Cb(iflo) == flo.cb, "group element wrong size");
_pggflo->GetRgb(iflo, ib, cbT, prgb);
}
else
{
//the data is on file
if (!flo.FReadRgb(prgb, cbT, ib))
{
Warn("read failed in fetch");
FillPb(prgb, cbT, kbGarbage);
}
}
prgb = PvAddBv(prgb, cbT);
ib = 0;
cb -= cbT;
}
}
/***************************************************************************
Write a portion of a BSF to the given flo.
***************************************************************************/
bool BSF::FWriteRgb(PFLO pflo, long ib)
{
AssertThis(0);
AssertPo(pflo, 0);
BLCK blck(pflo);
return FWriteRgb(&blck, ib);
}
/***************************************************************************
Write a portion of a BSF to the given block.
***************************************************************************/
bool BSF::FWriteRgb(PBLCK pblck, long ib)
{
AssertThis(fobjAssertFull);
AssertPo(pblck, 0);
AssertIn(ib, 0, _ibMac + 1);
AssertIn(pblck->Cb(), 0, kcbMax);
long iflo;
FLO flo;
long cb, ibT, ibDst;
long cbWrite = pblck->Cb();
bool fRet = fTrue;
if (ib + cbWrite > _ibMac)
{
Bug("blck is too big");
return fFalse;
}
if (cbWrite <= 0)
return fTrue;
iflo = _IfloFind(ib, &ibT);
ib -= ibT;
_pggflo->Lock();
AssertDo(pblck->FMoveLim(-cbWrite), 0);
for (ibDst = 0; fRet && ibDst < cbWrite && iflo < _pggflo->IvMac(); iflo++)
{
Assert(pblck->Cb() == 0, 0);
_pggflo->GetFixed(iflo, &flo);
Assert(flo.cb > ib, "_IfloFind messed up");
// write min(cbWrite, flo.cb - ib) bytes from position ib
// then set ib to 0 and update cbWrite
cb = LwMin(cbWrite, flo.cb - ib);
AssertDo(pblck->FMoveLim(cb), 0);
Assert(pblck->Cb() == cb, 0);
if (pvNil == flo.pfil)
{
//the data is in the GG
Assert(_pggflo->Cb(iflo) == flo.cb, "group element wrong size");
fRet = pblck->FWrite(PvAddBv(_pggflo->QvGet(iflo), ib));
}
else
{
//the data is on file
BLCK blck(flo.pfil, flo.fp + ib, cb);
fRet = blck.FWriteToBlck(pblck);
}
ib = 0;
ibDst += cb;
AssertDo(pblck->FMoveMin(cb), 0);
}
Assert(!fRet || ibDst == cbWrite, "wrong number of bytes written!");
Assert(pblck->Cb() == 0, 0);
AssertDo(pblck->FMoveMin(-ibDst), 0);
AssertDo(pblck->FMoveLim(cbWrite - ibDst), 0);
Assert(pblck->Cb() == cbWrite, 0);
_pggflo->Unlock();
return fRet;
}
/***************************************************************************
Write the stream out to a temp file and redirect the stream to just
refernce the temp file. This makes the stream's memory footprint
minimal.
***************************************************************************/
bool BSF::FCompact(void)
{
AssertThis(fobjAssertFull);
FLO flo;
bool fRet = fFalse;
if (_ibMac == 0 || _pggflo->IvMac() == 1 && _pggflo->Cb(1) == 0)
{
fRet = fTrue;
goto LShrinkGg;
}
if (pvNil == (flo.pfil = FIL::PfilCreateTemp()))
goto LShrinkGg;
flo.fp = 0;
flo.cb = _ibMac;
fRet = FWriteRgb(&flo) && FReplaceFlo(&flo, fFalse, 0, _ibMac);
ReleasePpo(&flo.pfil);
LShrinkGg:
if (pvNil != _pggflo)
_pggflo->FEnsureSpace(0, fgrpShrink);
AssertThis(fobjAssertFull);
return fRet;
}
#ifdef DEBUG
/***************************************************************************
Assert the validity of a byte stream (BSF).
***************************************************************************/
void BSF::AssertValid(ulong grfobj)
{
BSF_PAR::AssertValid(grfobj);
if (pvNil == _pggflo)
{
AssertVar(0 == _ibMac, "wrong _ibMac", &_ibMac);
return;
}
AssertPo(_pggflo, 0);
if (!(grfobj & fobjAssertFull))
return;
long cb, cbT, iflo;
FLO flo;
for (cb = 0, iflo = _pggflo->IvMac(); iflo-- > 0; )
{
_pggflo->GetFixed(iflo, &flo);
cbT = _pggflo->Cb(iflo);
if (pvNil == flo.pfil)
Assert(cbT == flo.cb, "wrong sized entry");
else
{
AssertPo(flo.pfil, 0);
Assert(cbT == 0, "wrong sized file entry");
AssertIn(flo.fp, 0, kcbMax);
AssertIn(flo.cb, 0, kcbMax);
cbT = flo.cb;
}
cb += cbT;
}
AssertVar(cb == _ibMac, "bad _ibMac", &_ibMac);
}
/***************************************************************************
Mark memory for the BSF.
***************************************************************************/
void BSF::MarkMem(void)
{
AssertThis(fobjAssertFull);
BSF_PAR::MarkMem();
MarkMemObj(_pggflo);
}
#endif //DEBUG