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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "hxcom.h"
  36. #include "hxtypes.h"
  37. #include "hxwintyp.h"
  38. #include "hxcomm.h"
  39. #include "ihxpckts.h"
  40. #include "hxfiles.h"
  41. #include "hxformt.h"
  42. #include "hxplugn.h"
  43. #include "hxver.h"
  44. #include "baseobj.h"
  45. #include "pckunpck.h"
  46. #include "jpegdef.h"
  47. #include "wbmphdr.h"
  48. #include "unifimg.h"
  49. #include "comimgff.h"
  50. #include "comimgff.ver"
  51. #include "hxheap.h"
  52. #ifdef _DEBUG
  53. #undef HX_THIS_FILE
  54. static const char HX_THIS_FILE[] = __FILE__;
  55. #endif
  56. const char* const CCommonImageFileFormat::m_pszDescription       = "Helix Common Image File Format Plugin";
  57. const char* const CCommonImageFileFormat::m_pszCopyright         = HXVER_COPYRIGHT;
  58. const char* const CCommonImageFileFormat::m_pszMoreInfoURL       = HXVER_MOREINFO;
  59. const char* const CCommonImageFileFormat::m_ppszFileMimeTypes[]  = {"image/jpeg", "image/png", "image/x-wap.wbmp", NULL};
  60. const char* const CCommonImageFileFormat::m_ppszFileExtensions[] = {"jpg", "jpeg", "jpe", "jfif", "png",  "wbmp", NULL};
  61. const char* const CCommonImageFileFormat::m_ppszFileOpenNames[]  = {"Images (*.jpg,*.png,*.wbmp)", NULL};
  62. const char* const CCommonImageFileFormat::m_ppszStreamMimeType[] = {"image/jpeg", "image/png", "image/x-wap.wbmp", NULL};
  63. CCommonImageFileFormat::CCommonImageFileFormat()
  64. {
  65.     m_lRefCount             = 0;
  66.     m_pContext              = NULL;
  67.     m_pFileObject           = NULL;
  68.     m_pFormatResponse       = NULL;
  69.     m_pCommonClassFactory   = NULL;
  70.     m_pFileMimeMapper       = NULL;
  71.     m_pURLStr               = NULL;
  72.     m_pMimeTypeStr          = NULL;
  73.     m_ulState               = kStateReady;
  74.     m_ulFileOffset          = 0;
  75.     m_ulDesiredFileOffset   = 0;
  76.     m_ulRequestedFileOffset = 0;
  77.     m_ulHeaderReadSize      = kInitialHeaderReadSize;
  78.     m_bFileObjectOpen       = FALSE;
  79. };
  80. CCommonImageFileFormat::~CCommonImageFileFormat()
  81. {
  82.     if (m_pFileObject)
  83.     {
  84.         m_pFileObject->Close();
  85.     }
  86.     HX_RELEASE(m_pContext);
  87.     HX_RELEASE(m_pFileObject);
  88.     HX_RELEASE(m_pFormatResponse);
  89.     HX_RELEASE(m_pCommonClassFactory);
  90.     HX_RELEASE(m_pFileMimeMapper);
  91.     HX_RELEASE(m_pURLStr);
  92.     HX_RELEASE(m_pMimeTypeStr);
  93. };
  94. STDMETHODIMP CCommonImageFileFormat::QueryInterface(REFIID riid, void** ppvObj)
  95. {
  96.     HX_RESULT retVal = HXR_FAIL;
  97.     if (ppvObj)
  98.     {
  99.         // Set defaults
  100.         *ppvObj = NULL;
  101.         retVal  = HXR_OK;
  102.         // Switch on iid
  103.         if (IsEqualIID(riid, IID_IUnknown))
  104.         {
  105.             AddRef();
  106.             *ppvObj = (IUnknown*) (CHXBaseCountingObject*) (IHXPlugin*) this;
  107.         }
  108.         else if (IsEqualIID(riid, IID_IHXPlugin))
  109.         {
  110.             AddRef();
  111.             *ppvObj = (IHXPlugin*) this;
  112.         }
  113.         else if (IsEqualIID(riid, IID_IHXFileFormatObject))
  114.         {
  115.             AddRef();
  116.             *ppvObj = (IHXFileFormatObject*) this;
  117.         }
  118.         else if (IsEqualIID(riid, IID_IHXFileResponse))
  119.         {
  120.             AddRef();
  121.             *ppvObj = (IHXFileResponse*) this;
  122.         }
  123.         else if (IsEqualIID(riid, IID_IHXFileMimeMapperResponse))
  124.         {
  125.             AddRef();
  126.             *ppvObj = (IHXFileMimeMapperResponse*) this;
  127.         }
  128.         else
  129.         {
  130.             retVal = HXR_NOINTERFACE;
  131.         }
  132.     }
  133.     return retVal;
  134. }
  135. STDMETHODIMP_(UINT32) CCommonImageFileFormat::AddRef()
  136. {
  137.     return InterlockedIncrement(&m_lRefCount);
  138. }
  139. STDMETHODIMP_(UINT32) CCommonImageFileFormat::Release()
  140. {
  141.     if (InterlockedDecrement(&m_lRefCount) > 0)
  142.     {
  143.         return m_lRefCount;
  144.     }
  145.     delete this;
  146.     return 0;
  147. }
  148. STDMETHODIMP CCommonImageFileFormat::GetPluginInfo(REF(BOOL)        rbLoadMultiple,
  149.                                                    REF(const char*) rpszDescription,
  150.                                                    REF(const char*) rpszCopyright,
  151.                                                    REF(const char*) rpszMoreInfoURL,
  152.                                                    REF(UINT32)      rulVersionNumber)
  153. {
  154.     rbLoadMultiple   = TRUE;
  155.     rpszDescription  = (const char*) m_pszDescription;
  156.     rpszCopyright    = (const char*) m_pszCopyright;
  157.     rpszMoreInfoURL  = (const char*) m_pszMoreInfoURL;
  158.     rulVersionNumber = TARVER_ULONG32_VERSION;
  159.     return HXR_OK;
  160. }
  161. STDMETHODIMP CCommonImageFileFormat::InitPlugin(IUnknown* pContext)
  162. {
  163.     HX_RESULT retVal = HXR_FAIL;
  164.     if (pContext)
  165.     {
  166.         // Save a copy of the calling context
  167.         HX_RELEASE(m_pContext);
  168.         m_pContext = pContext;
  169.         m_pContext->AddRef();
  170.         // Get an interface to the common class factory
  171.         HX_RELEASE(m_pCommonClassFactory);
  172.         retVal = m_pContext->QueryInterface(IID_IHXCommonClassFactory,
  173.                                             (void**) &m_pCommonClassFactory);
  174.     }
  175.     return retVal;
  176. }
  177. STDMETHODIMP CCommonImageFileFormat::GetFileFormatInfo(REF(const char**) rppszFileMimeTypes,
  178.                                                        REF(const char**) rppszFileExtensions,  
  179.                                                        REF(const char**) rppszFileOpenNames)
  180. {
  181.     rppszFileMimeTypes  = (const char**) m_ppszFileMimeTypes;
  182.     rppszFileExtensions = (const char**) m_ppszFileExtensions;
  183.     rppszFileOpenNames  = (const char**) m_ppszFileOpenNames;
  184.     return HXR_OK;
  185. }
  186. STDMETHODIMP CCommonImageFileFormat::InitFileFormat(IHXRequest*        pRequest, 
  187.                                                     IHXFormatResponse* pFormatResponse,
  188.                                                     IHXFileObject*     pFileObject)
  189. {
  190.     HX_RESULT retVal = HXR_FAIL;
  191.     if (pRequest && pFormatResponse && pFileObject)
  192.     {
  193.         if (m_ulState == kStateReady)
  194.         {
  195.             // Save members
  196.             HX_RELEASE(m_pFormatResponse);
  197.             m_pFormatResponse = pFormatResponse;
  198.             m_pFormatResponse->AddRef();
  199.             HX_RELEASE(m_pFileObject);
  200.             m_pFileObject = pFileObject;
  201.             m_pFileObject->AddRef();
  202.             // Get the URL from the request
  203.             const char* pszURL = NULL;
  204.             retVal = pRequest->GetURL(pszURL);
  205.             if (SUCCEEDED(retVal))
  206.             {
  207.                 // Save the URL
  208.                 HX_RELEASE(m_pURLStr);
  209.                 retVal = CreateStringBuffer(m_pURLStr, pszURL, m_pContext);
  210.                 if (SUCCEEDED(retVal))
  211.                 {
  212.                     // Set the state
  213.                     m_ulState = kStateIFFInitDonePending;
  214.                     // Clear the return value
  215.                     retVal = HXR_OK;
  216.                     // Init the file object
  217.                     m_pFileObject->Init(HX_FILE_READ | HX_FILE_BINARY, this);
  218.                 }
  219.             }
  220.         }
  221.     }
  222.     if (FAILED(retVal) && pFormatResponse)
  223.     {
  224.         pFormatResponse->InitDone(HXR_FAIL);
  225.     }
  226.     return retVal;
  227. }
  228. STDMETHODIMP CCommonImageFileFormat::GetFileHeader()
  229. {
  230.     HX_RESULT retVal = HXR_UNEXPECTED;
  231.     if (m_ulState == kStateReady)
  232.     {
  233.         // Get an IHXValues object
  234.         IHXValues* pHeader = NULL;
  235.         retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXValues,
  236.                                             (void**) &pHeader);
  237.         if (SUCCEEDED(retVal))
  238.         {
  239.             // Set the stream count
  240.             pHeader->SetPropertyULONG32("StreamCount", 1);
  241.             // Call the response interface
  242.             m_pFormatResponse->FileHeaderReady(HXR_OK, pHeader);
  243.         }
  244.         HX_RELEASE(pHeader);
  245.     }
  246.     if (FAILED(retVal) && m_pFormatResponse)
  247.     {
  248.         m_pFormatResponse->FileHeaderReady(retVal, NULL);
  249.     }
  250.     return retVal;
  251. }
  252. STDMETHODIMP CCommonImageFileFormat::GetStreamHeader(UINT16 usStreamNum)
  253. {
  254.     HX_RESULT retVal = HXR_UNEXPECTED;
  255.     if (m_ulState == kStateReady)
  256.     {
  257.         // Clear the return value
  258.         retVal = HXR_OK;
  259.         // Init the seeked file offset
  260.         m_ulRequestedFileOffset = 0;
  261.         // Set the state
  262.         m_ulState = kStateGSHSeekDonePending;
  263.         // Seek the file object to the beginning
  264.         m_pFileObject->Seek(m_ulRequestedFileOffset, FALSE);
  265.     }
  266.     if (FAILED(retVal) && m_pFormatResponse)
  267.     {
  268.         m_pFormatResponse->StreamHeaderReady(retVal, NULL);
  269.     }
  270.     return retVal;
  271. }
  272. STDMETHODIMP CCommonImageFileFormat::GetPacket(UINT16 usStreamNum)
  273. {
  274.     HX_RESULT retVal = HXR_UNEXPECTED;
  275.     if (m_ulState == kStateReady && usStreamNum == 0)
  276.     {
  277.         // Clear the return value
  278.         retVal = HXR_OK;
  279.         // Are we already at the desired file offset?
  280.         if (m_ulDesiredFileOffset == m_ulFileOffset)
  281.         {
  282.             // Set the state
  283.             m_ulState = kStateGPReadDonePending;
  284.             // Read kPacketSize bytes
  285.             HX_RESULT res = m_pFileObject->Read(kPacketSize);
  286.             if( HXR_FAIL == res) 
  287.             {
  288.                 //All the data has been read.
  289.                 ReadDone(HXR_FAIL, NULL );
  290.             }
  291.         }
  292.         else
  293.         {
  294.             // Set the state
  295.             m_ulState = kStateGPSeekDonePending;
  296.             // Save the value we are trying to seek to
  297.             m_ulRequestedFileOffset = m_ulDesiredFileOffset;
  298.             // Seek to the desired file offset
  299.             m_pFileObject->Seek(m_ulRequestedFileOffset, FALSE);
  300.         }
  301.     }
  302.     if (FAILED(retVal) && m_pFormatResponse)
  303.     {
  304.         m_pFormatResponse->StreamDone(0);
  305.     }
  306.     return retVal;
  307. }
  308. STDMETHODIMP CCommonImageFileFormat::Seek(UINT32 ulOffset)
  309. {
  310.     HX_RESULT retVal = HXR_UNEXPECTED;
  311.     if (m_pFormatResponse)
  312.     {
  313.         // Clear the return value
  314.         retVal = HXR_OK;
  315.         // Set the desired file offset back to the beginning
  316.         m_ulDesiredFileOffset = 0;
  317.         // Is the file object currently open?
  318.         if (m_bFileObjectOpen)
  319.         {
  320.             // The file object is still currently open,
  321.             // so all we have to do is start reading
  322.             // again back at the beginning of the file.
  323.             //
  324.             // Tell the response we're ready to start
  325.             // giving packets again.
  326.             m_pFormatResponse->SeekDone(HXR_OK);
  327.         }
  328.         else
  329.         {
  330.             // The file object has been closed. We need
  331.             // to reopen it.
  332.             //
  333.             // Set the state
  334.             m_ulState = kStateSeekInitDonePending;
  335.             // Init the file object
  336.             m_pFileObject->Init(HX_FILE_READ | HX_FILE_BINARY, this);
  337.         }
  338.     }
  339.     return retVal;
  340. }
  341. STDMETHODIMP CCommonImageFileFormat::Close()
  342. {
  343.     HX_RESULT retVal = HXR_OK;
  344.     if (m_pFileObject)
  345.     {
  346.         m_pFileObject->Close();
  347.     }
  348.     HX_RELEASE(m_pContext);
  349.     HX_RELEASE(m_pFileObject);
  350.     HX_RELEASE(m_pFormatResponse);
  351.     HX_RELEASE(m_pCommonClassFactory);
  352.     HX_RELEASE(m_pFileMimeMapper);
  353.     HX_RELEASE(m_pURLStr);
  354.     HX_RELEASE(m_pMimeTypeStr);
  355.     m_ulState               = kStateReady;
  356.     m_ulFileOffset          = 0;
  357.     m_ulDesiredFileOffset   = 0;
  358.     m_ulRequestedFileOffset = 0;
  359.     return retVal;
  360. }
  361. STDMETHODIMP CCommonImageFileFormat::InitDone(HX_RESULT status)
  362. {
  363.     HX_RESULT retVal = HXR_UNEXPECTED;
  364.     if (m_ulState == kStateIFFInitDonePending)
  365.     {
  366.         // Clear the return value
  367.         retVal = HXR_OK;
  368.         // Did the init succeed?
  369.         if (SUCCEEDED(status))
  370.         {
  371.             // Set the flag saying the file is open
  372.             m_bFileObjectOpen = TRUE;
  373.             // Try and get the IHXFileMimeMapper interface
  374.             HX_RELEASE(m_pFileMimeMapper);
  375.             m_pFileObject->QueryInterface(IID_IHXFileMimeMapper, (void**) &m_pFileMimeMapper);
  376.             if (m_pFileMimeMapper)
  377.             {
  378.                 // We got the IHXFileMimeMapper interface,
  379.                 // so get our own IHXFileMimeMapperResponse interface
  380.                 IHXFileMimeMapperResponse* pResponse = NULL;
  381.                 QueryInterface(IID_IHXFileMimeMapperResponse, (void**) &pResponse);
  382.                 // Set the state
  383.                 m_ulState = kStateIFFMimeTypeFoundPending;
  384.                 // Get the mime type
  385.                 m_pFileMimeMapper->FindMimeType((const char*) m_pURLStr->GetBuffer(), pResponse);
  386.                 // Now we can release our response interface
  387.                 HX_RELEASE(pResponse);
  388.             }
  389.             else
  390.             {
  391.                 // We didn't get an IHXFileMimeMapper interface,
  392.                 // but that's not a reason to fail
  393.                 //
  394.                 // Set state
  395.                 m_ulState = kStateReady;
  396.                 // Call back to response interface
  397.                 m_pFormatResponse->InitDone(status);
  398.             }
  399.         }
  400.         else
  401.         {
  402.             // Set the state
  403.             m_ulState = kStateIFFCloseDonePending;
  404.             // Close the file
  405.             m_pFileObject->Close();
  406.         }
  407.     }
  408.     else if (m_ulState == kStateSeekInitDonePending)
  409.     {
  410.         // Clear the return value
  411.         retVal = HXR_OK;
  412.         // Set the state
  413.         m_ulState = kStateReady;
  414.         // Did the init succeed?
  415.         if (SUCCEEDED(status))
  416.         {
  417.             // Set the flag saying the file is open
  418.             m_bFileObjectOpen = TRUE;
  419.         }
  420.         // Tell the response interface whether
  421.         // or not the seek succeeded
  422.         m_pFormatResponse->SeekDone(status);
  423.     }
  424.     return retVal;
  425. }
  426. STDMETHODIMP CCommonImageFileFormat::ReadDone(HX_RESULT status, IHXBuffer* pBuffer)
  427. {
  428.     HX_RESULT retVal = HXR_UNEXPECTED;
  429.     if (m_ulState == kStateGSHReadDonePending)
  430.     {
  431.         retVal = status;
  432.         if (SUCCEEDED(retVal))
  433.         {
  434.             // Update the file offset
  435.             m_ulFileOffset += pBuffer->GetSize();
  436.             // Determine if this is a WBMP file based on the mime
  437.             // type and the URL. We need to know this because WBMP
  438.             // does not have any kind of identifying magic number
  439.             // at the beginning of the file
  440.             BOOL bIsWBMP = IsWBMP(m_pMimeTypeStr, m_pURLStr);
  441.             // Determine width and height
  442.             UINT32 ulWidth     = 0;
  443.             UINT32 ulHeight    = 0;
  444.             UINT32 ulImageType = 0;
  445.             retVal = ParseWidthHeight(pBuffer, bIsWBMP, ulWidth, ulHeight, ulImageType);
  446.             if (SUCCEEDED(retVal))
  447.             {
  448.                 // Create a stream header
  449.                 IHXValues* pValues = NULL;
  450.                 retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXValues, (void**) &pValues);
  451.                 if (SUCCEEDED(retVal))
  452.                 {
  453.                     // Set the mime type
  454.                     SetCStringProperty(pValues,
  455.                                        "MimeType",
  456.                                        m_ppszStreamMimeType[ulImageType],
  457.                                        m_pContext);
  458.                     // Set the intrinsic duration property
  459.                     SetCStringProperty(pValues,
  460.                                        "intrinsicDurationType",
  461.                                        "intrinsicDurationDiscrete",
  462.                                        m_pContext);
  463.                     // Set the ASM rulebook
  464.                     SetCStringProperty(pValues,
  465.                                        "ASMRuleBook",
  466.                                        "AverageBandwidth=12000,Priority=5;",
  467.                                        m_pContext);
  468.                     // Set some ULONG32 properties
  469.                     pValues->SetPropertyULONG32("StreamNumber",     0);
  470.                     pValues->SetPropertyULONG32("MaxBitRate",       kBitrate);
  471.                     pValues->SetPropertyULONG32("AvgBitRate",       kBitrate);
  472.                     pValues->SetPropertyULONG32("MaxPacketSize",    kPacketSize);
  473.                     pValues->SetPropertyULONG32("AvgPacketSize",    kPacketSize);
  474.                     pValues->SetPropertyULONG32("StartTime",        0);
  475.                     pValues->SetPropertyULONG32("PreRoll",          kPreroll);
  476.                     pValues->SetPropertyULONG32("Duration",         kDuration);
  477.                     pValues->SetPropertyULONG32("ContentVersion",   0);
  478.                     pValues->SetPropertyULONG32("StreamVersion",    0);
  479.                     pValues->SetPropertyULONG32("ImageWidth",       ulWidth);
  480.                     pValues->SetPropertyULONG32("ImageHeight",      ulHeight);
  481.                     // Set the state
  482.                     m_ulState = kStateReady;
  483.                     // Set the desired offset
  484.                     m_ulDesiredFileOffset = 0;
  485.                     // Send the stream header
  486.                     m_pFormatResponse->StreamHeaderReady(HXR_OK, pValues);
  487.                 }
  488.                 HX_RELEASE(pValues);
  489.             }
  490.             else
  491.             {
  492.                 // We failed to find a supported image signature in the
  493.                 // amount of header of header we read. This may not be
  494.                 // a JPEG, PNG, or WBMP; or we just may not have read enough.
  495.                 // Sometimes JPEGs have lots of unnecessary header information
  496.                 // at the beginning of the file left there by Photoshop or
  497.                 // other image-editing tools. We will keep increasing the 
  498.                 // header size that we read until we have read the entire
  499.                 // file. At that point, we will fail. We know we are not yet
  500.                 // reading the entire file when our buffer size matches
  501.                 // the header read size
  502.                 if (pBuffer->GetSize() == m_ulHeaderReadSize)
  503.                 {
  504.                     // We will assume we just haven't read enough bytes
  505.                     // at the beginning of the file, so double the header
  506.                     // read size
  507.                     m_ulHeaderReadSize = (m_ulHeaderReadSize << 1);
  508.                     // Clear the return value
  509.                     retVal = HXR_OK;
  510.                     // Init the seeked file offset
  511.                     m_ulRequestedFileOffset = 0;
  512.                     // Set the state
  513.                     m_ulState = kStateGSHSeekDonePending;
  514.                     // Seek the file object to the beginning
  515.                     m_pFileObject->Seek(m_ulRequestedFileOffset, FALSE);
  516.                 }
  517.             }
  518.         }
  519.         if (FAILED(retVal))
  520.         {
  521.             // Set the state
  522.             m_ulState = kStateGSHCloseDonePending;
  523.             // Close the file
  524.             m_pFileObject->Close();
  525.         }
  526.     }
  527.     else if (m_ulState == kStateGPReadDonePending)
  528.     {
  529.         // Copy the read status
  530.         retVal = status;
  531.         // Did the read succeed?
  532.         if (SUCCEEDED(retVal))
  533.         {
  534.             // Update the file offset
  535.             m_ulFileOffset += pBuffer->GetSize();
  536.             // Create a packet
  537.             IHXPacket* pPacket = NULL;
  538.             retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket, (void**) &pPacket);
  539.             if (SUCCEEDED(retVal))
  540.             {
  541.                 // Set the packet
  542.                 retVal = pPacket->Set(pBuffer,           // data
  543.                                       0,                 // time stamp
  544.                                       0,                 // stream 0
  545.                                       HX_ASM_SWITCH_ON,  // ASM flag
  546.                                       0);                // ASM rule
  547.                 if (SUCCEEDED(retVal))
  548.                 {
  549.                     // Update the desired file offset
  550.                     m_ulDesiredFileOffset = m_ulFileOffset;
  551.                     // Set the state
  552.                     m_ulState = kStateReady;
  553.                     // Return the packet
  554.                     m_pFormatResponse->PacketReady(HXR_OK, pPacket);
  555.                 }
  556.             }
  557.             HX_RELEASE(pPacket);
  558.         }
  559.         if (FAILED(retVal))
  560.         {
  561.             // Clear the return value
  562.             retVal = HXR_OK;
  563.             // Set the state
  564.             m_ulState = kStateGPCloseDonePending;
  565.             // Close the file
  566.             m_pFileObject->Close();
  567.         }
  568.     }
  569.     return retVal;
  570. }
  571. STDMETHODIMP CCommonImageFileFormat::SeekDone(HX_RESULT status)
  572. {
  573.     HX_RESULT retVal = HXR_UNEXPECTED;
  574.     if (m_ulState == kStateGSHSeekDonePending)
  575.     {
  576.         // Clear the return value
  577.         retVal = HXR_OK;
  578.         // Did the seek succeed?
  579.         if (SUCCEEDED(status))
  580.         {
  581.             // Assign the actual file offset
  582.             m_ulFileOffset = m_ulRequestedFileOffset;
  583.             // Set the state
  584.             m_ulState = kStateGSHReadDonePending;
  585.             // Read the header
  586.             m_pFileObject->Read(m_ulHeaderReadSize);
  587.         }
  588.         else
  589.         {
  590.             // Set the state
  591.             m_ulState = kStateGSHCloseDonePending;
  592.             // Close the file
  593.             m_pFileObject->Close();
  594.         }
  595.     }
  596.     else if (m_ulState == kStateGPSeekDonePending)
  597.     {
  598.         // Clear the return value
  599.         retVal = HXR_OK;
  600.         // Did the seek succeed?
  601.         if (SUCCEEDED(status))
  602.         {
  603.             // Set the actual file offset
  604.             m_ulFileOffset = m_ulRequestedFileOffset;
  605.             // Set the state
  606.             m_ulState = kStateGPReadDonePending;
  607.             // Read kPacketSize bytes
  608.             m_pFileObject->Read(kPacketSize);
  609.         }
  610.         else
  611.         {
  612.             // Set the state
  613.             m_ulState = kStateGPCloseDonePending;
  614.             // Close the file
  615.             m_pFileObject->Close();
  616.         }
  617.     }
  618.     return retVal;
  619. }
  620. STDMETHODIMP CCommonImageFileFormat::CloseDone(HX_RESULT status)
  621. {
  622.     HX_RESULT retVal = HXR_UNEXPECTED;
  623.     // Clear the file open flag
  624.     m_bFileObjectOpen = FALSE;
  625.     if (m_ulState == kStateIFFCloseDonePending)
  626.     {
  627.         // Clear the return value
  628.         retVal = HXR_OK;
  629.         // Set the state
  630.         m_ulState = kStateReady;
  631.         // Report failure to the response interface
  632.         m_pFormatResponse->InitDone(HXR_FAIL);
  633.     }
  634.     else if (m_ulState == kStateGSHCloseDonePending)
  635.     {
  636.         // Clear the return value
  637.         retVal = HXR_OK;
  638.         // Set the state
  639.         m_ulState = kStateReady;
  640.         // Report failure to the response interface
  641.         m_pFormatResponse->StreamHeaderReady(HXR_FAIL, NULL);
  642.     }
  643.     else if (m_ulState == kStateGPCloseDonePending)
  644.     {
  645.         // Clear the return value
  646.         retVal = HXR_OK;
  647.         // Set the state
  648.         m_ulState = kStateReady;
  649.         // Terminate the stream
  650.         m_pFormatResponse->StreamDone(0);
  651.     }
  652.     return retVal;
  653. }
  654. STDMETHODIMP CCommonImageFileFormat::WriteDone(HX_RESULT status)
  655. {
  656.     // We don't ever write, so we don't expect to get this...
  657.     return HXR_UNEXPECTED;
  658. }
  659. STDMETHODIMP CCommonImageFileFormat::MimeTypeFound(HX_RESULT status, const char* pMimeType)
  660. {
  661.     HX_RESULT retVal = HXR_UNEXPECTED;
  662.     if (m_ulState == kStateIFFMimeTypeFoundPending)
  663.     {
  664.         // If we succeeded, then save the mime type.
  665.         // However, even if we fail, then just go on.
  666.         if (SUCCEEDED(status))
  667.         {
  668.             HX_RELEASE(m_pMimeTypeStr);
  669.             CreateStringBuffer(m_pMimeTypeStr, pMimeType, m_pContext);
  670.         }
  671.         // Clear the return value
  672.         retVal = HXR_OK;
  673.         // Set the state
  674.         m_ulState = kStateReady;
  675.         // Call back to the response interface
  676.         m_pFormatResponse->InitDone(HXR_OK);
  677.     }
  678.     if (FAILED(retVal) && m_pFormatResponse)
  679.     {
  680.         m_pFormatResponse->InitDone(retVal);
  681.     }
  682.     return retVal;
  683. }
  684. HX_RESULT STDAPICALLTYPE CCommonImageFileFormat::HXCreateInstance(IUnknown** ppIUnknown)
  685. {
  686.     HX_RESULT retVal = HXR_FAIL;
  687.     if (ppIUnknown)
  688.     {
  689.         // Set default
  690.         *ppIUnknown = NULL;
  691.         // Create the object
  692.         CCommonImageFileFormat *pObj = new CCommonImageFileFormat();
  693.         if (pObj)
  694.         {
  695.             // QI for IUnknown
  696.             retVal = pObj->QueryInterface(IID_IUnknown, (void**) ppIUnknown);
  697.         }
  698.         if (FAILED(retVal))
  699.         {
  700.             HX_DELETE(pObj);
  701.         }
  702.     }
  703.     return retVal;
  704. }
  705. BOOL CCommonImageFileFormat::_GetNextJPGMarker( BYTE** pBuf,
  706.                                                 BYTE* pBufEnd,
  707.                                                 BYTE* ucMarkerType )
  708. {
  709.     BOOL  bRetVal = FALSE;
  710.     BYTE* pPtr    = *pBuf;
  711.     UINT  unSize  = 0;
  712.     
  713.     // JPEG segment layout:
  714.     // byte  value
  715.     //  1    0xFF(JPEG_MARKER_FLAG)
  716.     //  2    segment type (marker type)
  717.     //  3    MSB segment size. Size does not include bytes 1 & 2.
  718.     //  4    LSB segment size. Size does not include bytes 1 & 2.
  719.     // 5..n  segment data.
  720.     
  721.     //If we are called pointing to the start of a segment, then we get
  722.     //the size and skip to the end of the segment before scanning for
  723.     //the next marker.
  724.     if( pBufEnd-pPtr >= 2 && *pPtr==JPEG_MARKER_FLAG )
  725.     {
  726.         unSize = 0;
  727.         if( _HasSize(*(pPtr+1)) && pBufEnd-pPtr>=4 )
  728.         {
  729.             unSize = (*(pPtr+2)<<8)|*(pPtr+3);
  730.         }
  731.         pPtr += unSize+2; //first 2 segment bytes not included.
  732.         
  733.     }
  734.     
  735.     //Scan for the next JPEG_MARKER_FLAG
  736.     while(pPtr<pBufEnd && JPEG_MARKER_FLAG!=*pPtr)
  737.         pPtr++;
  738.     //Did we find a marker and have at least 4 bytes for the header?
  739.     if( pBufEnd-pPtr>=4 && JPEG_MARKER_FLAG==*pPtr )
  740.     {
  741.         *ucMarkerType = *(pPtr+1);
  742.         *pBuf = pPtr;
  743.         bRetVal = TRUE;
  744.     }
  745.     return bRetVal;
  746. }
  747. BOOL CCommonImageFileFormat::_ParseJPGSOFSegment( BYTE* pBuf,
  748.                                                   BYTE* pBufEnd,
  749.                                                   UINT32& ulWidth,
  750.                                                   UINT32& ulHeight )
  751. {
  752.     // JPEG SOF0, SOF1, SOF2 segments....
  753.     // byte1:  0xFF(JPEG_MARKER_FLAG)
  754.     // byte2:  SOF marker tag
  755.     // byte3:  MSB segment size
  756.     // byte4:  LSB segment size
  757.     //         Size does not include byte1 or byte2
  758.     // byte5:  percision, bits/pixel
  759.     // byte6:  MSB image height
  760.     // byte7:  LSB image height
  761.     // byte8:  MSB image width
  762.     // byte9:  LSB image width
  763.     BOOL bRetVal = FALSE;
  764.     if( pBufEnd-pBuf>=9 )
  765.     {
  766.         ulHeight = (pBuf[5] << 8) | pBuf[6];
  767.         ulWidth  = (pBuf[7] << 8) | pBuf[8];
  768.         bRetVal  = HXR_OK;
  769.     }
  770.     return bRetVal;
  771. }
  772. BOOL CCommonImageFileFormat::_HasSize( BYTE marker )
  773. {
  774.     BOOL bRet = TRUE;
  775.     switch(marker)
  776.     {
  777.        case JPEG_MARKER_RST0: //fall through
  778.        case JPEG_MARKER_RST1: //fall through
  779.        case JPEG_MARKER_RST2: //fall through
  780.        case JPEG_MARKER_RST3: //fall through
  781.        case JPEG_MARKER_RST4: //fall through
  782.        case JPEG_MARKER_RST5: //fall through
  783.        case JPEG_MARKER_RST6: //fall through
  784.        case JPEG_MARKER_RST7: //fall through
  785.        case JPEG_MARKER_TEM:  //fall through
  786.        case JPEG_MARKER_SOI:  //fall through
  787.        case JPEG_MARKER_EOI:
  788.         bRet = FALSE;
  789.         break;
  790.     };
  791.     return bRet;
  792. }
  793. BOOL CCommonImageFileFormat::_IsJPEG( BYTE* pBuf, BYTE* pBufEnd )
  794. {
  795.     BOOL bRetVal = FALSE;
  796.     if( pBufEnd-pBuf >=2 )
  797.     {
  798.         if( JPEG_MARKER_FLAG==pBuf[0] && JPEG_MARKER_SOI==pBuf[1] )
  799.             bRetVal = TRUE;
  800.     }
  801.     return bRetVal;
  802. }
  803. HX_RESULT CCommonImageFileFormat::ParseWidthHeight(IHXBuffer* pBuffer,
  804.                                                    BOOL bIsWBMP,
  805.                                                    REF(UINT32) rulWidth,
  806.                                                    REF(UINT32) rulHeight,
  807.                                                    REF(UINT32) rulImageType)
  808. {
  809.     HX_RESULT retVal = HXR_FAIL;
  810.     
  811.     if (pBuffer)
  812.     {
  813.         // Set the parsing variables
  814.         BYTE* pBuf      = pBuffer->GetBuffer();
  815.         BYTE* pBufLimit = pBuf + pBuffer->GetSize();
  816.         // Do we already know this is WBMP?
  817.         if (bIsWBMP)
  818.         {
  819.             // Parse the WBMP header
  820.             UINT32 ulTmp = 0;
  821.             retVal = ParseWBMPHeader(pBuf,
  822.                                      pBuffer->GetSize(),
  823.                                      rulWidth,
  824.                                      rulHeight,
  825.                                      ulTmp);
  826.             if (SUCCEEDED(retVal))
  827.             {
  828.                 // Set the image type
  829.                 rulImageType = UNIF_IMAGETYPE_WBMP;
  830.             }
  831.         }
  832.         else
  833.         {
  834.             // This is not WBMP, so check for JPEG, GIF, and PNG
  835.             //
  836.             // Test for JPEG
  837.             BYTE  ucMarkerType = 0;
  838.             BOOL  bExit        = FALSE;
  839.             if( _IsJPEG(pBuf, pBufLimit) )
  840.             {
  841.                 // Set the image type
  842.                 rulImageType = UNIF_IMAGETYPE_JPEG;
  843.                 
  844.                 //Start searching for the SOF* 
  845.                 while( !bExit && _GetNextJPGMarker(&pBuf, pBufLimit, &ucMarkerType) )
  846.                 {
  847.                     switch(ucMarkerType)
  848.                     {
  849.                        case JPEG_MARKER_SOF0: //fall through
  850.                        case JPEG_MARKER_SOF1: //fall through
  851.                        case JPEG_MARKER_SOF2:
  852.                            retVal = _ParseJPGSOFSegment(pBuf, pBufLimit, rulWidth, rulHeight);
  853.                            bExit = TRUE;
  854.                            break;
  855.                        case JPEG_MARKER_EOI:
  856.                            //If we find the end of image marker its too late.
  857.                            retVal = HXR_FAIL;
  858.                            bExit  = TRUE;
  859.                            break;
  860.                        default:
  861.                            break;
  862.                     }
  863.                 }
  864.             }
  865. // Uncomment this if we support GIF in the
  866. // future. For now, do GIF with GIF plugins (not unified)
  867. #if 0
  868.             else if (pBuf + 10 <= pBufLimit &&
  869.                      pBuf[0] == 'G' && pBuf[1] == 'I' &&
  870.                      pBuf[2] == 'F' && pBuf[3] == '8' &&
  871.                      (pBuf[4] == '7' || pBuf[4] == '9') &&
  872.                      pBuf[5] == 'a')
  873.             {
  874.                 // Set the image type to GIF
  875.                 rulImageType = UNIF_IMAGETYPE_GIF;
  876.                 // Parse for width and height
  877.                 rulWidth  = (pBuf[7] << 8) | pBuf[6];
  878.                 rulHeight = (pBuf[9] << 8) | pBuf[8];
  879.                 // Clear the return value
  880.                 retVal = HXR_OK;
  881.             }
  882. #endif
  883.             else if (pBuf + 8 <= pBufLimit &&
  884.                      pBuf[0] == 0x89 && pBuf[1] == 0x50 &&
  885.                      pBuf[2] == 0x4e && pBuf[3] == 0x47 &&
  886.                      pBuf[4] == 0x0d && pBuf[5] == 0x0a &&
  887.                      pBuf[6] == 0x1a && pBuf[7] == 0x0a)
  888.             {
  889.                 // Set the image type to PNG
  890.                 rulImageType = UNIF_IMAGETYPE_PNG;
  891.                 // Skip the PNG signature
  892.                 pBuf += 8;
  893.                 // Scan for IHDR chunk, which should be first
  894.                 if (pBuf + 16 <= pBufLimit &&
  895.                     pBuf[4] == 'I' && pBuf[5] == 'H' &&
  896.                     pBuf[6] == 'D' && pBuf[7] == 'R')
  897.                 {
  898.                     // Get the width and height
  899.                     rulWidth   = (pBuf[8]  << 24) |
  900.                         (pBuf[9]  << 16) |
  901.                         (pBuf[10] <<  8) |
  902.                         (pBuf[11]);
  903.                     rulHeight  = (pBuf[12] << 24) |
  904.                         (pBuf[13] << 16) |
  905.                         (pBuf[14] <<  8) |
  906.                         (pBuf[15]);
  907.                     retVal = HXR_OK;
  908.                 }
  909.             }
  910.         }
  911.     }
  912.     return retVal;
  913. }
  914. BOOL CCommonImageFileFormat::IsWBMP(IHXBuffer* pMimeTypeStr, IHXBuffer* pURLStr)
  915. {
  916.     BOOL bRet = FALSE;
  917.     // Check the mime type first (if we have it)
  918.     if (pMimeTypeStr)
  919.     {
  920.         const char* pszMimeType = (const char*) pMimeTypeStr->GetBuffer();
  921.         if (pszMimeType && !strcmp(pszMimeType, "image/x-wap.wbmp"))
  922.         {
  923.             // This *is* a WBMP file
  924.             bRet = TRUE;
  925.         }
  926.     }
  927.     if (!bRet && pURLStr)
  928.     {
  929.         // Do a quick-and-dirty check for the extension
  930.         const char* pszURL = (const char*) pURLStr->GetBuffer();
  931.         if (pszURL)
  932.         {
  933.             char* pszDot = strrchr(pszURL, '.');
  934.             if (pszDot && strlen(pszDot) >= 5)
  935.             {
  936.                 char* pszExt = pszDot + 1;
  937.                 if (!strncmp(pszExt, "wbmp", 4))
  938.                 {
  939.                     bRet = TRUE;
  940.                 }
  941.             }
  942.         }
  943.     }
  944.     return bRet;
  945. }