//------------------------------------------------------------------------------
// File: PStream.cpp
//
// Desc: DirectShow base classes.
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------------------------


#include <streams.h>

#ifdef PERF
#include <measure.h>
#endif


//
// Constructor
//
CPersistStream::CPersistStream(IUnknown *punk, HRESULT *phr)
    : mPS_fDirty(FALSE)
{
    mPS_dwFileVersion = GetSoftwareVersion();
}


//
// Destructor
//
CPersistStream::~CPersistStream() {
    // Nothing to do
}

#if 0
SAMPLE CODE TO COPY - not active at the moment

//
// NonDelegatingQueryInterface
//
// This object supports IPersist & IPersistStream
STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
    if (riid == IID_IPersist) {
        return GetInterface((IPersist *) this, ppv);
    }
    else if (riid == IID_IPersistStream) {
        return GetInterface((IPersistStream *) this, ppv);
    }
    else {
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
    }
}
#endif


//
// WriteToStream
//
// Writes to the stream (default action is to write nothing)
HRESULT CPersistStream::WriteToStream(IStream *pStream)
{
    // You can override this to do things like
    // hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL);

    return NOERROR;
}



HRESULT CPersistStream::ReadFromStream(IStream * pStream)
{
    // You can override this to do things like
    // hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL);

    return NOERROR;
}


//
// Load
//
// Load all the data from the given stream
STDMETHODIMP CPersistStream::Load(LPSTREAM pStm)
{
    HRESULT hr;
    // Load the version number then the data
    mPS_dwFileVersion = ReadInt(pStm, hr);
    if (FAILED(hr)) {
        return hr;
    }

    return ReadFromStream(pStm);
}  // Load



//
// Save
//
// Save the contents of this Stream.
STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty)
{

    HRESULT hr = WriteInt(pStm, GetSoftwareVersion());
    if (FAILED(hr)) {
        return hr;
    }

    hr = WriteToStream(pStm);
    if (FAILED(hr)) {
        return hr;
    }

    mPS_fDirty = !fClearDirty;

    return hr;
} // Save


// WriteInt
//
// Writes an integer to an IStream as 11 UNICODE characters followed by one space.
// You could use this for shorts or unsigneds or anything (up to 32 bits)
// where the value isn't actually truncated by squeezing it into 32 bits.
// Values such as (unsigned) 0x80000000 would come out as -2147483648
// but would then load as 0x80000000 through ReadInt.  Cast as you please.

STDAPI WriteInt(IStream *pIStream, int n)
{
    WCHAR Buff[13];  // Allows for trailing null that we don't write
    (void)StringCchPrintfW(Buff, NUMELMS(Buff), L"%011d ",n);
    return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL);
} // WriteInt


// ReadInt
//
// Reads an integer from an IStream.
// Read as 4 bytes.  You could use this for shorts or unsigneds or anything
// where the value isn't actually truncated by squeezing it into 32 bits
// Striped down subset of what sscanf can do (without dragging in the C runtime)

STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr)
{

    int Sign = 1;
    unsigned int n = 0;    // result wil be n*Sign
    WCHAR wch;

    hr = pIStream->Read( &wch, sizeof(wch), NULL);
    if (FAILED(hr)) {
        return 0;
    }

    if (wch==L'-'){
        Sign = -1;
        hr = pIStream->Read( &wch, sizeof(wch), NULL);
        if (FAILED(hr)) {
            return 0;
        }
    }

    for( ; ; ) {
        if (wch>=L'0' && wch<=L'9') {
            n = 10*n+(int)(wch-L'0');
        } else if (  wch == L' '
                  || wch == L'\t'
                  || wch == L'\r'
                  || wch == L'\n'
                  || wch == L'\0'
                  ) {
            break;
        } else {
            hr = VFW_E_INVALID_FILE_FORMAT;
            return 0;
        }

        hr = pIStream->Read( &wch, sizeof(wch), NULL);
        if (FAILED(hr)) {
            return 0;
        }
    }

    if (n==0x80000000 && Sign==-1) {
        // This is the negative number that has no positive version!
        return (int)n;
    }
    else return (int)n * Sign;
} // ReadInt


// The microsoft C/C++ compile generates level 4 warnings to the effect that
// a particular inline function (from some base class) was not needed.
// This line gets rid of hundreds of such unwanted messages and makes
// -W4 compilation feasible:
#pragma warning(disable: 4514)
