📄 gifcodec.cpp
字号:
} while (ulBlockSize > 0); break; case kCommentExtension: case kPlainTextExtension: pBuf += 2; SkipBlocks(pBuf, pBufLimit); break; case kApplicationExtension: ParseApplicationExtension(pBuf); break; default: // An extension we don't know - just try to // pass it through pBuf += 2; SkipBlocks(pBuf, pBufLimit); break; } } else if (pBuf[0] == kTrailer) { /* We found a GIF trailer - we should be at the end of the file */ cMarkList.PushBack((void *) pBuf); break; } else { // Sometimes extra 0 blocks get stuck in GIFs. Check for them // here - if the current byte is 0, then it's OK. If it's not, // then we've gotten lost somewhere. if (pBuf[0] == 0x00) { pBuf++; } else { // Something is wrong with the GIF file. // // XXXMEH - instead of returning an error, we will // be lax and just break here. This will have the effect // of potentially sending garbage GIFs down to the // client. The upside is that there are a lot of // non-standard GIFs out there that will display in // browsers and this will allow them to be displayed. break; } } } /* The last mark is, of course, the end of the file. */ cMarkList.PushBack((void *) pBufLimit); /* * Now we convert our list to a more usable array of ParseSegment's. First * we compute the number of segments, which is one less than the number * of marks. */ m_ulNumSegmentsAllocated = cMarkList.Size() - 1; if (m_ulNumSegmentsAllocated == 0 || m_ulNumSegmentsAllocated > cMarkList.Size()) { return HXR_UNEXPECTED; } /* Allocate memory for the segment array */ if (m_pSegment) { delete [] m_pSegment; m_pSegment = NULL; } m_pSegment = new ParseSegment [m_ulNumSegmentsAllocated]; if (!m_pSegment) { return HXR_OUTOFMEMORY; } /* * Now run through the list of marks, computing segments. Note that * if the mark in the marklist is an extension not necessary for * deompression, we do not make it into a segment. */ m_ulNumSegments = 0; GListIterator itr = cMarkList.Begin(); BYTE *pLastMark = (BYTE *) *itr; itr++; do { BYTE *pCurMark = (BYTE *) *itr; /* * Filter out all unwanted extensions. We don't send application, * comment, or plain text extensions. We also don't send the GIF * Trailer */ if (!((pLastMark[0] == kExtension && (pLastMark[1] == kApplicationExtension || pLastMark[1] == kCommentExtension || pLastMark[1] == kPlainTextExtension)) || pLastMark[0] == kTrailer)) { m_pSegment[m_ulNumSegments].pMark = pLastMark; m_pSegment[m_ulNumSegments].ulSize = pCurMark - pLastMark; m_ulNumSegments++; } pLastMark = pCurMark; itr++; } while (itr != cMarkList.End()); /* Now we're done with the list */ cMarkList.EraseAll(); /* Set the state */ m_ulParseState = kStateParseInitialized; return HXR_OK;}UINT32 CGIFCodec::GetDelayTime(UINT32 i){ if (i >= m_ulNumImages || m_bIsGIF89a == FALSE) { return 0; } UINT32 ulDelay; ParseSegment *pSeg = &m_pSegment[1 + (i << 1)]; if (pSeg->pMark[0] == kExtension && pSeg->pMark[1] == kGraphicControlExtension) { CGIFImage::GraphicControlExtension cGCE; CGIFImage::ParseGraphicControlExtension(pSeg->pMark + 3, cGCE); ulDelay = cGCE.m_ulDelayTime; if (ulDelay == 0) { ulDelay = 1; } } else { ulDelay = 0; } return ulDelay;}UINT32 CGIFCodec::GetImageDataSize(UINT32 i){ if (i >= m_ulNumImages) { return 0; } return m_pSegment[2 + (i << 1)].ulSize;}HX_RESULT CGIFCodec::GetPacketBufferLength(UINT32 &rulLen){ /* Check state */ if (m_ulParseState != kStateParseInitialized && m_ulParseState != kStateParseInProgress) { return HXR_UNEXPECTED; } /* Is this our first time here? */ if (m_ulParseState == kStateParseInitialized) { /* This is the first time here - we need to find the header length */ UINT32 ulLen = 8 + /* Container header size, num images */ 8 * m_ulNumImages + /* Image header size and compressed data size */ m_pSegment[0].ulSize; /* Container header */ /* * Add the individual image header sizes - these are the segments which * begin with either an Image Descriptor or a GCE. */ UINT32 i; for (i = 0; i < m_ulNumSegments; i++) { BYTE *pMark = m_pSegment[i].pMark; if ( pMark[0] == kImageDescriptor || (pMark[0] == kExtension && pMark[1] == kGraphicControlExtension)) { ulLen += m_pSegment[i].ulSize; } } /* Set the initial segment for data packet parsing */ m_ulCurSegIndex = 2; m_ulCurSegOffset = 0; /* We have our length */ rulLen = ulLen; } else { /* This is NOT the first time here - we need to find the data packet length */ BYTE *pBufStart = m_pSegment[m_ulCurSegIndex].pMark; BYTE *pBuf = pBufStart + m_ulCurSegOffset; UINT32 ulSize = 0; /* If we are at the beginning of a LZW segment, we need to skip the min code size */ if (m_ulCurSegOffset == 0) { pBuf++; ulSize++; } /* Advance through the blocks, until we reach the ideal packet size */ UINT32 ulBlockSize; do { ulBlockSize = *pBuf; ulSize += ulBlockSize + 1; pBuf += ulBlockSize + 1; } while (ulBlockSize > 0 && ulSize < kIdealPacketSize); /* * Make a check to see if what's left over is not less than the * minimum packet size. If it IS less than the minimum packet size, * then go ahead and get the rest of it. */ UINT32 ulBytesLeftInSegment = pBufStart + m_pSegment[m_ulCurSegIndex].ulSize - pBuf; if (ulBytesLeftInSegment > 0 && ulBytesLeftInSegment < kMinimumPacketSize) { ulSize += ulBytesLeftInSegment; } /* Now we have our length */ rulLen = ulSize; } return HXR_OK;}UINT32 CGIFCodec::ComputeLZWDataSize(BYTE *pLZW){ /* Skip the minimum code size */ pLZW++; /* Run through blocks, adding up sizes */ UINT32 ulSum = 0; UINT32 ulBlockSize; do { ulBlockSize = *pLZW++; ulSum += ulBlockSize; pLZW += ulBlockSize; } while (ulBlockSize > 0); return ulSum;}HX_RESULT CGIFCodec::GetPacketBuffer(BYTE *pBuffer, UINT32 ulLen, BOOL &rbFirstInImage){ /* Check for input error conditions */ if (pBuffer == NULL || ulLen == 0) { return HXR_INVALID_PARAMETER; } /* Check state */ if (m_ulParseState != kStateParseInitialized && m_ulParseState != kStateParseInProgress) { return HXR_UNEXPECTED; } /* Is this our first time here? */ if (m_ulParseState == kStateParseInitialized) { /* Conainer header size */ Pack32(m_pSegment[0].ulSize, pBuffer); pBuffer += 4; /* Number of Images */ Pack32(m_ulNumImages, pBuffer); pBuffer += 4; /* Individual image parameters */ UINT32 i; for (i = 0; i < m_ulNumImages; i++) { /* Individual image header size */ Pack32(m_pSegment[1 + (i << 1)].ulSize, pBuffer); pBuffer += 4; /* Individual image compressed data size */ Pack32(ComputeLZWDataSize(m_pSegment[2 + (i << 1)].pMark), pBuffer); pBuffer += 4; } /* Copy container header */ memcpy(pBuffer, m_pSegment[0].pMark, m_pSegment[0].ulSize); /* Flawfinder: ignore */ pBuffer += m_pSegment[0].ulSize; /* Copy each individual image header */ for (i = 0; i < m_ulNumImages; i++) { ParseSegment *pSegment = &m_pSegment[1 + (i << 1)]; memcpy(pBuffer, pSegment->pMark, pSegment->ulSize); /* Flawfinder: ignore */ pBuffer += pSegment->ulSize; } /* Clear the flag */ rbFirstInImage = FALSE; /* Set the new state */ m_ulParseState = kStateParseInProgress; } else { /* Copy the data packet */ memcpy(pBuffer, /* Flawfinder: ignore */ m_pSegment[m_ulCurSegIndex].pMark + m_ulCurSegOffset, ulLen); /* Was this the first packet for one of the images? */ if (m_ulCurSegOffset == 0) { rbFirstInImage = TRUE; } else { rbFirstInImage = FALSE; } /* Check to see if we're done with this segment */ if (m_ulCurSegOffset + ulLen >= m_pSegment[m_ulCurSegIndex].ulSize) { m_ulCurSegIndex += 2; m_ulCurSegOffset = 0; } else { m_ulCurSegOffset += ulLen; } /* Check to see if we finished */ if (m_ulCurSegIndex >= m_ulNumSegments) { m_ulParseState = kStateParseFinished; } } return HXR_OK;}void CGIFCodec::ParseLogicalScreenDescriptor(BYTE *pBuffer, LogicalScreenDescriptor &cLSD){ /* Read Logical Screen Descriptor */ cLSD.m_ulLogicalScreenWidth = (pBuffer[1] << 8) | pBuffer[0]; cLSD.m_ulLogicalScreenHeight = (pBuffer[3] << 8) | pBuffer[2]; cLSD.m_bGlobalColorTablePresent = (pBuffer[4] & 0x80 ? TRUE : FALSE); cLSD.m_ulOriginalColorBits = ((pBuffer[4] & 0x70) >> 4) + 1; cLSD.m_bColorsSorted = (pBuffer[4] & 0x08 ? TRUE : FALSE); cLSD.m_ulColorTableBits = (pBuffer[4] & 0x07) + 1; cLSD.m_ulColorTableNumEntries = 1 << cLSD.m_ulColorTableBits; cLSD.m_ulBackgroundColorIndex = pBuffer[5]; cLSD.m_ulPixelAspectRatio = pBuffer[6]; cLSD.m_fPixelAspectRatio = (cLSD.m_ulPixelAspectRatio + 15.0F) / 64.0F;}HX_RESULT CGIFCodec::ParseContainerHeader(BYTE * &pBuffer){ /* Verify the signature */ if (pBuffer[0] != 'G' || pBuffer[1] != 'I' || pBuffer[2] != 'F') { return HXR_INVALID_OPERATION; } pBuffer += 3; /* Get the version */ if (pBuffer[0] == '8' && pBuffer[1] == '9' && pBuffer[2] == 'a') { m_bIsGIF89a = TRUE; } else if (pBuffer[0] == '8' && pBuffer[1] == '7' && pBuffer[2] == 'a') { m_bIsGIF89a = FALSE; } else { return HXR_INVALID_OPERATION; } pBuffer += 3; /* Read the Logical Screen Descriptor */ ParseLogicalScreenDescriptor(pBuffer, m_cLSD); pBuffer += 7; /* Read the colortable if present */ if (m_cLSD.m_bGlobalColorTablePresent == TRUE) { /* Allocate space for the global color table */ if (m_pucGlobalColorMap) { delete [] m_pucGlobalColorMap; m_pucGlobalColorMap = NULL; } UINT32 ulColorTableBytes = m_cLSD.m_ulColorTableNumEntries * 3; m_pucGlobalColorMap = new BYTE [ulColorTableBytes]; if (!m_pucGlobalColorMap) { return HXR_OUTOFMEMORY; } /* Copy the global color table */ memcpy(m_pucGlobalColorMap, pBuffer, ulColorTableBytes); /* Flawfinder: ignore */ /* Advance the pointer */ pBuffer += ulColorTableBytes; /* Loop through the images, setting the global color map */ UINT32 i; for (i = 0; i < m_ulNumImages; i++) { m_pImage[i].SetGlobalColorMap(m_cLSD.m_ulColorTableNumEntries, m_pucGlobalColorMap); } } // Reset the delay time sum m_ulDelayTimeSum = 0; /* Here we loop through looking for Image Descriptors or Graphic Control Extensions */ HX_RESULT retVal; UINT32 ulImageNum = 0; for (;;) { UINT32 ulMarker = *pBuffer; switch(ulMarker) { case kImageDescriptor: retVal = m_pImage[ulImageNum].InitDecompress(pBuffer, m_pImageHeaderSize[ulImageNum]); if (retVal != HXR_OK) { return retVal; } retVal = m_pImage[ulImageNum].SetCompressedBufferSize(m_pCompressedBufferSize[ulImageNum]); if (retVal != HXR_OK) { return retVal; } pBuffer += m_pImageHeaderSize[ulImageNum]; ulImageNum++; break; case kExtension: if (pBuffer[1] == kGraphicControlExtension) { retVal = m_pImage[ulImageNum].InitDecompress(pBuffer, m_pImageHeaderSize[ulImageNum]); if (retVal != HXR_OK)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -