📄 minifileobj.cpp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/****************************************************************************
* Includes
*/
#include "hxtypes.h"
#include "hlxclib/stdio.h" /* FILE */
#include "hlxclib/string.h" /* strcpy, etc. */
#include "hlxclib/sys/stat.h" /* stat() */
#if defined (_WINDOWS ) && defined (_WIN32)
#include <atlbase.h>
#ifndef _WINCE
#include <direct.h> /* mkdir, etc. */
#endif
#elif defined (_MACINTOSH)
#include <unix.h> /* fileno */
#endif
#include "hxcom.h" /* IUnknown */
#include "hxcomm.h" /* IHXCommonClassFactory */
#include "ihxpckts.h" /* IHXValues, IHXBuffers */
#include "rtsputil.h"
#include "minifilesys.h" /* FILE_SYS_PROTOCOL */
#include "minifileobj.h" /* CHXMiniFileObject */
#include "debug.h" /* DPRINTF */
#include "hxdir.h" /* OS_SEPERATOR_STRING */
#define D_MINI_FO 0x1000000
// CHXMiniFileObject Class Methods
/****************************************************************************
* CHXMiniFileObject::CHXMiniFileObject
*
* Constructor
*/
CHXMiniFileObject::CHXMiniFileObject(IHXCommonClassFactory* pClassFactory, const char* pBasePath): m_RefCount(0),
m_pClassFactory (pClassFactory),
m_pFileResponse (NULL),
m_pFile (NULL),
m_pFilename (NULL),
m_pRequest (NULL),
m_pBasePath (NULL),
#if defined (_WINDOWS ) && defined (_WIN32)
m_hFileHandle (0),
#endif
m_FileAccessMode (0),
m_pDirResponse (NULL),
m_bInReadDone(FALSE),
m_pPendingReadBuf(NULL)
{
DPRINTF(D_MINI_FO, ("CHXMiniFO::CHXMiniFileObject()\n"));
// Signify that we need to keep a reference to this object
if (m_pClassFactory != NULL)
{
m_pClassFactory->AddRef();
}
if (pBasePath)
{
m_pBasePath = new char[strlen(pBasePath) + 1];
if (m_pBasePath)
{
strcpy(m_pBasePath, pBasePath);
}
}
}
/****************************************************************************
* CHXMiniFileObject::~CHXMiniFileObject
*
* Destructor. It is essential to call the Close() routine before destroying
* this object.
*/
CHXMiniFileObject::~CHXMiniFileObject(void)
{
DPRINTF(D_MINI_FO, ("CHXMiniFO::~CHXMiniFileObject()\n"));
Close();
delete [] m_pBasePath;
m_pBasePath = 0;
if (m_pFilename != NULL)
{
delete[] m_pFilename;
m_pFilename = 0;
}
if (m_pClassFactory != NULL)
{
m_pClassFactory->Release();
m_pClassFactory = NULL;
}
}
/****************************************************************************
* CHXMiniFileObject::OpenFile
*
* This routine opens a file according to the access mode given. It is
* called while initializing the File Object.
*/
STDMETHODIMP CHXMiniFileObject::OpenFile(UINT32 fileAccessMode)
{
HX_RESULT result = HXR_OK;
// Construct the proper access mode string
char modeStr[4];
if (fileAccessMode & HX_FILE_READ)
{
strcpy(modeStr, "r");
if (fileAccessMode & HX_FILE_WRITE)
{
strcat(modeStr, "+");
}
if (fileAccessMode & HX_FILE_BINARY)
{
strcat(modeStr, "b");
}
}
else if (fileAccessMode & HX_FILE_WRITE)
{
strcpy(modeStr, "w");
if (fileAccessMode & HX_FILE_BINARY)
{
strcat(modeStr, "b");
}
}
else if (fileAccessMode == 0)
{
fileAccessMode = HX_FILE_READ | HX_FILE_BINARY;
strcpy(modeStr, "rb");
}
else
{
result = HXR_INVALID_PARAMETER;
}
// Open the file with the proper access mode
if (result == HXR_OK)
{
m_pFile = fopen(m_pFilename, modeStr);
result = m_pFile ? HXR_OK : HXR_DOC_MISSING;
}
return result;
}
/****************************************************************************
* CHXMiniFileObject::ConvertToPlatformPath
*
* This routine converts the given file path to a platform specific file
* path based upon the naming conventions of that platform. The platform
* specific path name is required to properly open the file.
*/
STDMETHODIMP CHXMiniFileObject::ConvertToPlatformPath(REF(char*) pFilePathPlatform, const char* pFilePath)
{
HX_RESULT res = HXR_OUTOFMEMORY;
pFilePathPlatform = 0;
if (m_pBasePath && pFilePath)
{
// Create new string
pFilePathPlatform =
new char[ strlen(m_pBasePath) + strlen(pFilePath) + 2 ];
}
UINT32 length = strlen(FILE_SYS_PROTOCOL) + 1; // Add 1 for the colon
char* pProtocolString = new char[length + 1];
if (pFilePathPlatform && pProtocolString && m_pBasePath)
{
// Prepend base path, if any
if (strlen(m_pBasePath) > 0)
{
strcpy(pFilePathPlatform, m_pBasePath);
strcat(pFilePathPlatform, OS_SEPARATOR_STRING);
strcat(pFilePathPlatform, pFilePath);
}
else
{
strcpy(pFilePathPlatform, pFilePath);
}
// Strip protocol string, if any
strcpy(pProtocolString, FILE_SYS_PROTOCOL);
strcat(pProtocolString, ":");
if (strnicmp(pFilePathPlatform, pProtocolString, length) == 0)
{
//copy the rest of the string back onto itself.
memmove( (void*) pFilePathPlatform,
(void*) &pFilePathPlatform[length],
(strlen( &pFilePathPlatform[length] )+1)*sizeof(char)
);
if ((pFilePathPlatform[0] == '/') &&
(pFilePathPlatform[1] == '/'))
{
// "file://" forms
// Find next '/'
const char* pNext = strchr(pFilePathPlatform + 2, '/');
if (pNext)
{
// "file://host/path" or "file:///path" form.
// Copy everything after the third '/'
memmove( (void*) pFilePathPlatform,
(void*) (pNext+1),
(strlen(pNext+1)+1)*sizeof(char)
);
pNext = 0;
res = HXR_OK;
}
else
{
// Forms: file://c:\file.ra
// file://file.ra
memmove( (void*) pFilePathPlatform,
(void*) (pFilePathPlatform+2),
(strlen(pFilePathPlatform+2)+1)*sizeof(char)
);
res = HXR_OK;
}
}
else
{
res = HXR_OK;
}
if (HXR_OK == res)
{
// Replace path slashes with platform specific path separators
// and watch for the parameter delimiter
char* pCur = pFilePathPlatform;
for (; *pCur && (*pCur != '?'); pCur++)
{
if (*pCur == '/')
{
*pCur = OS_SEPARATOR_CHAR;
}
}
/*
* Strip off the parameters
*/
if (*pCur == '?')
{
*pCur = '\0';
}
}
}
else
{
if (NULL == strstr(pFilePathPlatform,"//"))
res = HXR_OK; // allow path/file w/o file://
else
res = HXR_INVALID_PROTOCOL;
}
}
delete [] pProtocolString;
pProtocolString = 0;
if (res != HXR_OK)
{
delete [] pFilePathPlatform;
pFilePathPlatform = 0;
}
return res;
}
// IHXFileObject Interface Methods
/****************************************************************************
* IHXFileObject::Init
*
* This routine associates this File Object with a File Response object
* which is notified when file operations (read, write, seek, etc.) are
* complete. This method also checks the validity of the file by actually
* opening it.
*/
STDMETHODIMP CHXMiniFileObject::Init( UINT32 fileAccessMode, IHXFileResponse* pFileResponse )
{
/*
* Associate this File Object with a File Response object for completion
* notification.
*/
DPRINTF(D_MINI_FO, ("CHXMiniFO::Init()\n"));
if (pFileResponse != NULL)
{
// Release any previous File Response objects
if (m_pFileResponse != NULL)
{
m_pFileResponse->Release();
}
m_pFileResponse = pFileResponse;
m_pFileResponse->AddRef();
}
else
{
return HXR_INVALID_PARAMETER;
}
/*
* Open the file and notify File Response when complete
*/
if (m_pFile != NULL) // File is already open
{
// Has requested access mode changed?
if ((fileAccessMode == m_FileAccessMode) ||
(fileAccessMode == 0))
{
// reset to start of file
fseek(m_pFile, 0, SEEK_SET);
// notify that file is ready
m_pFileResponse->InitDone(HXR_OK);
return HXR_OK;
}
else // Access mode has changed
{
fclose(m_pFile);
m_pFile = NULL;
}
}
m_FileAccessMode = fileAccessMode;
HX_RESULT fileOpenResult = OpenFile(fileAccessMode);
m_pFileResponse->InitDone(fileOpenResult);
return fileOpenResult;
}
/****************************************************************************
* IHXFileObject::GetFilename
*
* This routine returns the name of the requested file (without any path
* information). This method may be called by the File Format plug-in if the
* short name of the file is required.
*/
STDMETHODIMP CHXMiniFileObject::GetFilename( REF(const char*) pFileName )
{
DPRINTF(D_MINI_FO, ("CHXMiniFO::GetFilename()\n"));
pFileName = NULL;
HX_RESULT result = HXR_OK;
// Find the separator character before the file name
pFileName = ::strrchr(m_pFilename, OS_SEPARATOR_CHAR);
if (pFileName != NULL) // Found
{
// File name starts after the separator charactor
pFileName++;
}
else // Not found
{
pFileName = m_pFilename;
}
return result;
}
/****************************************************************************
* IHXFileObject::Read
*
* This routine reads a block of data of the specified length from the file.
* When reading has completed, the caller is asynchronously notified via the
* File Response object associated with this File Object. This method is
* called by the File Format plug-in when it needs to read from the file.
*/
STDMETHODIMP CHXMiniFileObject::Read( UINT32 byteCount )
{
DPRINTF(D_MINI_FO, ("CHXMiniFO::Read(%u)\n", byteCount));
HX_RESULT result = HXR_UNEXPECTED;
if ((m_pPendingReadBuf == NULL) && (m_pClassFactory != NULL))
{
if (byteCount > 0x000FFFFF)
{
m_bInReadDone = FALSE;
m_pFileResponse->ReadDone(HXR_FAILED, NULL);
return HXR_INVALID_PARAMETER;
}
m_pClassFactory->CreateInstance(CLSID_IHXBuffer, (void**)&m_pPendingReadBuf);
if (m_pPendingReadBuf != NULL)
{
result = m_pPendingReadBuf->SetSize(byteCount);
if (HXR_OK != result)
{
HX_RELEASE(m_pPendingReadBuf);
}
else if (!m_bInReadDone)
{
// We use a loop here so we can service Read() calls
// occurred inside the ReadDone() callback
while (m_pPendingReadBuf)
{
// Transfer ownership of the pending buffer to
// this local variable. This prepares for the
// possibility that Read() may be called from
// ReadDone()
IHXBuffer* pBuffer = m_pPendingReadBuf;
m_pPendingReadBuf = NULL;
// Read from the file directly into the buffer object
UINT32 actualCount = fread(pBuffer->GetBuffer(),
sizeof(UCHAR),
pBuffer->GetSize(), m_pFile);
result = pBuffer->SetSize(actualCount);
// Notify the caller that the read is done
HX_RESULT readResult = actualCount > 0 ? HXR_OK : HXR_FAILED;
m_bInReadDone = TRUE;
// If heap gets low, memory allocations for new file read
// buffers is one of the first places we notice it, and
// if we're not careful to report this error, we can get
// into a state where the renderer is stuck trying to
// rebuffer, but the front end can't get any new data
// because we can't allocate any new buffers. If we replace
// this with a caching buffer system, this issue goes away.
if( result == HXR_OK )
{
result = m_pFileResponse->ReadDone(readResult, pBuffer);
}
m_bInReadDone = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -