//---------------------------------------------------------------
//
//  For conditions of distribution and use, see copyright notice
//  in Flashpix.h
//
//  Copyright (c) 1999 Digital Imaging Group, Inc.
//
//  Contents:   Generic DocFile support functions
//
//  Functions:  ModeToTFlags
//              CheckName
//              wcsdup
//              VerifyPerms
//
//---------------------------------------------------------------

#include "dfhead.cxx"

//+--------------------------------------------------------------
//
//  Function:   ModeToDFlags, private
//
//  Synopsis:   Translates STGM flags to DF flags
//
//  Arguments:  [dwModeFlags]
//
//  Returns:    DF_*
//
//---------------------------------------------------------------

DFLAGS ModeToDFlags(DWORD const dwModeFlags)
{
    DFLAGS df;

    olDebugOut((DEB_ITRACE, "In  ModeToDFlags(%lX)\n", dwModeFlags));
    if ((dwModeFlags & STGM_TRANSACTED) == 0)
        df = DF_DIRECT;
    else
        df = DF_TRANSACTED;
    if ((dwModeFlags & STGM_TRANSACTED) &&
        (dwModeFlags & STGM_PRIORITY) == 0 &&
        (dwModeFlags & STGM_DENY) != STGM_SHARE_DENY_WRITE &&
        (dwModeFlags & STGM_DENY) != STGM_SHARE_EXCLUSIVE)
        df |= DF_INDEPENDENT;
    switch(dwModeFlags & STGM_RDWR)
    {
    case STGM_READ:
        df |= DF_READ;
        break;
    case STGM_WRITE:
        df |= DF_WRITE;
        break;
    case STGM_READWRITE:
        df |= DF_READWRITE;
        break;
    default:
        olAssert(FALSE);
        break;
    }
    switch(dwModeFlags & STGM_DENY)
    {
    case STGM_SHARE_DENY_READ:
        df |= DF_DENYREAD;
        break;
    case STGM_SHARE_DENY_WRITE:
        df |= DF_DENYWRITE;
        break;
    case STGM_SHARE_EXCLUSIVE:
        df |= DF_DENYALL;
        break;
        // Default is deny none
    }
    if (dwModeFlags & STGM_PRIORITY)
        df |= DF_PRIORITY;
    olDebugOut((DEB_ITRACE, "Out ModeToDFlags => %lX\n", df));
    return df;
}

//+--------------------------------------------------------------
//
//  Function:   DFlagsToMode, private
//
//  Synopsis:   Converts the read/write/denials/transacted/priority
//              to STGM flags
//
//  Arguments:  [df] - DFlags
//
//  Returns:    STGM flags
//
//---------------------------------------------------------------

DWORD DFlagsToMode(DFLAGS const df)
{
    DWORD dwMode;

    olDebugOut((DEB_ITRACE, "In  DFlagsToMode(%X)\n", df));
    if (P_READ(df))
        if (P_WRITE(df))
            dwMode = STGM_READWRITE;
        else
            dwMode = STGM_READ;
    else if (P_WRITE(df))
        dwMode = STGM_WRITE;
    // Must have either read or write, so no else

    if (P_DENYREAD(df))
        if (P_DENYWRITE(df))
            dwMode |= STGM_SHARE_EXCLUSIVE;
        else
            dwMode |= STGM_SHARE_DENY_READ;
    else if (P_DENYWRITE(df))
        dwMode |= STGM_SHARE_DENY_WRITE;
    else
        dwMode |= STGM_SHARE_DENY_NONE;

    if (P_TRANSACTED(df))
        dwMode |= STGM_TRANSACTED;

    if (P_PRIORITY(df))
        dwMode |= STGM_PRIORITY;

    olDebugOut((DEB_ITRACE, "Out DFlagsToMode\n"));
    return dwMode;
}

//+--------------------------------------------------------------
//
//  Function:   VerifyPerms, private
//
//  Synopsis:   Checks flags to see if they are valid
//
//  Arguments:  [grfMode] - Permissions
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------

SCODE VerifyPerms(DWORD grfMode)
{
    SCODE sc = S_OK;

    olDebugOut((DEB_ITRACE, "In  VerifyPerms(%lX)\n", grfMode));

    // Check for valid flags
    if ((grfMode & STGM_RDWR) > STGM_READWRITE ||
        (grfMode & STGM_DENY) > STGM_SHARE_DENY_NONE ||
        (grfMode & ~(STGM_RDWR | STGM_DENY | STGM_DIRECT | STGM_TRANSACTED |
                     STGM_PRIORITY | STGM_CREATE | STGM_CONVERT |
                     STGM_FAILIFTHERE | STGM_DELETEONRELEASE)))
        olErr(EH_Err, STG_E_INVALIDFLAG);

    // We don't support these modes
    if (grfMode & (STGM_PRIORITY|STGM_TRANSACTED|STGM_SIMPLE))
    {
        olAssert( FALSE &&
            aMsg("Unsupported feature of reference implemention called"));
        return STG_E_INVALIDFUNCTION;
    }

    // Check to make sure only one existence flag is specified
    // FAILIFTHERE is zero so it can't be checked
    if ((grfMode & (STGM_CREATE | STGM_CONVERT)) ==
        (STGM_CREATE | STGM_CONVERT))
        olErr(EH_Err, STG_E_INVALIDFLAG);

    // If not transacted and not priority, you can either be
    // read-only deny write or read-write deny all
    if ((grfMode & (STGM_TRANSACTED | STGM_PRIORITY)) == 0)
    {
        if ((grfMode & STGM_RDWR) == STGM_READ)
        {
            //  we're asking for read-only access

            if ((grfMode & STGM_DENY) != STGM_SHARE_EXCLUSIVE &&
                (grfMode & STGM_DENY) != STGM_SHARE_DENY_WRITE)
            {
                //  Can't allow others to have write access
                olErr(EH_Err, STG_E_INVALIDFLAG);
            }
        }
        else
        {
            //  we're asking for write access

            if ((grfMode & STGM_DENY) != STGM_SHARE_EXCLUSIVE)
            {
                //  Can't allow others to have any access
                olErr(EH_Err, STG_E_INVALIDFLAG);
            }
        }
    }
    olDebugOut((DEB_ITRACE, "Out VerifyPerms\n"));
    // Fall through
EH_Err:
    return sc;
}



//+--------------------------------------------------------------
//
//  Function:   wcsdup, public
//
//  Synopsis:   Duplicates a WCHAR string
//
//  Arguments:  [pwcs] - String
//
//  Returns:    Pointer to new string or Appropriate status code
//
//---------------------------------------------------------------

WCHAR * _CRTAPI1 wcsdup(WCHAR const *pwcs)
{
    WCHAR *pwcsNew;

    olDebugOut((DEB_ITRACE, "In  wcsdup(%ws)\n", pwcs));
    pwcsNew = new WCHAR[wcslen(pwcs)+1];
    if (pwcsNew == NULL)
        return NULL;
    wcscpy(pwcsNew, pwcs);
    olDebugOut((DEB_ITRACE, "Out wcsdup => %p\n", pwcsNew));
    return pwcsNew;
}



//+--------------------------------------------------------------
//
//  Function:   ValidateSNBW
//
//  Synopsis:   Validates SNB memory
//
//  Arguments:  [snb] - SNB
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------
#ifdef _UNICODE
SCODE ValidateSNBW(SNBW snb)
{
    SCODE sc;

    olDebugOut((DEB_ITRACE, "In  ValidateSNB(%p)\n", snb));
    for (;;)
    {
        olChk(ValidatePtrBuffer(snb));
        if (*snb == NULL)
            break;
        olChk(ValidateNameW(*snb, CWCMAXPATHCOMPLEN));
        snb++;
    }
    olDebugOut((DEB_ITRACE, "Out ValidateSNB\n"));
    return S_OK;
EH_Err:
    return sc;
}
#endif // ifdef _UNICODE
//+--------------------------------------------------------------
//
//  Function:   CheckWName, public
//
//  Synopsis:   Checks name for illegal characters and length
//
//  Arguments:  [pwcsName] - Name
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------

