recognizer.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:12k
源码类别:

Symbian

开发平台:

Visual C++

  1. #include "ihxpckts.h"
  2. #include "hxbuffer.h"
  3. #include "hlxclib/ctype.h" /* for isspace() */
  4. #include "hxmarsh.h"      /* for getshort() */
  5. #include "recognizer.h"
  6. #define REALMEDIA_MIME_TYPE             "application/x-pn-realmedia"
  7. #define REALAUDIO_MIME_TYPE             "audio/x-pn-realaudio"
  8. #define FLASH_MIME_TYPE                 "application/x-shockwave-flash"
  9. #define REALAUDIO_METAFILE_MIME_TYPE    "audio/x-pn-realaudio"
  10. #define REALAUDIO_PLUGIN_MIME_TYPE      "audio/x-pn-realaudio-plugin"
  11. #define SMIL_MIME_TYPE                  "application/smil"
  12. // length of buffer read from file and passed to recognizer
  13. #if defined(_UNIX) && !defined(_MAC_UNIX)
  14. // we want a little more data, since we need to try to detect smil, ram and mp3
  15. #define RECOG_LEN 4096
  16. #else
  17. #define RECOG_LEN 512
  18. #endif
  19.  
  20. #if !defined (_SYMBIAN)
  21. HX_RESULT CHXFileRecognizer::GetMimeType(const char* pFileName, IHXBuffer* pBuffer, REF(IHXBuffer*) pMimeType)
  22. {
  23.     HX_RESULT res = HXR_FAIL;
  24.     const char* pMimeTypeStr = NULL;
  25. #if defined(_UNIX) && !defined(_MAC_UNIX)
  26.     do
  27.     {
  28. res = GetMimeTypeFromMagic(pBuffer, pMimeTypeStr);
  29. if (SUCCEEDED(res))
  30.     break;
  31. res = TestSMILFile(pBuffer, pFileName, pMimeTypeStr);
  32. if (SUCCEEDED(res))
  33.     break;
  34. res = TestRAMFile(pBuffer, pFileName, pMimeTypeStr);
  35. if (SUCCEEDED(res))
  36.     break;
  37. res = TestMP3File(pBuffer, pFileName, pMimeTypeStr);
  38.     }
  39.     while (0);
  40. #else // #if defined(_UNIX) && !defined(_MAC_UNIX)
  41.     if (IsSDPFile(pBuffer))
  42.     {
  43. pMimeTypeStr = "application/sdp";
  44. res = HXR_OK;
  45.     }
  46. #endif // #if defined(_UNIX) && !defined(_MAC_UNIX)
  47.     if (pMimeTypeStr)
  48.     {
  49.         // convert mime type to IHXBuffer
  50.         pMimeType = new CHXBuffer;
  51.         if (pMimeType)
  52.         {
  53.             pMimeType->AddRef();
  54.             int len = strlen(pMimeTypeStr);
  55.     res = pMimeType->Set((const UCHAR*)pMimeTypeStr, len + 1);
  56.     if (FAILED(res))
  57.     {
  58. HX_RELEASE(pMimeType);
  59.     }
  60.         }
  61. else
  62. {
  63.     res = HXR_OUTOFMEMORY;
  64. }
  65.     }
  66.     return res;
  67. }
  68. #endif
  69. #if defined(_UNIX) && !defined(_MAC_UNIX)
  70. HX_RESULT
  71. CHXFileRecognizer::GetMimeTypeFromMagic(IHXBuffer* pBuffer,
  72. REF(const char*) pMimeType)
  73. {
  74.     HX_RESULT res = HXR_FAIL;
  75.     pMimeType = NULL;
  76.     HX_ASSERT(pBuffer);
  77.     if (pBuffer && pBuffer->GetSize())
  78.     {
  79. UCHAR* pData = pBuffer->GetBuffer();
  80. UINT32 uLength = pBuffer->GetSize();
  81. // map magic data to a mime type
  82. typedef struct
  83. {
  84.     UINT32 uOffset;
  85.     const char* pMagic;
  86.     UINT32 uLength;
  87.     const char* pMimeType;
  88. } magic_data;
  89. // these are the magic tricks we know
  90. const magic_data kMagicMap[] =
  91.     {
  92. { 0, "v=",               2, "application/sdp" },
  93. { 0, ".RA ",             4, REALAUDIO_MIME_TYPE },
  94. { 0, ".RMF",             4, REALMEDIA_MIME_TYPE },
  95. { 0, ".RMS",             4, REALMEDIA_MIME_TYPE },
  96. { 0, "OggS",             4, "audio/x-ogg", },
  97. { 0, "#!AMR",            5, "audio/amr" },
  98. { 0, "WAVE",             4, "audio/x-wav" },
  99. { 0, "GIF89a",           6, "image/gif" },
  100. { 0, "GIF87a",           6, "image/gif" },
  101. { 0, "211PNG",          4, "image/png" },
  102. { 0, "377330377340", 4, "image/jpeg" },
  103. { 0, "BM",               2, "image/bmp" },
  104. { 0, "355253356333", 4, "application/x-rpm" },
  105. { 0, "FWS",              3, FLASH_MIME_TYPE },
  106. { 0, "CWS",              3, FLASH_MIME_TYPE },
  107. { 0, "#EXTM3U",          7, "audio/scpls" },
  108. { 0, NULL, 0, NULL } // null terminator
  109.     };
  110. // find a matching magic string
  111. for (const magic_data* pCursor = kMagicMap; pCursor->pMagic; ++pCursor)
  112. {
  113.     if (pCursor->uOffset + pCursor->uLength < uLength &&
  114. memcmp(pData + pCursor->uOffset, 
  115.        pCursor->pMagic, pCursor->uLength) == 0)
  116.     {
  117. pMimeType = pCursor->pMimeType;
  118. res = HXR_OK;
  119. break;
  120.     }
  121. }
  122.     }
  123.     return res;
  124. }
  125. HX_RESULT
  126. CHXFileRecognizer::TestMP3File(IHXBuffer* pBuffer,
  127.        const char* pFileName,
  128.        REF(const char*) pMimeType)
  129. {
  130.     HX_RESULT res = HXR_FAIL;
  131.     HX_ASSERT(pBuffer);
  132.     BOOL bMPA = FALSE;
  133.     BOOL bID3 = FALSE;
  134.     if (pBuffer->GetSize() >= 4)
  135.     {
  136. const char* pBegin = (const char*)pBuffer->GetBuffer();
  137. // XXXNH: I stole this from /usr/share/misc/magic and it seems to
  138. // do a good job of guessing mp3
  139. UINT16 uShort = getshort((UINT8*)pBegin);
  140. if ((uShort & 0xffe0) == 0xffe0 &&
  141.     (uShort & 0x0018) != 0x0008 &&
  142.     (uShort & 0x0006) != 0x0000)
  143. {
  144.     bMPA = TRUE;
  145. }
  146. else if (memcmp(pBegin, "ID303", 4) == 0)
  147. {
  148.     bID3 = TRUE;
  149. }
  150.     }
  151.     if (bMPA || bID3)
  152.     {
  153. res = HXR_OK;
  154. pMimeType = "audio/mp3";
  155.     }
  156.     return res;
  157. }
  158. HX_RESULT
  159. CHXFileRecognizer::TestSMILFile(IHXBuffer* pBuffer,
  160. const char* pFileName,
  161. REF(const char*) pMimeType)
  162. {
  163.     HX_RESULT res = HXR_FAIL;
  164.     HX_ASSERT(pBuffer);
  165.     const char* pExt = strrchr(pFileName, '.');
  166.     BOOL bValidExt = pExt && (strcasecmp(pExt, ".smi") == 0 ||
  167.       strcasecmp(pExt, ".smil") == 0);
  168.     const char* pBegin = (const char*)pBuffer->GetBuffer();
  169.     UINT32 uLen = pBuffer->GetSize();
  170.     const char* pEnd = (const char*)((UINT32)pBegin + uLen);
  171.     BOOL bSMILFound = FALSE;
  172.     BOOL bBodyFound = FALSE;
  173.     for (const char* pCursor = pBegin; 
  174.  (!bSMILFound || !bBodyFound) && pCursor && pCursor < pEnd; 
  175.  pCursor = strpbrk(pCursor+1, "nr")) // next line
  176.     {
  177. // eat whitespace
  178. while (isspace(*pCursor) && pCursor < pEnd)
  179.     ++pCursor;
  180. const char* pTag = strchr(pCursor, '<');
  181. while (pTag && (!bSMILFound || !bBodyFound))
  182. {
  183.     if (!bSMILFound && strncasecmp(pTag, "<smil", 5) == 0)
  184.     {
  185. bSMILFound = TRUE;
  186.     }
  187.     else if (!bBodyFound && strncasecmp(pTag, "<body", 5) == 0)
  188.     {
  189. bBodyFound = TRUE;
  190.     }
  191.     pTag = strchr(pTag+1, '<');
  192. }
  193.     }
  194.     if (bSMILFound && (bBodyFound || bValidExt))
  195.     {
  196. // very likely a SMIL file
  197. pMimeType = SMIL_MIME_TYPE;
  198. res = HXR_OK;
  199.     }
  200.     return res;
  201. }
  202. HX_RESULT
  203. CHXFileRecognizer::TestRAMFile(IHXBuffer* pBuffer,
  204.        const char* pFileName,
  205.        REF(const char*) pMimeType)
  206. {
  207.     HX_RESULT res = HXR_FAIL;
  208.     HX_ASSERT(pBuffer);
  209.     const char* pBegin = (const char*)pBuffer->GetBuffer();
  210.     UINT32 uLen = pBuffer->GetSize();
  211.     const char* pEnd = (const char*)((UINT32)pBegin + uLen);
  212.     BOOL bProtocolFound = FALSE;
  213.     BOOL bHTML = FALSE;
  214.     for (const char* pCursor = pBegin; pCursor && pCursor < pEnd; 
  215.  pCursor = strpbrk(pCursor+1, "nr")) // next line
  216.     {
  217. // eat whitespace
  218. while (isspace(*pCursor) && pCursor < pEnd)
  219.     ++pCursor;
  220. if (pCursor && pCursor < pEnd && *pCursor != '#') // skip comments
  221. {
  222.     // do we have an html tag?
  223.     const char* pTag = strchr(pCursor, '<');
  224.     if (pTag && strncasecmp(pCursor, "<html", 5) == 0)
  225.     {
  226. bHTML = TRUE;
  227. break;
  228.     }
  229.     // find a protocol?
  230.     if (strncasecmp(pCursor, "rtsp://", 7) == 0 ||
  231. strncasecmp(pCursor, "http://", 7) == 0 ||
  232. strncasecmp(pCursor, "file://", 7) == 0 ||
  233. strncasecmp(pCursor, "pnm://", 6) == 0)
  234.     {
  235. bProtocolFound = TRUE;
  236. break;
  237.     }
  238. }
  239.     }
  240.     if (!bHTML && bProtocolFound)
  241.     {
  242. // this is probably a RAM file
  243. const char* pExt = strrchr(pFileName, '.');
  244. if (pExt && strcasecmp(pExt, ".rpm") == 0)
  245. {
  246.     pMimeType = REALAUDIO_PLUGIN_MIME_TYPE;
  247. }
  248. else
  249. {
  250.     pMimeType = REALAUDIO_METAFILE_MIME_TYPE;
  251. }
  252. res = HXR_OK;
  253.     }
  254.     return res;
  255. }
  256. #else // #if defined(_UNIX) && !defined(_MAC_UNIX)
  257. BOOL
  258. CHXFileRecognizer::IsSDPFile(IHXBuffer* pBuffer)
  259. {
  260.     BOOL bResult = FALSE;
  261.     if (pBuffer && pBuffer->GetSize())
  262.     {
  263.         if (0 == strncmp((const char*)pBuffer->GetBuffer(), "v=", 2))
  264.         {
  265.             bResult = TRUE;
  266.         }
  267.     }
  268.     return bResult;
  269. }
  270. #endif // #if defined(_UNIX) && !defined(_MAC_UNIX)
  271. CHXFileRecognizer::CHXFileRecognizer()
  272.     : m_lRefCount(0),
  273.       m_pFile(NULL),
  274.       m_pResponse(NULL),
  275.       m_pBuffer(NULL),
  276.       m_bGetMimeTypeDone(FALSE)
  277. {
  278. }
  279. CHXFileRecognizer::~CHXFileRecognizer()
  280. {
  281.     HX_RELEASE(m_pBuffer);
  282.     HX_RELEASE(m_pResponse);
  283.     HX_RELEASE(m_pFile);
  284. }
  285. STDMETHODIMP CHXFileRecognizer::QueryInterface(REFIID riid, void** ppvObj)
  286. {
  287.     HX_RESULT ret = HXR_OK;
  288.     if (IsEqualIID(riid, IID_IHXFileRecognizer))
  289.     {
  290. AddRef();
  291. *ppvObj = (IHXFileRecognizer*)this;
  292.     }
  293.     else if (IsEqualIID(riid, IID_IHXFileResponse))
  294.     {
  295. AddRef();
  296. *ppvObj = (IHXFileResponse*)this;
  297.     }
  298.     else if (IsEqualIID(riid, IID_IUnknown))
  299.     {
  300. AddRef();
  301. *ppvObj = this;
  302.     }
  303.     else
  304.     {
  305. *ppvObj = NULL;
  306. ret = HXR_NOINTERFACE;
  307.     }
  308.     return ret;
  309. }
  310. STDMETHODIMP_(ULONG32) CHXFileRecognizer::AddRef()
  311. {
  312.     return InterlockedIncrement(&m_lRefCount);
  313. }
  314. STDMETHODIMP_(ULONG32) CHXFileRecognizer::Release()
  315. {
  316.     if (InterlockedDecrement(&m_lRefCount) > 0)
  317.     {
  318.         return m_lRefCount;
  319.     }
  320.     delete this;
  321.     return 0;
  322. }
  323. STDMETHODIMP CHXFileRecognizer::GetMimeType(IHXFileObject* /*IN*/ pFile, 
  324.     IHXFileRecognizerResponse* /*IN*/ pRecognizerResponse)
  325. {
  326.     HX_RESULT ret = HXR_FAIL;
  327.     if (pRecognizerResponse)
  328.     {
  329. m_pResponse = pRecognizerResponse;
  330. m_pResponse->AddRef();
  331.     }
  332.     
  333.     // get our own IHXFileResponse interface
  334.     IHXFileResponse* pFileResponse = NULL;
  335.     ret = QueryInterface(IID_IHXFileResponse, (void**) &pFileResponse);
  336.     if (SUCCEEDED(ret) && pFileResponse && pFile != NULL)
  337.     {
  338. m_pFile = pFile;
  339. m_pFile->AddRef();
  340.     
  341.         ret = m_pFile->Init(HX_FILE_READ | HX_FILE_BINARY, pFileResponse);
  342.     }
  343.     if (FAILED(ret) && m_pResponse)
  344.     {
  345. m_pResponse->GetMimeTypeDone(ret, NULL);
  346.     }
  347.     
  348.     HX_RELEASE(pFileResponse);
  349.     return ret;
  350. }
  351. STDMETHODIMP CHXFileRecognizer::InitDone(HX_RESULT status)
  352. {
  353.     if (SUCCEEDED(status))
  354.     {
  355. status = m_pFile->Read(RECOG_LEN);
  356.     }
  357.     if (FAILED(status) && m_pResponse)
  358.     {
  359. m_pResponse->GetMimeTypeDone(status, NULL);
  360.     }
  361.     return status;
  362. }
  363. STDMETHODIMP CHXFileRecognizer::SeekDone(HX_RESULT /* status */)
  364. {
  365.     if (!m_bGetMimeTypeDone)
  366.     {
  367.         DoFileRecognize();
  368.         HX_RELEASE(m_pBuffer);
  369.     }
  370.     return HXR_OK;
  371. }
  372. STDMETHODIMP CHXFileRecognizer::ReadDone(HX_RESULT status,
  373.  IHXBuffer* pBuffer)
  374. {
  375.     if (FAILED(status) && m_pResponse)
  376.     {
  377. m_pResponse->GetMimeTypeDone(HXR_FAIL, NULL);
  378.     }
  379.     else
  380.     {
  381.         HX_ASSERT(!m_pBuffer);
  382.         m_pBuffer = pBuffer;
  383.         HX_ADDREF(m_pBuffer);
  384.  
  385.          // seek back to the beginning of the file
  386.          // since the same file object will be passed to the file format
  387.         if (HXR_OK != m_pFile->Seek(0, FALSE) &&
  388.             !m_bGetMimeTypeDone)
  389.         {
  390.             DoFileRecognize();
  391.             HX_RELEASE(m_pBuffer);
  392.         }
  393.     }
  394.     return HXR_OK;
  395. }
  396. STDMETHODIMP CHXFileRecognizer::WriteDone(HX_RESULT /* status */)
  397. {
  398.     return HXR_OK;
  399. }
  400. STDMETHODIMP CHXFileRecognizer::CloseDone(HX_RESULT /* status */)
  401. {
  402.     return HXR_OK;
  403. }
  404. void
  405. CHXFileRecognizer::DoFileRecognize(void)
  406. {
  407.     HX_RESULT   ret = HXR_OK;
  408.     IHXBuffer*  pMimeType = NULL;
  409.     const char* pFileName = NULL;
  410.     m_bGetMimeTypeDone = TRUE;
  411.     if (m_pFile)
  412. m_pFile->GetFilename(pFileName);
  413.     ret = GetMimeType(pFileName, m_pBuffer, pMimeType);
  414.     if (SUCCEEDED(ret) && 
  415. pMimeType && 
  416. pMimeType->GetSize() > 0 && 
  417. m_pResponse)
  418.     {
  419. m_pResponse->GetMimeTypeDone(HXR_OK, pMimeType);
  420.     }
  421.     else
  422.     {
  423. m_pResponse->GetMimeTypeDone(HXR_FAIL, NULL);
  424.     }
  425.     HX_RELEASE(pMimeType);
  426. }