comimgff.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:34k
- /* ***** 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 ***** */
- #include "hxcom.h"
- #include "hxtypes.h"
- #include "hxwintyp.h"
- #include "hxcomm.h"
- #include "ihxpckts.h"
- #include "hxfiles.h"
- #include "hxformt.h"
- #include "hxplugn.h"
- #include "hxver.h"
- #include "baseobj.h"
- #include "pckunpck.h"
- #include "jpegdef.h"
- #include "wbmphdr.h"
- #include "unifimg.h"
- #include "comimgff.h"
- #include "comimgff.ver"
- #include "hxheap.h"
- #ifdef _DEBUG
- #undef HX_THIS_FILE
- static const char HX_THIS_FILE[] = __FILE__;
- #endif
- const char* const CCommonImageFileFormat::m_pszDescription = "Helix Common Image File Format Plugin";
- const char* const CCommonImageFileFormat::m_pszCopyright = HXVER_COPYRIGHT;
- const char* const CCommonImageFileFormat::m_pszMoreInfoURL = HXVER_MOREINFO;
- const char* const CCommonImageFileFormat::m_ppszFileMimeTypes[] = {"image/jpeg", "image/png", "image/x-wap.wbmp", NULL};
- const char* const CCommonImageFileFormat::m_ppszFileExtensions[] = {"jpg", "jpeg", "jpe", "jfif", "png", "wbmp", NULL};
- const char* const CCommonImageFileFormat::m_ppszFileOpenNames[] = {"Images (*.jpg,*.png,*.wbmp)", NULL};
- const char* const CCommonImageFileFormat::m_ppszStreamMimeType[] = {"image/jpeg", "image/png", "image/x-wap.wbmp", NULL};
- CCommonImageFileFormat::CCommonImageFileFormat()
- {
- m_lRefCount = 0;
- m_pContext = NULL;
- m_pFileObject = NULL;
- m_pFormatResponse = NULL;
- m_pCommonClassFactory = NULL;
- m_pFileMimeMapper = NULL;
- m_pURLStr = NULL;
- m_pMimeTypeStr = NULL;
- m_ulState = kStateReady;
- m_ulFileOffset = 0;
- m_ulDesiredFileOffset = 0;
- m_ulRequestedFileOffset = 0;
- m_ulHeaderReadSize = kInitialHeaderReadSize;
- m_bFileObjectOpen = FALSE;
- };
- CCommonImageFileFormat::~CCommonImageFileFormat()
- {
- if (m_pFileObject)
- {
- m_pFileObject->Close();
- }
- HX_RELEASE(m_pContext);
- HX_RELEASE(m_pFileObject);
- HX_RELEASE(m_pFormatResponse);
- HX_RELEASE(m_pCommonClassFactory);
- HX_RELEASE(m_pFileMimeMapper);
- HX_RELEASE(m_pURLStr);
- HX_RELEASE(m_pMimeTypeStr);
- };
- STDMETHODIMP CCommonImageFileFormat::QueryInterface(REFIID riid, void** ppvObj)
- {
- HX_RESULT retVal = HXR_FAIL;
- if (ppvObj)
- {
- // Set defaults
- *ppvObj = NULL;
- retVal = HXR_OK;
- // Switch on iid
- if (IsEqualIID(riid, IID_IUnknown))
- {
- AddRef();
- *ppvObj = (IUnknown*) (CHXBaseCountingObject*) (IHXPlugin*) this;
- }
- else if (IsEqualIID(riid, IID_IHXPlugin))
- {
- AddRef();
- *ppvObj = (IHXPlugin*) this;
- }
- else if (IsEqualIID(riid, IID_IHXFileFormatObject))
- {
- AddRef();
- *ppvObj = (IHXFileFormatObject*) this;
- }
- else if (IsEqualIID(riid, IID_IHXFileResponse))
- {
- AddRef();
- *ppvObj = (IHXFileResponse*) this;
- }
- else if (IsEqualIID(riid, IID_IHXFileMimeMapperResponse))
- {
- AddRef();
- *ppvObj = (IHXFileMimeMapperResponse*) this;
- }
- else
- {
- retVal = HXR_NOINTERFACE;
- }
- }
- return retVal;
- }
- STDMETHODIMP_(UINT32) CCommonImageFileFormat::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- STDMETHODIMP_(UINT32) CCommonImageFileFormat::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- STDMETHODIMP CCommonImageFileFormat::GetPluginInfo(REF(BOOL) rbLoadMultiple,
- REF(const char*) rpszDescription,
- REF(const char*) rpszCopyright,
- REF(const char*) rpszMoreInfoURL,
- REF(UINT32) rulVersionNumber)
- {
- rbLoadMultiple = TRUE;
- rpszDescription = (const char*) m_pszDescription;
- rpszCopyright = (const char*) m_pszCopyright;
- rpszMoreInfoURL = (const char*) m_pszMoreInfoURL;
- rulVersionNumber = TARVER_ULONG32_VERSION;
- return HXR_OK;
- }
- STDMETHODIMP CCommonImageFileFormat::InitPlugin(IUnknown* pContext)
- {
- HX_RESULT retVal = HXR_FAIL;
- if (pContext)
- {
- // Save a copy of the calling context
- HX_RELEASE(m_pContext);
- m_pContext = pContext;
- m_pContext->AddRef();
- // Get an interface to the common class factory
- HX_RELEASE(m_pCommonClassFactory);
- retVal = m_pContext->QueryInterface(IID_IHXCommonClassFactory,
- (void**) &m_pCommonClassFactory);
- }
- return retVal;
- }
- STDMETHODIMP CCommonImageFileFormat::GetFileFormatInfo(REF(const char**) rppszFileMimeTypes,
- REF(const char**) rppszFileExtensions,
- REF(const char**) rppszFileOpenNames)
- {
- rppszFileMimeTypes = (const char**) m_ppszFileMimeTypes;
- rppszFileExtensions = (const char**) m_ppszFileExtensions;
- rppszFileOpenNames = (const char**) m_ppszFileOpenNames;
- return HXR_OK;
- }
- STDMETHODIMP CCommonImageFileFormat::InitFileFormat(IHXRequest* pRequest,
- IHXFormatResponse* pFormatResponse,
- IHXFileObject* pFileObject)
- {
- HX_RESULT retVal = HXR_FAIL;
- if (pRequest && pFormatResponse && pFileObject)
- {
- if (m_ulState == kStateReady)
- {
- // Save members
- HX_RELEASE(m_pFormatResponse);
- m_pFormatResponse = pFormatResponse;
- m_pFormatResponse->AddRef();
- HX_RELEASE(m_pFileObject);
- m_pFileObject = pFileObject;
- m_pFileObject->AddRef();
- // Get the URL from the request
- const char* pszURL = NULL;
- retVal = pRequest->GetURL(pszURL);
- if (SUCCEEDED(retVal))
- {
- // Save the URL
- HX_RELEASE(m_pURLStr);
- retVal = CreateStringBuffer(m_pURLStr, pszURL, m_pContext);
- if (SUCCEEDED(retVal))
- {
- // Set the state
- m_ulState = kStateIFFInitDonePending;
- // Clear the return value
- retVal = HXR_OK;
- // Init the file object
- m_pFileObject->Init(HX_FILE_READ | HX_FILE_BINARY, this);
- }
- }
- }
- }
- if (FAILED(retVal) && pFormatResponse)
- {
- pFormatResponse->InitDone(HXR_FAIL);
- }
- return retVal;
- }
- STDMETHODIMP CCommonImageFileFormat::GetFileHeader()
- {
- HX_RESULT retVal = HXR_UNEXPECTED;
- if (m_ulState == kStateReady)
- {
- // Get an IHXValues object
- IHXValues* pHeader = NULL;
- retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXValues,
- (void**) &pHeader);
- if (SUCCEEDED(retVal))
- {
- // Set the stream count
- pHeader->SetPropertyULONG32("StreamCount", 1);
- // Call the response interface
- m_pFormatResponse->FileHeaderReady(HXR_OK, pHeader);
- }
- HX_RELEASE(pHeader);
- }
- if (FAILED(retVal) && m_pFormatResponse)
- {
- m_pFormatResponse->FileHeaderReady(retVal, NULL);
- }
- return retVal;
- }
- STDMETHODIMP CCommonImageFileFormat::GetStreamHeader(UINT16 usStreamNum)
- {
- HX_RESULT retVal = HXR_UNEXPECTED;
- if (m_ulState == kStateReady)
- {
- // Clear the return value
- retVal = HXR_OK;
- // Init the seeked file offset
- m_ulRequestedFileOffset = 0;
- // Set the state
- m_ulState = kStateGSHSeekDonePending;
- // Seek the file object to the beginning
- m_pFileObject->Seek(m_ulRequestedFileOffset, FALSE);
- }
- if (FAILED(retVal) && m_pFormatResponse)
- {
- m_pFormatResponse->StreamHeaderReady(retVal, NULL);
- }
- return retVal;
- }
- STDMETHODIMP CCommonImageFileFormat::GetPacket(UINT16 usStreamNum)
- {
- HX_RESULT retVal = HXR_UNEXPECTED;
- if (m_ulState == kStateReady && usStreamNum == 0)
- {
- // Clear the return value
- retVal = HXR_OK;
- // Are we already at the desired file offset?
- if (m_ulDesiredFileOffset == m_ulFileOffset)
- {
- // Set the state
- m_ulState = kStateGPReadDonePending;
- // Read kPacketSize bytes
- HX_RESULT res = m_pFileObject->Read(kPacketSize);
- if( HXR_FAIL == res)
- {
- //All the data has been read.
- ReadDone(HXR_FAIL, NULL );
- }
- }
- else
- {
- // Set the state
- m_ulState = kStateGPSeekDonePending;
- // Save the value we are trying to seek to
- m_ulRequestedFileOffset = m_ulDesiredFileOffset;
- // Seek to the desired file offset
- m_pFileObject->Seek(m_ulRequestedFileOffset, FALSE);
- }
- }
- if (FAILED(retVal) && m_pFormatResponse)
- {
- m_pFormatResponse->StreamDone(0);
- }
- return retVal;
- }
- STDMETHODIMP CCommonImageFileFormat::Seek(UINT32 ulOffset)
- {
- HX_RESULT retVal = HXR_UNEXPECTED;
- if (m_pFormatResponse)
- {
- // Clear the return value
- retVal = HXR_OK;
- // Set the desired file offset back to the beginning
- m_ulDesiredFileOffset = 0;
- // Is the file object currently open?
- if (m_bFileObjectOpen)
- {
- // The file object is still currently open,
- // so all we have to do is start reading
- // again back at the beginning of the file.
- //
- // Tell the response we're ready to start
- // giving packets again.
- m_pFormatResponse->SeekDone(HXR_OK);
- }
- else
- {
- // The file object has been closed. We need
- // to reopen it.
- //
- // Set the state
- m_ulState = kStateSeekInitDonePending;
- // Init the file object
- m_pFileObject->Init(HX_FILE_READ | HX_FILE_BINARY, this);
- }
- }
- return retVal;
- }
- STDMETHODIMP CCommonImageFileFormat::Close()
- {
- HX_RESULT retVal = HXR_OK;
- if (m_pFileObject)
- {
- m_pFileObject->Close();
- }
- HX_RELEASE(m_pContext);
- HX_RELEASE(m_pFileObject);
- HX_RELEASE(m_pFormatResponse);
- HX_RELEASE(m_pCommonClassFactory);
- HX_RELEASE(m_pFileMimeMapper);
- HX_RELEASE(m_pURLStr);
- HX_RELEASE(m_pMimeTypeStr);
- m_ulState = kStateReady;
- m_ulFileOffset = 0;
- m_ulDesiredFileOffset = 0;
- m_ulRequestedFileOffset = 0;
- return retVal;
- }
- STDMETHODIMP CCommonImageFileFormat::InitDone(HX_RESULT status)
- {
- HX_RESULT retVal = HXR_UNEXPECTED;
- if (m_ulState == kStateIFFInitDonePending)
- {
- // Clear the return value
- retVal = HXR_OK;
- // Did the init succeed?
- if (SUCCEEDED(status))
- {
- // Set the flag saying the file is open
- m_bFileObjectOpen = TRUE;
- // Try and get the IHXFileMimeMapper interface
- HX_RELEASE(m_pFileMimeMapper);
- m_pFileObject->QueryInterface(IID_IHXFileMimeMapper, (void**) &m_pFileMimeMapper);
- if (m_pFileMimeMapper)
- {
- // We got the IHXFileMimeMapper interface,
- // so get our own IHXFileMimeMapperResponse interface
- IHXFileMimeMapperResponse* pResponse = NULL;
- QueryInterface(IID_IHXFileMimeMapperResponse, (void**) &pResponse);
- // Set the state
- m_ulState = kStateIFFMimeTypeFoundPending;
- // Get the mime type
- m_pFileMimeMapper->FindMimeType((const char*) m_pURLStr->GetBuffer(), pResponse);
- // Now we can release our response interface
- HX_RELEASE(pResponse);
- }
- else
- {
- // We didn't get an IHXFileMimeMapper interface,
- // but that's not a reason to fail
- //
- // Set state
- m_ulState = kStateReady;
- // Call back to response interface
- m_pFormatResponse->InitDone(status);
- }
- }
- else
- {
- // Set the state
- m_ulState = kStateIFFCloseDonePending;
- // Close the file
- m_pFileObject->Close();
- }
- }
- else if (m_ulState == kStateSeekInitDonePending)
- {
- // Clear the return value
- retVal = HXR_OK;
- // Set the state
- m_ulState = kStateReady;
- // Did the init succeed?
- if (SUCCEEDED(status))
- {
- // Set the flag saying the file is open
- m_bFileObjectOpen = TRUE;
- }
- // Tell the response interface whether
- // or not the seek succeeded
- m_pFormatResponse->SeekDone(status);
- }
- return retVal;
- }
- STDMETHODIMP CCommonImageFileFormat::ReadDone(HX_RESULT status, IHXBuffer* pBuffer)
- {
- HX_RESULT retVal = HXR_UNEXPECTED;
- if (m_ulState == kStateGSHReadDonePending)
- {
- retVal = status;
- if (SUCCEEDED(retVal))
- {
- // Update the file offset
- m_ulFileOffset += pBuffer->GetSize();
- // Determine if this is a WBMP file based on the mime
- // type and the URL. We need to know this because WBMP
- // does not have any kind of identifying magic number
- // at the beginning of the file
- BOOL bIsWBMP = IsWBMP(m_pMimeTypeStr, m_pURLStr);
- // Determine width and height
- UINT32 ulWidth = 0;
- UINT32 ulHeight = 0;
- UINT32 ulImageType = 0;
- retVal = ParseWidthHeight(pBuffer, bIsWBMP, ulWidth, ulHeight, ulImageType);
- if (SUCCEEDED(retVal))
- {
- // Create a stream header
- IHXValues* pValues = NULL;
- retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXValues, (void**) &pValues);
- if (SUCCEEDED(retVal))
- {
- // Set the mime type
- SetCStringProperty(pValues,
- "MimeType",
- m_ppszStreamMimeType[ulImageType],
- m_pContext);
- // Set the intrinsic duration property
- SetCStringProperty(pValues,
- "intrinsicDurationType",
- "intrinsicDurationDiscrete",
- m_pContext);
- // Set the ASM rulebook
- SetCStringProperty(pValues,
- "ASMRuleBook",
- "AverageBandwidth=12000,Priority=5;",
- m_pContext);
- // Set some ULONG32 properties
- pValues->SetPropertyULONG32("StreamNumber", 0);
- pValues->SetPropertyULONG32("MaxBitRate", kBitrate);
- pValues->SetPropertyULONG32("AvgBitRate", kBitrate);
- pValues->SetPropertyULONG32("MaxPacketSize", kPacketSize);
- pValues->SetPropertyULONG32("AvgPacketSize", kPacketSize);
- pValues->SetPropertyULONG32("StartTime", 0);
- pValues->SetPropertyULONG32("PreRoll", kPreroll);
- pValues->SetPropertyULONG32("Duration", kDuration);
- pValues->SetPropertyULONG32("ContentVersion", 0);
- pValues->SetPropertyULONG32("StreamVersion", 0);
- pValues->SetPropertyULONG32("ImageWidth", ulWidth);
- pValues->SetPropertyULONG32("ImageHeight", ulHeight);
- // Set the state
- m_ulState = kStateReady;
- // Set the desired offset
- m_ulDesiredFileOffset = 0;
- // Send the stream header
- m_pFormatResponse->StreamHeaderReady(HXR_OK, pValues);
- }
- HX_RELEASE(pValues);
- }
- else
- {
- // We failed to find a supported image signature in the
- // amount of header of header we read. This may not be
- // a JPEG, PNG, or WBMP; or we just may not have read enough.
- // Sometimes JPEGs have lots of unnecessary header information
- // at the beginning of the file left there by Photoshop or
- // other image-editing tools. We will keep increasing the
- // header size that we read until we have read the entire
- // file. At that point, we will fail. We know we are not yet
- // reading the entire file when our buffer size matches
- // the header read size
- if (pBuffer->GetSize() == m_ulHeaderReadSize)
- {
- // We will assume we just haven't read enough bytes
- // at the beginning of the file, so double the header
- // read size
- m_ulHeaderReadSize = (m_ulHeaderReadSize << 1);
- // Clear the return value
- retVal = HXR_OK;
- // Init the seeked file offset
- m_ulRequestedFileOffset = 0;
- // Set the state
- m_ulState = kStateGSHSeekDonePending;
- // Seek the file object to the beginning
- m_pFileObject->Seek(m_ulRequestedFileOffset, FALSE);
- }
- }
- }
- if (FAILED(retVal))
- {
- // Set the state
- m_ulState = kStateGSHCloseDonePending;
- // Close the file
- m_pFileObject->Close();
- }
- }
- else if (m_ulState == kStateGPReadDonePending)
- {
- // Copy the read status
- retVal = status;
- // Did the read succeed?
- if (SUCCEEDED(retVal))
- {
- // Update the file offset
- m_ulFileOffset += pBuffer->GetSize();
- // Create a packet
- IHXPacket* pPacket = NULL;
- retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket, (void**) &pPacket);
- if (SUCCEEDED(retVal))
- {
- // Set the packet
- retVal = pPacket->Set(pBuffer, // data
- 0, // time stamp
- 0, // stream 0
- HX_ASM_SWITCH_ON, // ASM flag
- 0); // ASM rule
- if (SUCCEEDED(retVal))
- {
- // Update the desired file offset
- m_ulDesiredFileOffset = m_ulFileOffset;
- // Set the state
- m_ulState = kStateReady;
- // Return the packet
- m_pFormatResponse->PacketReady(HXR_OK, pPacket);
- }
- }
- HX_RELEASE(pPacket);
- }
- if (FAILED(retVal))
- {
- // Clear the return value
- retVal = HXR_OK;
- // Set the state
- m_ulState = kStateGPCloseDonePending;
- // Close the file
- m_pFileObject->Close();
- }
- }
- return retVal;
- }
- STDMETHODIMP CCommonImageFileFormat::SeekDone(HX_RESULT status)
- {
- HX_RESULT retVal = HXR_UNEXPECTED;
- if (m_ulState == kStateGSHSeekDonePending)
- {
- // Clear the return value
- retVal = HXR_OK;
- // Did the seek succeed?
- if (SUCCEEDED(status))
- {
- // Assign the actual file offset
- m_ulFileOffset = m_ulRequestedFileOffset;
- // Set the state
- m_ulState = kStateGSHReadDonePending;
- // Read the header
- m_pFileObject->Read(m_ulHeaderReadSize);
- }
- else
- {
- // Set the state
- m_ulState = kStateGSHCloseDonePending;
- // Close the file
- m_pFileObject->Close();
- }
- }
- else if (m_ulState == kStateGPSeekDonePending)
- {
- // Clear the return value
- retVal = HXR_OK;
- // Did the seek succeed?
- if (SUCCEEDED(status))
- {
- // Set the actual file offset
- m_ulFileOffset = m_ulRequestedFileOffset;
- // Set the state
- m_ulState = kStateGPReadDonePending;
- // Read kPacketSize bytes
- m_pFileObject->Read(kPacketSize);
- }
- else
- {
- // Set the state
- m_ulState = kStateGPCloseDonePending;
- // Close the file
- m_pFileObject->Close();
- }
- }
- return retVal;
- }
- STDMETHODIMP CCommonImageFileFormat::CloseDone(HX_RESULT status)
- {
- HX_RESULT retVal = HXR_UNEXPECTED;
- // Clear the file open flag
- m_bFileObjectOpen = FALSE;
- if (m_ulState == kStateIFFCloseDonePending)
- {
- // Clear the return value
- retVal = HXR_OK;
- // Set the state
- m_ulState = kStateReady;
- // Report failure to the response interface
- m_pFormatResponse->InitDone(HXR_FAIL);
- }
- else if (m_ulState == kStateGSHCloseDonePending)
- {
- // Clear the return value
- retVal = HXR_OK;
- // Set the state
- m_ulState = kStateReady;
- // Report failure to the response interface
- m_pFormatResponse->StreamHeaderReady(HXR_FAIL, NULL);
- }
- else if (m_ulState == kStateGPCloseDonePending)
- {
- // Clear the return value
- retVal = HXR_OK;
- // Set the state
- m_ulState = kStateReady;
- // Terminate the stream
- m_pFormatResponse->StreamDone(0);
- }
- return retVal;
- }
- STDMETHODIMP CCommonImageFileFormat::WriteDone(HX_RESULT status)
- {
- // We don't ever write, so we don't expect to get this...
- return HXR_UNEXPECTED;
- }
- STDMETHODIMP CCommonImageFileFormat::MimeTypeFound(HX_RESULT status, const char* pMimeType)
- {
- HX_RESULT retVal = HXR_UNEXPECTED;
- if (m_ulState == kStateIFFMimeTypeFoundPending)
- {
- // If we succeeded, then save the mime type.
- // However, even if we fail, then just go on.
- if (SUCCEEDED(status))
- {
- HX_RELEASE(m_pMimeTypeStr);
- CreateStringBuffer(m_pMimeTypeStr, pMimeType, m_pContext);
- }
- // Clear the return value
- retVal = HXR_OK;
- // Set the state
- m_ulState = kStateReady;
- // Call back to the response interface
- m_pFormatResponse->InitDone(HXR_OK);
- }
- if (FAILED(retVal) && m_pFormatResponse)
- {
- m_pFormatResponse->InitDone(retVal);
- }
- return retVal;
- }
- HX_RESULT STDAPICALLTYPE CCommonImageFileFormat::HXCreateInstance(IUnknown** ppIUnknown)
- {
- HX_RESULT retVal = HXR_FAIL;
- if (ppIUnknown)
- {
- // Set default
- *ppIUnknown = NULL;
- // Create the object
- CCommonImageFileFormat *pObj = new CCommonImageFileFormat();
- if (pObj)
- {
- // QI for IUnknown
- retVal = pObj->QueryInterface(IID_IUnknown, (void**) ppIUnknown);
- }
- if (FAILED(retVal))
- {
- HX_DELETE(pObj);
- }
- }
- return retVal;
- }
- BOOL CCommonImageFileFormat::_GetNextJPGMarker( BYTE** pBuf,
- BYTE* pBufEnd,
- BYTE* ucMarkerType )
- {
- BOOL bRetVal = FALSE;
- BYTE* pPtr = *pBuf;
- UINT unSize = 0;
-
- // JPEG segment layout:
- // byte value
- // 1 0xFF(JPEG_MARKER_FLAG)
- // 2 segment type (marker type)
- // 3 MSB segment size. Size does not include bytes 1 & 2.
- // 4 LSB segment size. Size does not include bytes 1 & 2.
- // 5..n segment data.
-
- //If we are called pointing to the start of a segment, then we get
- //the size and skip to the end of the segment before scanning for
- //the next marker.
- if( pBufEnd-pPtr >= 2 && *pPtr==JPEG_MARKER_FLAG )
- {
- unSize = 0;
- if( _HasSize(*(pPtr+1)) && pBufEnd-pPtr>=4 )
- {
- unSize = (*(pPtr+2)<<8)|*(pPtr+3);
- }
- pPtr += unSize+2; //first 2 segment bytes not included.
-
- }
-
- //Scan for the next JPEG_MARKER_FLAG
- while(pPtr<pBufEnd && JPEG_MARKER_FLAG!=*pPtr)
- pPtr++;
- //Did we find a marker and have at least 4 bytes for the header?
- if( pBufEnd-pPtr>=4 && JPEG_MARKER_FLAG==*pPtr )
- {
- *ucMarkerType = *(pPtr+1);
- *pBuf = pPtr;
- bRetVal = TRUE;
- }
- return bRetVal;
- }
- BOOL CCommonImageFileFormat::_ParseJPGSOFSegment( BYTE* pBuf,
- BYTE* pBufEnd,
- UINT32& ulWidth,
- UINT32& ulHeight )
- {
- // JPEG SOF0, SOF1, SOF2 segments....
- // byte1: 0xFF(JPEG_MARKER_FLAG)
- // byte2: SOF marker tag
- // byte3: MSB segment size
- // byte4: LSB segment size
- // Size does not include byte1 or byte2
- // byte5: percision, bits/pixel
- // byte6: MSB image height
- // byte7: LSB image height
- // byte8: MSB image width
- // byte9: LSB image width
- BOOL bRetVal = FALSE;
- if( pBufEnd-pBuf>=9 )
- {
- ulHeight = (pBuf[5] << 8) | pBuf[6];
- ulWidth = (pBuf[7] << 8) | pBuf[8];
- bRetVal = HXR_OK;
- }
- return bRetVal;
- }
- BOOL CCommonImageFileFormat::_HasSize( BYTE marker )
- {
- BOOL bRet = TRUE;
- switch(marker)
- {
- case JPEG_MARKER_RST0: //fall through
- case JPEG_MARKER_RST1: //fall through
- case JPEG_MARKER_RST2: //fall through
- case JPEG_MARKER_RST3: //fall through
- case JPEG_MARKER_RST4: //fall through
- case JPEG_MARKER_RST5: //fall through
- case JPEG_MARKER_RST6: //fall through
- case JPEG_MARKER_RST7: //fall through
- case JPEG_MARKER_TEM: //fall through
- case JPEG_MARKER_SOI: //fall through
- case JPEG_MARKER_EOI:
- bRet = FALSE;
- break;
- };
- return bRet;
- }
- BOOL CCommonImageFileFormat::_IsJPEG( BYTE* pBuf, BYTE* pBufEnd )
- {
- BOOL bRetVal = FALSE;
- if( pBufEnd-pBuf >=2 )
- {
- if( JPEG_MARKER_FLAG==pBuf[0] && JPEG_MARKER_SOI==pBuf[1] )
- bRetVal = TRUE;
- }
- return bRetVal;
- }
- HX_RESULT CCommonImageFileFormat::ParseWidthHeight(IHXBuffer* pBuffer,
- BOOL bIsWBMP,
- REF(UINT32) rulWidth,
- REF(UINT32) rulHeight,
- REF(UINT32) rulImageType)
- {
- HX_RESULT retVal = HXR_FAIL;
-
- if (pBuffer)
- {
- // Set the parsing variables
- BYTE* pBuf = pBuffer->GetBuffer();
- BYTE* pBufLimit = pBuf + pBuffer->GetSize();
- // Do we already know this is WBMP?
- if (bIsWBMP)
- {
- // Parse the WBMP header
- UINT32 ulTmp = 0;
- retVal = ParseWBMPHeader(pBuf,
- pBuffer->GetSize(),
- rulWidth,
- rulHeight,
- ulTmp);
- if (SUCCEEDED(retVal))
- {
- // Set the image type
- rulImageType = UNIF_IMAGETYPE_WBMP;
- }
- }
- else
- {
- // This is not WBMP, so check for JPEG, GIF, and PNG
- //
- // Test for JPEG
- BYTE ucMarkerType = 0;
- BOOL bExit = FALSE;
- if( _IsJPEG(pBuf, pBufLimit) )
- {
- // Set the image type
- rulImageType = UNIF_IMAGETYPE_JPEG;
-
- //Start searching for the SOF*
- while( !bExit && _GetNextJPGMarker(&pBuf, pBufLimit, &ucMarkerType) )
- {
- switch(ucMarkerType)
- {
- case JPEG_MARKER_SOF0: //fall through
- case JPEG_MARKER_SOF1: //fall through
- case JPEG_MARKER_SOF2:
- retVal = _ParseJPGSOFSegment(pBuf, pBufLimit, rulWidth, rulHeight);
- bExit = TRUE;
- break;
- case JPEG_MARKER_EOI:
- //If we find the end of image marker its too late.
- retVal = HXR_FAIL;
- bExit = TRUE;
- break;
- default:
- break;
- }
- }
- }
- // Uncomment this if we support GIF in the
- // future. For now, do GIF with GIF plugins (not unified)
- #if 0
- else if (pBuf + 10 <= pBufLimit &&
- pBuf[0] == 'G' && pBuf[1] == 'I' &&
- pBuf[2] == 'F' && pBuf[3] == '8' &&
- (pBuf[4] == '7' || pBuf[4] == '9') &&
- pBuf[5] == 'a')
- {
- // Set the image type to GIF
- rulImageType = UNIF_IMAGETYPE_GIF;
- // Parse for width and height
- rulWidth = (pBuf[7] << 8) | pBuf[6];
- rulHeight = (pBuf[9] << 8) | pBuf[8];
- // Clear the return value
- retVal = HXR_OK;
- }
- #endif
- else if (pBuf + 8 <= pBufLimit &&
- pBuf[0] == 0x89 && pBuf[1] == 0x50 &&
- pBuf[2] == 0x4e && pBuf[3] == 0x47 &&
- pBuf[4] == 0x0d && pBuf[5] == 0x0a &&
- pBuf[6] == 0x1a && pBuf[7] == 0x0a)
- {
- // Set the image type to PNG
- rulImageType = UNIF_IMAGETYPE_PNG;
- // Skip the PNG signature
- pBuf += 8;
- // Scan for IHDR chunk, which should be first
- if (pBuf + 16 <= pBufLimit &&
- pBuf[4] == 'I' && pBuf[5] == 'H' &&
- pBuf[6] == 'D' && pBuf[7] == 'R')
- {
- // Get the width and height
- rulWidth = (pBuf[8] << 24) |
- (pBuf[9] << 16) |
- (pBuf[10] << 8) |
- (pBuf[11]);
- rulHeight = (pBuf[12] << 24) |
- (pBuf[13] << 16) |
- (pBuf[14] << 8) |
- (pBuf[15]);
- retVal = HXR_OK;
- }
- }
- }
- }
- return retVal;
- }
- BOOL CCommonImageFileFormat::IsWBMP(IHXBuffer* pMimeTypeStr, IHXBuffer* pURLStr)
- {
- BOOL bRet = FALSE;
- // Check the mime type first (if we have it)
- if (pMimeTypeStr)
- {
- const char* pszMimeType = (const char*) pMimeTypeStr->GetBuffer();
- if (pszMimeType && !strcmp(pszMimeType, "image/x-wap.wbmp"))
- {
- // This *is* a WBMP file
- bRet = TRUE;
- }
- }
- if (!bRet && pURLStr)
- {
- // Do a quick-and-dirty check for the extension
- const char* pszURL = (const char*) pURLStr->GetBuffer();
- if (pszURL)
- {
- char* pszDot = strrchr(pszURL, '.');
- if (pszDot && strlen(pszDot) >= 5)
- {
- char* pszExt = pszDot + 1;
- if (!strncmp(pszExt, "wbmp", 4))
- {
- bRet = TRUE;
- }
- }
- }
- }
- return bRet;
- }