550 lines
17 KiB
C
550 lines
17 KiB
C
/** @file
|
|
The instance of JPEG Decode Library
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2020, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include "JfifDecode.h"
|
|
#include "McuDecode.h"
|
|
|
|
EFI_JPEG_JFIF_DATA mJfifData;
|
|
EFI_JPEG_DECODER_DATA mDecoderData;
|
|
|
|
|
|
/**
|
|
Get the SOF0(Start Of Frame, Baseline sequential DCT mode) marker's data.
|
|
And initialize the relative globle parameters.
|
|
|
|
|
|
@retval EFI_JPEG_DECODE_SUCCESS Get the markers data successfully.
|
|
@retval EFI_JPEG_SOF_ERROR Not have the three components info,
|
|
The Sample precision is not 8 bits,
|
|
Does not have a image components in the frame,
|
|
The sample rate Hi, Vi is neither 1 nor 2,
|
|
The blocks number in a MCU is more than 10.
|
|
|
|
**/
|
|
EFI_JPEG_DECODER_STATUS
|
|
GetSof0Data (
|
|
IN UINT8 *ImagePtr
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
UINT8 Blocks;
|
|
//
|
|
// ImagePtr[4]: sample precision, baseline sequential just support 8 bits.
|
|
// ImagePtr[9]: number of image components in frame.
|
|
//
|
|
if (ImagePtr[4] != 8 || ImagePtr[9] == 0 || ImagePtr[9] > 3) {
|
|
return EFI_JPEG_SOF_ERROR;
|
|
}
|
|
|
|
mJfifData.Sof0Data.Height = (ImagePtr[5] << 8) + ImagePtr[6];
|
|
mJfifData.Sof0Data.Width = (ImagePtr[7] << 8) + ImagePtr[8];
|
|
mJfifData.Sof0Data.Components = ImagePtr[9];
|
|
|
|
Blocks = 0;
|
|
for (Index = 0; Index < ImagePtr[9]; Index++) {
|
|
mJfifData.Sof0Data.Samples[Index].Hi = ImagePtr[11 + Index * 3] >> 4;
|
|
mJfifData.Sof0Data.Samples[Index].Vi = ImagePtr[11 + Index * 3] & 0x0F;
|
|
mJfifData.Sof0Data.Samples[Index].Blocks =
|
|
mJfifData.Sof0Data.Samples[Index].Hi * mJfifData.Sof0Data.Samples[Index].Vi;
|
|
mJfifData.Sof0Data.Samples[Index].QuanTable = ImagePtr[11 + Index * 3 + 1];
|
|
|
|
//
|
|
// Just support 4:1:1,4:2:2, 4:2:1, 1:1:1, 2:1:1
|
|
//
|
|
if (mJfifData.Sof0Data.Samples[Index].Blocks != 1
|
|
&& mJfifData.Sof0Data.Samples[Index].Blocks != 2
|
|
&& mJfifData.Sof0Data.Samples[Index].Blocks != 4) {
|
|
return EFI_JPEG_SOF_ERROR;
|
|
}
|
|
Blocks = Blocks + mJfifData.Sof0Data.Samples[Index].Blocks;
|
|
}
|
|
//
|
|
// In a MCU, the blocks' number must not more than 10.
|
|
//
|
|
if (Blocks > 10) {
|
|
return EFI_JPEG_SOF_ERROR;
|
|
}
|
|
return EFI_JPEG_DECODE_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get the HuffmanTable data. And initialize the relative globle parameters.
|
|
|
|
@param [in] ImagePtr The pointer of the DHT (Definintion of Huffman Table) marker
|
|
|
|
@retval EFI_JPEG_DECODE_SUCCESS Get the Huffman table data successfully.
|
|
@retval EFI_JPEG_HUFFMANTABLE_ERROR The data of Huffman table is error.
|
|
|
|
**/
|
|
EFI_JPEG_DECODER_STATUS
|
|
GetHuffmanTable (
|
|
IN UINT8 *ImagePtr
|
|
)
|
|
{
|
|
UINT8 index1;
|
|
UINT8 index2;
|
|
UINT8 TableIndex;
|
|
UINT8 ValIndex;
|
|
UINT8 *CodesPtr;
|
|
UINT8 *ValPtr;
|
|
UINT8 *TablePtr;
|
|
BOOLEAN IsZero;
|
|
UINT16 HuffmanCode;
|
|
|
|
TablePtr = ImagePtr + 4;
|
|
while(TablePtr < (ImagePtr + ((UINTN)ImagePtr[2] << 8) + ImagePtr[3])) {
|
|
TableIndex = (TablePtr[0] >> 3) + (TablePtr[0] & 0x0F);
|
|
if (TableIndex > 3) {
|
|
return EFI_JPEG_HUFFMANTABLE_ERROR;
|
|
}
|
|
|
|
mJfifData.HuffTable[TableIndex].Ptr = ImagePtr;
|
|
mJfifData.HuffTable[TableIndex].Number = TablePtr[0] & 0x0F;
|
|
mJfifData.HuffTable[TableIndex].Type = TablePtr[0] >> 4;
|
|
|
|
//
|
|
//Initial the layer's ptr of the Huffman tree, CodesPtr[1] is the first Huffman tree's layer.
|
|
// then the index of the layer is just the bits' number of the layer's huffman code.
|
|
//Initial the value's ptr of Huffman tree, ValPtr[0] is the first Huffman tree's value
|
|
//
|
|
IsZero = TRUE;
|
|
ValIndex = 0;
|
|
HuffmanCode = 0;
|
|
CodesPtr = TablePtr;
|
|
ValPtr = TablePtr + 17;
|
|
for (index1 = 1; index1 < 17; index1++) {
|
|
mJfifData.HuffTable[TableIndex].Codes[index1] = CodesPtr[index1];
|
|
}
|
|
for (index1 = 1; index1 < 17; index1++) {
|
|
if (IsZero && CodesPtr[index1] == 0) {
|
|
continue;
|
|
} else if (IsZero) {
|
|
IsZero = FALSE;
|
|
}
|
|
HuffmanCode = HuffmanCode << 1;
|
|
mJfifData.HuffTable[TableIndex].MinCode[index1] = HuffmanCode;
|
|
for ( index2 = 0; index2 < CodesPtr[index1]; index2++, HuffmanCode++) {
|
|
mJfifData.HuffTable[TableIndex].HuffmanVal[ValIndex] = ValPtr[ValIndex];
|
|
ValIndex++;
|
|
}
|
|
mJfifData.HuffTable[TableIndex].MaxCode[index1] =
|
|
mJfifData.HuffTable[TableIndex].MinCode[index1] + CodesPtr[index1] - 1;
|
|
mJfifData.HuffTable[TableIndex].FirstCode[index1] = ValIndex - CodesPtr[index1];
|
|
}
|
|
TablePtr = ValPtr + ValIndex;
|
|
}
|
|
return EFI_JPEG_DECODE_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get the important marker data, and store them into the globle parameters,
|
|
which will be used in the decoding.
|
|
|
|
@param [in] ImageData
|
|
@param [in] ImageDataSize The length in byte of the JFIF image
|
|
|
|
@retval EFI_JPEG_DECODE_SUCCESS Get the markers data successfully.
|
|
@retval EFI_JPEG_INVALID_PARAMETER Not have the start marker of SOI,
|
|
@retval EFI_JPEG_SOF_ERROR The data of SOF is error,
|
|
@retval EFI_JPEG_SOS_ERROR The data of SOS is error,
|
|
@retval EFI_JPEG_QUANTIZATIONTABLE_ERROR The data of Quantization table is error,
|
|
@retval EFI_JPEG_HUFFMANTABLE_ERROR The data of Huffman table is error.
|
|
|
|
**/
|
|
EFI_JPEG_DECODER_STATUS
|
|
InitJfifData (
|
|
IN UINT8 *ImageData,
|
|
IN UINTN ImageDataSize
|
|
)
|
|
{
|
|
EFI_JPEG_DECODER_STATUS DecodeStatus;
|
|
UINT32 Index;
|
|
UINT8 DqtCount;
|
|
UINT8 *TempPtr;
|
|
UINT8 *ImagePtr;
|
|
UINT8 DqtPtrIndex;
|
|
|
|
Index = 0;
|
|
ImagePtr = ImageData;
|
|
|
|
SetMem (&mJfifData, sizeof(mJfifData), 0);
|
|
if (ImagePtr[0] != 0xFF || ImagePtr[1] != (UINT8) JPEG_SOI) {
|
|
return EFI_JPEG_INVALID_PARAMETER;
|
|
} else {
|
|
mJfifData.SoiPtr = ImagePtr;
|
|
ImagePtr += 2;
|
|
}
|
|
|
|
//
|
|
// Initialize the value of mJfifData
|
|
//
|
|
while (ImagePtr < (ImageData + ImageDataSize)) {
|
|
if (ImagePtr[0] != 0xFF ||(ImagePtr[0] == 0xFF && ImagePtr[1] == 0x00)) {
|
|
ImagePtr++;
|
|
continue;
|
|
}
|
|
//
|
|
// Check this marker is the supporting SOFn (n>0) or not
|
|
//
|
|
if (ImagePtr[1] > 0xc0 && ImagePtr[1] != 0xc4 && ImagePtr[1] <= 0xcf) {
|
|
return EFI_JPEG_SOF_ERROR;
|
|
}
|
|
|
|
switch (ImagePtr[1]) {
|
|
case JPEG_SOF0:
|
|
mJfifData.Sof0Data.Ptr = ImagePtr;
|
|
DecodeStatus = GetSof0Data (ImagePtr);
|
|
if (DecodeStatus != EFI_JPEG_DECODE_SUCCESS) {
|
|
return DecodeStatus;
|
|
}
|
|
break;
|
|
|
|
case JPEG_SOS:
|
|
mJfifData.SosPtr = ImagePtr;
|
|
//
|
|
// ImagePtr[4]: interleaving, have three component(Y,Cb,Cr) in the scan or grayscale
|
|
// ImagePtr[Index - 1]: Ss(Start of spectral or predictior selection)
|
|
// ImagePtr[Index]: Se(End of spetral selection)
|
|
// ImagePtr[Index + 1]: Ah:Al(high and low of Successive approximation bit position)
|
|
//
|
|
Index = (ImagePtr[2] << 8) + ImagePtr[3];
|
|
if ((ImagePtr[4] != 3 && ImagePtr[4] != 1)
|
|
|| ImagePtr[Index - 1] != 0
|
|
|| ImagePtr[Index] != 63
|
|
|| ImagePtr[Index + 1] != 0) {
|
|
return EFI_JPEG_SOS_ERROR;
|
|
}
|
|
//
|
|
// For the checking of the components of this scan.
|
|
// ImagePtr[4 + Index * 2]: the index of the three component
|
|
// ImagePtr[4 + Index * 2 + 1]: Td:Ta(the HuffmanTable index of DC and AC )
|
|
//
|
|
for (Index = 0; Index < ImagePtr[4]; Index++) {
|
|
if (ImagePtr[4 + Index * 2 + 1] > 3
|
|
|| (ImagePtr[4 + Index * 2 + 2] >> 4) > 1
|
|
|| (ImagePtr[4 + Index * 2 + 2] & 0x0F) > 1) {
|
|
return EFI_JPEG_SOS_ERROR;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case JPEG_DHT:
|
|
DecodeStatus = GetHuffmanTable (ImagePtr);
|
|
if (DecodeStatus != EFI_JPEG_DECODE_SUCCESS) {
|
|
return DecodeStatus;
|
|
}
|
|
break;
|
|
|
|
case JPEG_DQT:
|
|
//
|
|
// There will be several Quantization tables in one DQT segment
|
|
// About the first Quantization table in the DQT:
|
|
// ImagePtr[4]: the bits of [0:3], Pq(Quantization table element precision)
|
|
// ImagePtr[4]: the bits of [4:7], Tq(Quantization table destination identifier)
|
|
//
|
|
DqtCount = ((ImagePtr[2] << 8) + ImagePtr[3] - 2)/65;
|
|
TempPtr = ImagePtr + 4;
|
|
for (Index = 0; Index < DqtCount; Index++) {
|
|
DqtPtrIndex = TempPtr[0] & 0x0F;
|
|
if (DqtPtrIndex > 3 || (TempPtr[0] >> 4) != 0) {
|
|
return EFI_JPEG_QUANTIZATIONTABLE_ERROR;
|
|
}
|
|
mJfifData.DqtPtr[DqtPtrIndex] = TempPtr + 1;
|
|
TempPtr += 65;
|
|
}
|
|
break;
|
|
|
|
case JPEG_APP0:
|
|
mJfifData.App0Ptr = ImagePtr;
|
|
break;
|
|
|
|
case JPEG_APP1:
|
|
case JPEG_APP2:
|
|
case JPEG_APP3:
|
|
case JPEG_APP4:
|
|
case JPEG_APP5:
|
|
case JPEG_APP6:
|
|
case JPEG_APP7:
|
|
case JPEG_APP8:
|
|
case JPEG_APP9:
|
|
case JPEG_APP10:
|
|
case JPEG_APP11:
|
|
case JPEG_APP12:
|
|
case JPEG_APP13:
|
|
case JPEG_APP14:
|
|
case JPEG_APP15:
|
|
break;
|
|
|
|
case JPEG_COM:
|
|
mJfifData.ComPtr = ImagePtr;
|
|
break;
|
|
|
|
case JPEG_DRI:
|
|
mJfifData.McuRestart = (ImagePtr[4] << 8) + ImagePtr[5];
|
|
break;
|
|
|
|
case JPEG_RST0:
|
|
case JPEG_RST1:
|
|
case JPEG_RST2:
|
|
case JPEG_RST3:
|
|
case JPEG_RST4:
|
|
case JPEG_RST5:
|
|
case JPEG_RST6:
|
|
case JPEG_RST7:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
if (*(ImagePtr + 2) == 0xFF) {
|
|
ImagePtr += 2;
|
|
} else {
|
|
ImagePtr += 2 + (ImagePtr[2] << 8) + ImagePtr[3];
|
|
}
|
|
}
|
|
|
|
return EFI_JPEG_DECODE_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Using the globle parameter mJfifData to initialize the globle parameter of mDecoderData.
|
|
|
|
|
|
|
|
**/
|
|
VOID
|
|
InitDecoderData (
|
|
)
|
|
{
|
|
UINT8 Index1;
|
|
UINT8 Index2;
|
|
UINT8 Index3;
|
|
UINT8 Blocks;
|
|
|
|
//
|
|
// Initialize the value of mDecoderData
|
|
//
|
|
mDecoderData.ImagePtr =
|
|
mJfifData.SosPtr + 2 + ((UINTN)mJfifData.SosPtr[2] << 8) + mJfifData.SosPtr[3];
|
|
mDecoderData.CurByte = *(mDecoderData.ImagePtr);
|
|
mDecoderData.ImagePtr++;
|
|
mDecoderData.BitPos = 7;
|
|
|
|
//
|
|
//Initialize the blocks infomation in a MCU
|
|
//
|
|
Blocks = 0;
|
|
for (Index3 = 0; Index3 < mJfifData.Sof0Data.Components; Index3++) {
|
|
for (Index1 = 0; Index1 < mJfifData.Sof0Data.Samples[Index3].Vi; Index1++) {
|
|
for (Index2 = 0; Index2 < mJfifData.Sof0Data.Samples[Index3].Hi; Index2++) {
|
|
mDecoderData.BlocksInMcu[Blocks].DcAcHTIndex = *(mJfifData.SosPtr + 6 + Index3 * 2);
|
|
mDecoderData.BlocksInMcu[Blocks].QTIndex = mJfifData.Sof0Data.Samples[Index3].QuanTable;
|
|
mDecoderData.BlocksInMcu[Blocks].HiViIndex = (Index2 << 4) + Index1;
|
|
mDecoderData.DcVal[Index3] = 0;
|
|
mDecoderData.BlocksInMcu[Blocks].DcValPtr = &(mDecoderData.DcVal[Index3]);
|
|
Blocks++;
|
|
}
|
|
}
|
|
}
|
|
mDecoderData.Blocks = Blocks;
|
|
}
|
|
|
|
/**
|
|
Decodes a JFIF image into a UGA formatted image,
|
|
and returns the decoded image, image's width and image's height
|
|
|
|
@param [in] This Protocol instance structure
|
|
@param [in] ImageData The data of the JFIF image, which will be decoded
|
|
@param [in] ImageDataSize The size in bytes of ImageData
|
|
@param [out] DecodedData The decoded data, this output parameter contains
|
|
a newly allocated memory space, and it is the
|
|
caller's responsibility to free this memory buffer.
|
|
@param [out] DecodedDataSize The size in bytes of DecodedData
|
|
@param [out] Height The height of the image's displaying
|
|
@param [out] Width The width of the image's displaying
|
|
@param [out] DecoderStatus The status of the decoding progress, defined in
|
|
\Protocol\JpegDecoder\JpegDecoder.h.
|
|
|
|
@retval EFI_SUCCESS The JFIF image is decoded successfully.
|
|
@retval EFI_INVALID_PARAMETER Either one of ImageData, Width, Height, DecodedDataSize
|
|
and DecoderStatus is NULL, or ImageDataSize is zero.
|
|
@retval EFI_OUT_OF_RESOURCES The memory for DecodedData could not be allocated.
|
|
@retval EFI_UNSUPPORTED The JFIF image can not be decoded, and the detail error info
|
|
will be returned by the output parameter DecoderStatus.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
H2OHiiJpegDecode (
|
|
IN UINT8 *ImageData,
|
|
IN UINTN ImageDataSize,
|
|
OUT UINT8 **DecodedData,
|
|
OUT UINTN *DecodedDataSize,
|
|
OUT UINTN *Height,
|
|
OUT UINTN *Width,
|
|
OUT EFI_JPEG_DECODER_STATUS *DecoderStatus
|
|
)
|
|
{
|
|
BOOLEAN IntervalFlag;
|
|
BOOLEAN IsEnd;
|
|
UINT16 McuCount;
|
|
INT16 McuSrcBuff[10*64];
|
|
INT16 McuDstBuff[12*64];
|
|
UINT16 CurHPixel;
|
|
UINT16 CurVLine;
|
|
UINT64 BltBufferSize;
|
|
|
|
if (ImageData == NULL
|
|
|| ImageDataSize == 0
|
|
|| DecodedDataSize == NULL
|
|
|| Height == NULL
|
|
|| Width == NULL
|
|
|| DecoderStatus == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*DecoderStatus = InitJfifData (ImageData, ImageDataSize);
|
|
if (*DecoderStatus != EFI_JPEG_DECODE_SUCCESS) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
*Width = mJfifData.Sof0Data.Width;
|
|
*Height = mJfifData.Sof0Data.Height;
|
|
BltBufferSize = MultU64x32 ((UINT64) (mJfifData.Sof0Data.Width * mJfifData.Sof0Data.Height), sizeof (EFI_UGA_PIXEL));
|
|
if (BltBufferSize >= 0x100000000LL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
*DecodedDataSize = (UINTN) BltBufferSize;
|
|
*DecodedData = H2OImageDecoderLibAllocateMem (*DecodedDataSize);
|
|
if (*DecodedData == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
ZeroMem (*DecodedData, *DecodedDataSize);
|
|
CurHPixel = 0;
|
|
CurVLine = 0;
|
|
IntervalFlag = FALSE;
|
|
|
|
IsEnd = FALSE;
|
|
McuCount = 0;
|
|
InitDecoderData();
|
|
while (!IsEnd) {
|
|
SetMem(&McuDstBuff, sizeof(McuDstBuff), 0);
|
|
if (McuRetrieve((INT16 *)&McuSrcBuff, IntervalFlag, &IsEnd, DecoderStatus) != EFI_SUCCESS) {
|
|
break;
|
|
}
|
|
McuCount++;
|
|
if ((mJfifData.McuRestart)&&(McuCount % mJfifData.McuRestart==0)) {
|
|
IntervalFlag = TRUE;
|
|
} else {
|
|
IntervalFlag = FALSE;
|
|
}
|
|
McuDecode ((INT16 *)&McuSrcBuff, (INT16 *)&McuDstBuff);
|
|
StoreMcuToUgaBlt ((INT16 *)&McuDstBuff, DecodedData, &CurHPixel, &CurVLine);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get a special Marker info of the JFIF image
|
|
|
|
@param [in] Start The start of the JFIF image,
|
|
or the output Next parameter from a previous call.
|
|
@param [in] End The end of the JFIF image.
|
|
@param [in, out] MarkerType The type of the marker in the JFIF image
|
|
@param [out] MarkerData The pointer of the marker specified by the special MarkerType in the JFIF image.
|
|
@param [out] DataSize The size in bytes of MarkerData (with the marker bytes and length bytes).
|
|
@param [out] Next The next pointer following the "MarkerType" marker,
|
|
it is next marker pointer, or the compressed data pointer after SOS marker.
|
|
|
|
@retval EFI_SUCCESS The marker's information is retrieved sucessfully.
|
|
@retval EFI_INVALID_PARAMETER Either one of Start, End and DataSize is NULL,
|
|
or End is less than Start.
|
|
@retval EFI_NOT_FOUND The marker can not be found in the JFIF image.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
H2OHiiJpegDecoderGetMarkerData (
|
|
IN UINT8 *Start,
|
|
IN UINT8 *End,
|
|
IN OUT EFI_JPEG_MARKER_TYPE *MarkerType,
|
|
OUT UINT8 **MarkerData,
|
|
OUT UINT32 *DataSize,
|
|
OUT UINT8 **Next OPTIONAL
|
|
)
|
|
{
|
|
UINT8 *ImagePtr;
|
|
UINT16 i;
|
|
|
|
i = 0;
|
|
ImagePtr = Start;
|
|
if (Start == NULL
|
|
|| End == NULL
|
|
|| End < Start
|
|
|| DataSize == NULL) {
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
while (ImagePtr < End) {
|
|
//
|
|
// The ImagePtr is not a Marker's pointer
|
|
//
|
|
if (*ImagePtr != 0xFF || (*ImagePtr == 0xFF && *(ImagePtr + 1) == 0x00)) {
|
|
ImagePtr++;
|
|
continue;
|
|
}
|
|
|
|
if (*(ImagePtr + 2) == 0xFF) {
|
|
//
|
|
// The ImagePtr is a marker's pointer, and this marker does not have data info
|
|
//
|
|
*DataSize = 2;
|
|
} else {
|
|
*DataSize = (*(ImagePtr + 2) << 8) + *(ImagePtr + 3) + 2;
|
|
}
|
|
if (*MarkerType == JPEG_ANY) {
|
|
//
|
|
//Find the first marker following the Start pointer which has data info.
|
|
//
|
|
*MarkerType = *(ImagePtr + 1);
|
|
*MarkerData = ImagePtr;
|
|
if (Next != NULL) {
|
|
*Next = ImagePtr + *DataSize;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
} else if ( *(ImagePtr + 1) == *MarkerType) {
|
|
//
|
|
// The ImagePtr is a marker's pointer, and this marker have info
|
|
//
|
|
*MarkerData = ImagePtr;
|
|
if (Next != NULL) {
|
|
*Next = ImagePtr + *DataSize;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
ImagePtr += *DataSize;
|
|
}
|
|
}
|
|
*MarkerData = NULL;
|
|
*DataSize = 0;
|
|
if (Next != NULL) {
|
|
*Next = NULL;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|