mirror of
https://github.com/microsoft/Microsoft-3D-Movie-Maker.git
synced 2024-11-25 03:33:22 +01:00
417 lines
8.0 KiB
C++
417 lines
8.0 KiB
C++
/* Copyright (c) Microsoft Corporation.
|
|
Licensed under the MIT License. */
|
|
|
|
/***************************************************************************
|
|
Author: ShonK
|
|
Project: Kauai
|
|
Reviewed:
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Windows specific file management.
|
|
|
|
***************************************************************************/
|
|
#include "util.h"
|
|
ASSERTNAME
|
|
|
|
|
|
const ulong kfpError = 0xFFFFFFFF;
|
|
priv HANDLE _HfileOpen(PSZ pszFile, bool fCreate, ulong grffil);
|
|
|
|
|
|
/***************************************************************************
|
|
Open or create the file by calling CreateFile. Returns hBadWin on
|
|
failure.
|
|
***************************************************************************/
|
|
priv HANDLE _HfileOpen(PSZ psz, bool fCreate, ulong grffil)
|
|
{
|
|
ulong luAccess = GENERIC_READ;
|
|
ulong luShare = 0;
|
|
|
|
if (grffil & ffilWriteEnable)
|
|
luAccess |= GENERIC_WRITE;
|
|
if (!(grffil & ffilDenyRead))
|
|
luShare |= FILE_SHARE_READ;
|
|
if (!(grffil & ffilDenyWrite))
|
|
luShare |= FILE_SHARE_WRITE;
|
|
|
|
return CreateFile(psz, luAccess, luShare, pvNil,
|
|
fCreate ? CREATE_ALWAYS : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, pvNil);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Open or create the file. If the file is already open, sets the
|
|
permissions according to grffil.
|
|
***************************************************************************/
|
|
bool FIL::_FOpen(bool fCreate, ulong grffil)
|
|
{
|
|
AssertBaseThis(0);
|
|
bool fRet = fFalse;
|
|
|
|
_mutx.Enter();
|
|
|
|
if (_el >= kelCritical)
|
|
goto LRet;
|
|
|
|
grffil &= kgrffilPerm;
|
|
if (_fOpen)
|
|
{
|
|
Assert(!fCreate, "can't create an open file");
|
|
if ((~_grffil & grffil) == 0)
|
|
{
|
|
// permissions are already set high enough
|
|
fRet = fTrue;
|
|
goto LRet;
|
|
}
|
|
CloseHandle(_hfile);
|
|
_hfile = hBadWin;
|
|
|
|
// maintain the permissions we had before
|
|
grffil |= _grffil & kgrffilPerm;
|
|
}
|
|
|
|
_hfile = _HfileOpen(_fni._stnFile.Psz(), fCreate, grffil);
|
|
|
|
if (hBadWin == _hfile)
|
|
{
|
|
// if it was open, re-open it with old permissions
|
|
if (_fOpen)
|
|
{
|
|
_hfile = _HfileOpen(_fni._stnFile.Psz(), fFalse, _grffil);
|
|
if (hBadWin != _hfile)
|
|
goto LRet;
|
|
}
|
|
_fOpen = fFalse;
|
|
_el = kelCritical;
|
|
goto LRet;
|
|
}
|
|
|
|
_fOpen = fTrue;
|
|
_fEverOpen = fTrue;
|
|
_grffil = (_grffil & ~kgrffilPerm) | grffil;
|
|
fRet = fTrue;
|
|
|
|
LRet:
|
|
_mutx.Leave();
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Close the file.
|
|
***************************************************************************/
|
|
void FIL::_Close(bool fFinal)
|
|
{
|
|
AssertBaseThis(0);
|
|
|
|
_mutx.Enter();
|
|
|
|
if (_fOpen)
|
|
{
|
|
Flush();
|
|
CloseHandle(_hfile);
|
|
_fOpen = fFalse;
|
|
_hfile = hBadWin;
|
|
}
|
|
|
|
if ((_grffil & ffilTemp) && fFinal && _fEverOpen)
|
|
{
|
|
if (!DeleteFile(_fni._stnFile.Psz()))
|
|
Warn("Deleting temp file failed");
|
|
}
|
|
|
|
_mutx.Leave();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Flush the file (and its volume?).
|
|
***************************************************************************/
|
|
void FIL::Flush(void)
|
|
{
|
|
AssertThis(0);
|
|
|
|
_mutx.Enter();
|
|
|
|
if (_fOpen)
|
|
FlushFileBuffers(_hfile);
|
|
|
|
_mutx.Leave();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Seek to the given fp - assumes the mutx is already entered.
|
|
***************************************************************************/
|
|
void FIL::_SetFpPos(FP fp)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (!_fOpen)
|
|
_FOpen(fFalse, _grffil);
|
|
|
|
if (_el < kelSeek &&
|
|
SetFilePointer(_hfile, fp, pvNil, FILE_BEGIN) == kfpError)
|
|
{
|
|
PushErc(ercFileGeneral);
|
|
_el = kelSeek;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Set the length of the file. This doesn't zero the appended portion.
|
|
***************************************************************************/
|
|
bool FIL::FSetFpMac(FP fp)
|
|
{
|
|
AssertThis(0);
|
|
AssertIn(fp, 0, kcbMax);
|
|
bool fRet;
|
|
|
|
_mutx.Enter();
|
|
|
|
Assert(_grffil & ffilWriteEnable, "can't write to read only file");
|
|
_SetFpPos(fp);
|
|
|
|
if (_el < kelWrite)
|
|
{
|
|
_fWrote = fTrue;
|
|
if (!SetEndOfFile(_hfile))
|
|
{
|
|
PushErc(ercFileGeneral);
|
|
_el = kelWrite;
|
|
}
|
|
}
|
|
fRet = _el < kelWrite;
|
|
|
|
_mutx.Leave();
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return the length of the file.
|
|
***************************************************************************/
|
|
FP FIL::FpMac(void)
|
|
{
|
|
AssertThis(0);
|
|
FP fp;
|
|
|
|
_mutx.Enter();
|
|
|
|
if (!_fOpen)
|
|
_FOpen(fFalse, _grffil);
|
|
|
|
if (_el < kelSeek &&
|
|
(fp = SetFilePointer(_hfile, 0, pvNil, FILE_END)) == kfpError)
|
|
{
|
|
PushErc(ercFileGeneral);
|
|
_el = kelSeek;
|
|
}
|
|
|
|
if (_el >= kelSeek)
|
|
fp = 0;
|
|
|
|
_mutx.Leave();
|
|
|
|
return fp;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Read a block from the file.
|
|
***************************************************************************/
|
|
bool FIL::FReadRgb(void *pv, long cb, FP fp)
|
|
{
|
|
AssertThis(0);
|
|
AssertIn(cb, 0, kcbMax);
|
|
AssertIn(fp, 0, klwMax);
|
|
AssertPvCb(pv, cb);
|
|
|
|
long cbT;
|
|
bool fRet = fFalse;
|
|
|
|
if (cb <= 0)
|
|
return fTrue;
|
|
|
|
_mutx.Enter();
|
|
|
|
if (!_fOpen)
|
|
_FOpen(fFalse, _grffil);
|
|
|
|
Debug( FP dfp = FpMac() - fp; )
|
|
|
|
_SetFpPos(fp);
|
|
if (_el >= kelRead)
|
|
goto LRet;
|
|
|
|
Assert(dfp >= cb, "read past EOF");
|
|
if (!ReadFile(_hfile, pv, cb, (ulong *)&cbT, pvNil) || cb != cbT)
|
|
{
|
|
PushErc(ercFileGeneral);
|
|
_el = kelRead;
|
|
goto LRet;
|
|
}
|
|
|
|
fRet = fTrue;
|
|
|
|
LRet:
|
|
_mutx.Leave();
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Write a block to the file.
|
|
***************************************************************************/
|
|
bool FIL::FWriteRgb(void *pv, long cb, FP fp)
|
|
{
|
|
AssertThis(0);
|
|
AssertIn(cb, 0, kcbMax);
|
|
AssertIn(fp, 0, klwMax);
|
|
AssertPvCb(pv, cb);
|
|
|
|
long cbT;
|
|
bool fRet = fFalse;
|
|
|
|
if (cb <= 0)
|
|
return fTrue;
|
|
|
|
_mutx.Enter();
|
|
|
|
Assert(_grffil & ffilWriteEnable, "can't write to read only file");
|
|
|
|
if (!_fOpen)
|
|
_FOpen(fFalse, _grffil);
|
|
|
|
_SetFpPos(fp);
|
|
if (_el >= kelWrite)
|
|
goto LRet;
|
|
|
|
_fWrote = fTrue;
|
|
if (!WriteFile(_hfile, pv, cb, (ulong *)&cbT, pvNil) || cb != cbT)
|
|
{
|
|
PushErc(ercFileGeneral);
|
|
_el = kelWrite;
|
|
goto LRet;
|
|
}
|
|
|
|
fRet = fTrue;
|
|
|
|
LRet:
|
|
_mutx.Leave();
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Swap the names of the two files. They should be in the same directory.
|
|
***************************************************************************/
|
|
bool FIL::FSwapNames(PFIL pfil)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pfil, 0);
|
|
FNI fni;
|
|
FNI fniT;
|
|
bool fRet = fFalse;
|
|
|
|
if (this == pfil)
|
|
{
|
|
Bug("Why are you calling FSwapNames on the same file?");
|
|
return fTrue;
|
|
}
|
|
|
|
_mutx.Enter();
|
|
pfil->_mutx.Enter();
|
|
|
|
Assert(_fni.FSameDir(&pfil->_fni),
|
|
"trying to change directories with FSwapNames");
|
|
|
|
fni = pfil->_fni;
|
|
if (!fni.FGetUnique(fni.Ftg()))
|
|
goto LRet;
|
|
|
|
_Close();
|
|
pfil->_Close();
|
|
|
|
if (!_fni.FRename(&fni))
|
|
goto LFail;
|
|
if (!pfil->_fni.FRename(&_fni))
|
|
goto LRenameFail;
|
|
if (!fni.FRename(&pfil->_fni))
|
|
{
|
|
if (!_fni.FRename(&pfil->_fni))
|
|
{
|
|
Bug("rename failure");
|
|
pfil->_fni = _fni;
|
|
_fni = fni;
|
|
goto LFail;
|
|
}
|
|
|
|
LRenameFail:
|
|
if (!fni.FRename(&_fni))
|
|
{
|
|
Bug("rename failure");
|
|
_fni = fni;
|
|
}
|
|
goto LFail;
|
|
}
|
|
|
|
fni = _fni;
|
|
_fni = pfil->_fni;
|
|
pfil->_fni = fni;
|
|
fRet = fTrue;
|
|
|
|
LFail:
|
|
// reopen the files
|
|
_FOpen(fFalse, _grffil);
|
|
pfil->_FOpen(fFalse, pfil->_grffil);
|
|
|
|
LRet:
|
|
_mutx.Leave();
|
|
pfil->_mutx.Leave();
|
|
|
|
if (!fRet)
|
|
PushErc(ercFileSwapNames);
|
|
|
|
AssertThis(0);
|
|
AssertPo(pfil, 0);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Rename a file. The new fni should be on the same volume.
|
|
This may fail without an error code being set.
|
|
***************************************************************************/
|
|
bool FIL::FRename(FNI *pfni)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pfni, ffniFile);
|
|
FNI fni;
|
|
bool fRet = fFalse;
|
|
|
|
_mutx.Enter();
|
|
|
|
Assert(_fni.FSameDir(pfni), "trying to change directories with FRename");
|
|
|
|
_Close();
|
|
if (fRet = _fni.FRename(pfni))
|
|
_fni = *pfni;
|
|
|
|
// reopen the file
|
|
if (!_FOpen(fFalse, _grffil))
|
|
fRet = fFalse;
|
|
|
|
_mutx.Leave();
|
|
|
|
if (!fRet)
|
|
PushErc(ercFileRename);
|
|
|
|
AssertThis(0);
|
|
return fRet;
|
|
}
|