recognizer.cpp
来自「symbian 下的helix player源代码」· C++ 代码 · 共 514 行
CPP
514 行
#include "ihxpckts.h"
#include "hxbuffer.h"
#include "hlxclib/ctype.h" /* for isspace() */
#include "hxmarsh.h" /* for getshort() */
#include "recognizer.h"
#define REALMEDIA_MIME_TYPE "application/x-pn-realmedia"
#define REALAUDIO_MIME_TYPE "audio/x-pn-realaudio"
#define FLASH_MIME_TYPE "application/x-shockwave-flash"
#define REALAUDIO_METAFILE_MIME_TYPE "audio/x-pn-realaudio"
#define REALAUDIO_PLUGIN_MIME_TYPE "audio/x-pn-realaudio-plugin"
#define SMIL_MIME_TYPE "application/smil"
// length of buffer read from file and passed to recognizer
#if defined(_UNIX) && !defined(_MAC_UNIX)
// we want a little more data, since we need to try to detect smil, ram and mp3
#define RECOG_LEN 4096
#else
#define RECOG_LEN 512
#endif
#if !defined (_SYMBIAN)
HX_RESULT CHXFileRecognizer::GetMimeType(const char* pFileName, IHXBuffer* pBuffer, REF(IHXBuffer*) pMimeType)
{
HX_RESULT res = HXR_FAIL;
const char* pMimeTypeStr = NULL;
#if defined(_UNIX) && !defined(_MAC_UNIX)
do
{
res = GetMimeTypeFromMagic(pBuffer, pMimeTypeStr);
if (SUCCEEDED(res))
break;
res = TestSMILFile(pBuffer, pFileName, pMimeTypeStr);
if (SUCCEEDED(res))
break;
res = TestRAMFile(pBuffer, pFileName, pMimeTypeStr);
if (SUCCEEDED(res))
break;
res = TestMP3File(pBuffer, pFileName, pMimeTypeStr);
}
while (0);
#else // #if defined(_UNIX) && !defined(_MAC_UNIX)
if (IsSDPFile(pBuffer))
{
pMimeTypeStr = "application/sdp";
res = HXR_OK;
}
#endif // #if defined(_UNIX) && !defined(_MAC_UNIX)
if (pMimeTypeStr)
{
// convert mime type to IHXBuffer
pMimeType = new CHXBuffer;
if (pMimeType)
{
pMimeType->AddRef();
int len = strlen(pMimeTypeStr);
res = pMimeType->Set((const UCHAR*)pMimeTypeStr, len + 1);
if (FAILED(res))
{
HX_RELEASE(pMimeType);
}
}
else
{
res = HXR_OUTOFMEMORY;
}
}
return res;
}
#endif
#if defined(_UNIX) && !defined(_MAC_UNIX)
HX_RESULT
CHXFileRecognizer::GetMimeTypeFromMagic(IHXBuffer* pBuffer,
REF(const char*) pMimeType)
{
HX_RESULT res = HXR_FAIL;
pMimeType = NULL;
HX_ASSERT(pBuffer);
if (pBuffer && pBuffer->GetSize())
{
UCHAR* pData = pBuffer->GetBuffer();
UINT32 uLength = pBuffer->GetSize();
// map magic data to a mime type
typedef struct
{
UINT32 uOffset;
const char* pMagic;
UINT32 uLength;
const char* pMimeType;
} magic_data;
// these are the magic tricks we know
const magic_data kMagicMap[] =
{
{ 0, "v=", 2, "application/sdp" },
{ 0, ".RA ", 4, REALAUDIO_MIME_TYPE },
{ 0, ".RMF", 4, REALMEDIA_MIME_TYPE },
{ 0, ".RMS", 4, REALMEDIA_MIME_TYPE },
{ 0, "OggS", 4, "audio/x-ogg", },
{ 0, "#!AMR", 5, "audio/amr" },
{ 0, "WAVE", 4, "audio/x-wav" },
{ 0, "GIF89a", 6, "image/gif" },
{ 0, "GIF87a", 6, "image/gif" },
{ 0, "\211PNG", 4, "image/png" },
{ 0, "\377\330\377\340", 4, "image/jpeg" },
{ 0, "BM", 2, "image/bmp" },
{ 0, "\355\253\356\333", 4, "application/x-rpm" },
{ 0, "FWS", 3, FLASH_MIME_TYPE },
{ 0, "CWS", 3, FLASH_MIME_TYPE },
{ 0, "#EXTM3U", 7, "audio/scpls" },
{ 0, NULL, 0, NULL } // null terminator
};
// find a matching magic string
for (const magic_data* pCursor = kMagicMap; pCursor->pMagic; ++pCursor)
{
if (pCursor->uOffset + pCursor->uLength < uLength &&
memcmp(pData + pCursor->uOffset,
pCursor->pMagic, pCursor->uLength) == 0)
{
pMimeType = pCursor->pMimeType;
res = HXR_OK;
break;
}
}
}
return res;
}
HX_RESULT
CHXFileRecognizer::TestMP3File(IHXBuffer* pBuffer,
const char* pFileName,
REF(const char*) pMimeType)
{
HX_RESULT res = HXR_FAIL;
HX_ASSERT(pBuffer);
BOOL bMPA = FALSE;
BOOL bID3 = FALSE;
if (pBuffer->GetSize() >= 4)
{
const char* pBegin = (const char*)pBuffer->GetBuffer();
// XXXNH: I stole this from /usr/share/misc/magic and it seems to
// do a good job of guessing mp3
UINT16 uShort = getshort((UINT8*)pBegin);
if ((uShort & 0xffe0) == 0xffe0 &&
(uShort & 0x0018) != 0x0008 &&
(uShort & 0x0006) != 0x0000)
{
bMPA = TRUE;
}
else if (memcmp(pBegin, "ID3\003", 4) == 0)
{
bID3 = TRUE;
}
}
if (bMPA || bID3)
{
res = HXR_OK;
pMimeType = "audio/mp3";
}
return res;
}
HX_RESULT
CHXFileRecognizer::TestSMILFile(IHXBuffer* pBuffer,
const char* pFileName,
REF(const char*) pMimeType)
{
HX_RESULT res = HXR_FAIL;
HX_ASSERT(pBuffer);
const char* pExt = strrchr(pFileName, '.');
BOOL bValidExt = pExt && (strcasecmp(pExt, ".smi") == 0 ||
strcasecmp(pExt, ".smil") == 0);
const char* pBegin = (const char*)pBuffer->GetBuffer();
UINT32 uLen = pBuffer->GetSize();
const char* pEnd = (const char*)((UINT32)pBegin + uLen);
BOOL bSMILFound = FALSE;
BOOL bBodyFound = FALSE;
for (const char* pCursor = pBegin;
(!bSMILFound || !bBodyFound) && pCursor && pCursor < pEnd;
pCursor = strpbrk(pCursor+1, "\n\r")) // next line
{
// eat whitespace
while (isspace(*pCursor) && pCursor < pEnd)
++pCursor;
const char* pTag = strchr(pCursor, '<');
while (pTag && (!bSMILFound || !bBodyFound))
{
if (!bSMILFound && strncasecmp(pTag, "<smil", 5) == 0)
{
bSMILFound = TRUE;
}
else if (!bBodyFound && strncasecmp(pTag, "<body", 5) == 0)
{
bBodyFound = TRUE;
}
pTag = strchr(pTag+1, '<');
}
}
if (bSMILFound && (bBodyFound || bValidExt))
{
// very likely a SMIL file
pMimeType = SMIL_MIME_TYPE;
res = HXR_OK;
}
return res;
}
HX_RESULT
CHXFileRecognizer::TestRAMFile(IHXBuffer* pBuffer,
const char* pFileName,
REF(const char*) pMimeType)
{
HX_RESULT res = HXR_FAIL;
HX_ASSERT(pBuffer);
const char* pBegin = (const char*)pBuffer->GetBuffer();
UINT32 uLen = pBuffer->GetSize();
const char* pEnd = (const char*)((UINT32)pBegin + uLen);
BOOL bProtocolFound = FALSE;
BOOL bHTML = FALSE;
for (const char* pCursor = pBegin; pCursor && pCursor < pEnd;
pCursor = strpbrk(pCursor+1, "\n\r")) // next line
{
// eat whitespace
while (isspace(*pCursor) && pCursor < pEnd)
++pCursor;
if (pCursor && pCursor < pEnd && *pCursor != '#') // skip comments
{
// do we have an html tag?
const char* pTag = strchr(pCursor, '<');
if (pTag && strncasecmp(pCursor, "<html", 5) == 0)
{
bHTML = TRUE;
break;
}
// find a protocol?
if (strncasecmp(pCursor, "rtsp://", 7) == 0 ||
strncasecmp(pCursor, "http://", 7) == 0 ||
strncasecmp(pCursor, "file://", 7) == 0 ||
strncasecmp(pCursor, "pnm://", 6) == 0)
{
bProtocolFound = TRUE;
break;
}
}
}
if (!bHTML && bProtocolFound)
{
// this is probably a RAM file
const char* pExt = strrchr(pFileName, '.');
if (pExt && strcasecmp(pExt, ".rpm") == 0)
{
pMimeType = REALAUDIO_PLUGIN_MIME_TYPE;
}
else
{
pMimeType = REALAUDIO_METAFILE_MIME_TYPE;
}
res = HXR_OK;
}
return res;
}
#else // #if defined(_UNIX) && !defined(_MAC_UNIX)
BOOL
CHXFileRecognizer::IsSDPFile(IHXBuffer* pBuffer)
{
BOOL bResult = FALSE;
if (pBuffer && pBuffer->GetSize())
{
if (0 == strncmp((const char*)pBuffer->GetBuffer(), "v=", 2))
{
bResult = TRUE;
}
}
return bResult;
}
#endif // #if defined(_UNIX) && !defined(_MAC_UNIX)
CHXFileRecognizer::CHXFileRecognizer()
: m_lRefCount(0),
m_pFile(NULL),
m_pResponse(NULL),
m_pBuffer(NULL),
m_bGetMimeTypeDone(FALSE)
{
}
CHXFileRecognizer::~CHXFileRecognizer()
{
HX_RELEASE(m_pBuffer);
HX_RELEASE(m_pResponse);
HX_RELEASE(m_pFile);
}
STDMETHODIMP CHXFileRecognizer::QueryInterface(REFIID riid, void** ppvObj)
{
HX_RESULT ret = HXR_OK;
if (IsEqualIID(riid, IID_IHXFileRecognizer))
{
AddRef();
*ppvObj = (IHXFileRecognizer*)this;
}
else if (IsEqualIID(riid, IID_IHXFileResponse))
{
AddRef();
*ppvObj = (IHXFileResponse*)this;
}
else if (IsEqualIID(riid, IID_IUnknown))
{
AddRef();
*ppvObj = this;
}
else
{
*ppvObj = NULL;
ret = HXR_NOINTERFACE;
}
return ret;
}
STDMETHODIMP_(ULONG32) CHXFileRecognizer::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
STDMETHODIMP_(ULONG32) CHXFileRecognizer::Release()
{
if (InterlockedDecrement(&m_lRefCount) > 0)
{
return m_lRefCount;
}
delete this;
return 0;
}
STDMETHODIMP CHXFileRecognizer::GetMimeType(IHXFileObject* /*IN*/ pFile,
IHXFileRecognizerResponse* /*IN*/ pRecognizerResponse)
{
HX_RESULT ret = HXR_FAIL;
if (pRecognizerResponse)
{
m_pResponse = pRecognizerResponse;
m_pResponse->AddRef();
}
// get our own IHXFileResponse interface
IHXFileResponse* pFileResponse = NULL;
ret = QueryInterface(IID_IHXFileResponse, (void**) &pFileResponse);
if (SUCCEEDED(ret) && pFileResponse && pFile != NULL)
{
m_pFile = pFile;
m_pFile->AddRef();
ret = m_pFile->Init(HX_FILE_READ | HX_FILE_BINARY, pFileResponse);
}
if (FAILED(ret) && m_pResponse)
{
m_pResponse->GetMimeTypeDone(ret, NULL);
}
HX_RELEASE(pFileResponse);
return ret;
}
STDMETHODIMP CHXFileRecognizer::InitDone(HX_RESULT status)
{
if (SUCCEEDED(status))
{
status = m_pFile->Read(RECOG_LEN);
}
if (FAILED(status) && m_pResponse)
{
m_pResponse->GetMimeTypeDone(status, NULL);
}
return status;
}
STDMETHODIMP CHXFileRecognizer::SeekDone(HX_RESULT /* status */)
{
if (!m_bGetMimeTypeDone)
{
DoFileRecognize();
HX_RELEASE(m_pBuffer);
}
return HXR_OK;
}
STDMETHODIMP CHXFileRecognizer::ReadDone(HX_RESULT status,
IHXBuffer* pBuffer)
{
if (FAILED(status) && m_pResponse)
{
m_pResponse->GetMimeTypeDone(HXR_FAIL, NULL);
}
else
{
HX_ASSERT(!m_pBuffer);
m_pBuffer = pBuffer;
HX_ADDREF(m_pBuffer);
// seek back to the beginning of the file
// since the same file object will be passed to the file format
if (HXR_OK != m_pFile->Seek(0, FALSE) &&
!m_bGetMimeTypeDone)
{
DoFileRecognize();
HX_RELEASE(m_pBuffer);
}
}
return HXR_OK;
}
STDMETHODIMP CHXFileRecognizer::WriteDone(HX_RESULT /* status */)
{
return HXR_OK;
}
STDMETHODIMP CHXFileRecognizer::CloseDone(HX_RESULT /* status */)
{
return HXR_OK;
}
void
CHXFileRecognizer::DoFileRecognize(void)
{
HX_RESULT ret = HXR_OK;
IHXBuffer* pMimeType = NULL;
const char* pFileName = NULL;
m_bGetMimeTypeDone = TRUE;
if (m_pFile)
m_pFile->GetFilename(pFileName);
ret = GetMimeType(pFileName, m_pBuffer, pMimeType);
if (SUCCEEDED(ret) &&
pMimeType &&
pMimeType->GetSize() > 0 &&
m_pResponse)
{
m_pResponse->GetMimeTypeDone(HXR_OK, pMimeType);
}
else
{
m_pResponse->GetMimeTypeDone(HXR_FAIL, NULL);
}
HX_RELEASE(pMimeType);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?