#ifdef _UNICODE
WCHAR wcsInvalid[] = { '\\', '/', ':', '!','\0' };

SCODE CheckWName(WCHAR const *pwcsName)
{
    SCODE sc;
    olDebugOut((DEB_ITRACE, "In  CheckWName(%s)\n", pwcsName));
    if (FAILED(sc = ValidateNameW(pwcsName, CBMAXPATHCOMPLEN)))
        return sc;
    // >= is used because the max len includes the null terminator
    if (wcslen(pwcsName) >= CWCMAXPATHCOMPLEN)
        return STG_E_INVALIDNAME;
    for (; *pwcsName; pwcsName++)
    {
        if ( wcschr(wcsInvalid, *pwcsName) )
            return STG_E_INVALIDNAME;
    }
    olDebugOut((DEB_ITRACE, "Out CheckWName\n"));
    return S_OK;
}
#else  // validation done in ascii layer already

#define CheckWName(pwcsName) (S_OK)

#endif // ifdef _UNICODE

//+--------------------------------------------------------------
//
//  Function:   CopyDStreamToDStream
//
//  Synopsis:   Copies the contents of a stream to another stream
//
//  Arguments:  [pstFrom] - Stream to copy from
//              [pstTo] - Stream to copy to
//
//  Returns:    Appropriate status code
//
//  Notes:      This function may fail due to out of memory.  It
//              may not be used by callers who must not fail due
//              to out of memory.
//
//              This function does not check permissions
//              for write in the to streams.
//
//---------------------------------------------------------------

SCODE CopyStreamToStream(CDirectStream *pstFrom,
                         CDirectStream *pstTo)
{
    BYTE *pbBuffer;
    SCODE sc;
    ULONG cbRead, cbWritten, cbSize, cbPos;

    // Set destination size for contiguity
    pstFrom->GetSize(&cbSize);
    olChk(pstTo->SetSize(cbSize));

    // We're allowed to fail due to out of memory
    olMem(pbBuffer = new BYTE[STREAMBUFFERSIZE]);

    // Copy between streams
    cbPos = 0;
    for (;;)
    {
        olChkTo(EH_pbBuffer,
                pstFrom->ReadAt(cbPos, pbBuffer, STREAMBUFFERSIZE,
                                 (ULONG STACKBASED *)&cbRead));
        if (cbRead == 0) // EOF
            break;
        olChkTo(EH_pbBuffer,
                pstTo->WriteAt(cbPos, pbBuffer, cbRead,
                                (ULONG STACKBASED *)&cbWritten));
        if (cbRead != cbWritten)
            olErr(EH_Err, STG_E_WRITEFAULT);
        cbPos += cbWritten;
    }
    delete pbBuffer;
    return S_OK;

EH_pbBuffer:
    delete pbBuffer;
EH_Err:
    return sc;
}

//+--------------------------------------------------------------
//
//  Function:   NameInSNB, private
//
//  Synopsis:   Determines whether the given name is in the SNB
//
//  Arguments:  [dfn] - Name
//              [snb] - SNB
//
//  Returns:    S_OK or S_FALSE
//
//---------------------------------------------------------------

SCODE NameInSNB(CDfName const *dfn, SNBW snb)
{
    SCODE sc = S_FALSE;

    olDebugOut((DEB_ITRACE, "In  NameInSNB(%ws, %p)\n", dfn, snb));

    for (; *snb; snb++) {
        if (dfwcsnicmp((WCHAR *)dfn->GetBuffer(), (WCHAR *)*snb,
            dfn->GetLength()) == 0)
        {
            sc = S_OK;
            break;
        }
    }

    olDebugOut((DEB_ITRACE, "Out NameInSNB\n"));
    return sc;
}
