JD2022-TU1/main/extern/mkclean/custom/libebml2/ebmlelement.c

351 lines
No EOL
11 KiB
C

/*
* $Id: ebmlelement.c 642 2010-11-28 08:38:47Z robux4 $
* Copyright (c) 2008-2010, Matroska (non-profit organisation)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Matroska assocation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY the Matroska association ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL The Matroska Foundation BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ebml/ebml.h"
#include "ebml/ebml_internal.h"
static bool_t ValidateSize(const ebml_element *p)
{
return 1;
}
static void PostCreate(ebml_element *Element, bool_t SetDefault)
{
Element->DefaultSize = -1;
Element->ElementPosition = INVALID_FILEPOS_T;
Element->SizePosition = INVALID_FILEPOS_T;
}
static bool_t NeedsDataSizeUpdate(ebml_element *Element, bool_t bWithDefault)
{
if (!Element->bNeedDataSizeUpdate)
return 0;
if (!bWithDefault && EBML_ElementIsDefaultValue(Element))
return 0;
return 1;
}
static filepos_t UpdateDataSize(ebml_element *Element, bool_t bWithDefault, bool_t bForceWithoutMandatory)
{
if (!bWithDefault && EBML_ElementIsDefaultValue(Element))
return 0;
if (Element->DefaultSize > Element->DataSize)
Element->DataSize = Element->DefaultSize;
Element->bNeedDataSizeUpdate = 0;
#if !defined(NDEBUG)
assert(!EBML_ElementNeedsDataSizeUpdate(Element, bWithDefault));
#endif
return Element->DataSize;
}
static err_t Create(ebml_element *Element)
{
Element->DataSize = INVALID_FILEPOS_T;
Element->bNeedDataSizeUpdate = 1;
return ERR_NONE;
}
META_START(EBMLElement_Class,EBML_ELEMENT_CLASS)
META_CLASS(SIZE,sizeof(ebml_element))
META_CLASS(VMT_SIZE,sizeof(ebml_element_vmt))
META_CLASS(FLAGS,CFLAG_ABSTRACT)
META_CLASS(CREATE,Create)
META_VMT(TYPE_FUNC,ebml_element_vmt,PostCreate,PostCreate)
META_VMT(TYPE_FUNC,ebml_element_vmt,ValidateSize,ValidateSize)
META_VMT(TYPE_FUNC,ebml_element_vmt,UpdateDataSize,UpdateDataSize)
META_VMT(TYPE_FUNC,ebml_element_vmt,NeedsDataSizeUpdate,NeedsDataSizeUpdate)
META_PARAM(TYPE,EBML_ELEMENT_INFINITESIZE,TYPE_BOOLEAN)
META_DYNAMIC(TYPE_BOOLEAN,EBML_ELEMENT_INFINITESIZE)
META_PARAM(TYPE,EBML_ELEMENT_OBJECT,TYPE_PTR)
META_DYNAMIC(TYPE_PTR,EBML_ELEMENT_OBJECT)
META_END_CONTINUE(NODETREE_CLASS)
META_START_CONTINUE(EBML_DUMMY_ID)
META_CLASS(SIZE,sizeof(ebml_dummy))
META_END(EBML_BINARY_CLASS)
bool_t EBML_ElementIsFiniteSize(const ebml_element *Element)
{
return (Node_GetData((const node*)Element,EBML_ELEMENT_INFINITESIZE,TYPE_BOOLEAN) == 0);
}
void EBML_ElementSetInfiniteSize(const ebml_element *Element, bool_t Set)
{
bool_t b = Set;
Node_SetData((node*)Element,EBML_ELEMENT_INFINITESIZE,TYPE_BOOLEAN,&b);
}
bool_t EBML_ElementIsDummy(const ebml_element *Element)
{
return Node_IsPartOf(Element,EBML_DUMMY_ID);
}
ebml_element *EBML_ElementSkipData(ebml_element *p, stream *Input, const ebml_parser_context *Context, ebml_element *TestReadElt, bool_t AllowDummyElt)
{
ebml_element *Result = NULL;
if (EBML_ElementIsFiniteSize(p)) {
assert(TestReadElt == NULL);
assert(p->ElementPosition < p->SizePosition);
Stream_Seek(Input, EBML_ElementPositionEnd(p), SEEK_SET);
} else {
// read elements until an upper element is found
int bUpperElement = 0; // trick to call FindNextID correctly
Result = EBML_FindNextElement(Input, Context, &bUpperElement, AllowDummyElt);
if (Result != NULL)
Stream_Seek(Input, EBML_ElementPositionData(Result), SEEK_SET);
}
return Result;
}
const ebml_context *EBML_ElementContext(const ebml_element *Element)
{
return Element->Context;
}
filepos_t EBML_ElementFullSize(const ebml_element *Element, bool_t bWithDefault)
{
if (!bWithDefault && EBML_ElementIsDefaultValue(Element))
return INVALID_FILEPOS_T; // won't be saved
return Element->DataSize + GetIdLength(Element->Context->Id) + EBML_CodedSizeLength(Element->DataSize, Element->SizeLength, EBML_ElementIsFiniteSize(Element));
}
filepos_t EBML_ElementDataSize(const ebml_element *Element, bool_t bWithDefault)
{
return Element->DataSize;
}
void EBML_ElementForceDataSize(ebml_element *Element, filepos_t Size)
{
Element->DataSize = Size;
}
uint8_t EBML_ElementSizeLength(const ebml_element *Element)
{
return Element->SizeLength;
}
void EBML_ElementSetSizeLength(ebml_element *Element, uint8_t SizeLength)
{
Element->SizeLength = SizeLength;
}
bool_t EBML_ElementIsType(const ebml_element *Element, const ebml_context *Context)
{
return Element->Context->Id == Context->Id;
}
fourcc_t EBML_ElementClassID(const ebml_element *Element)
{
return Element->Context->Id;
}
filepos_t EBML_ElementPosition(const ebml_element *Element)
{
return Element->ElementPosition;
}
void EBML_ElementForcePosition(ebml_element *Element, filepos_t Pos)
{
Element->ElementPosition = Pos;
}
filepos_t EBML_ElementPositionData(const ebml_element *Element)
{
if (!EBML_ElementIsFiniteSize(Element))
{
if (!Element->SizeLength)
return INVALID_FILEPOS_T;
return Element->SizePosition + Element->SizeLength;
}
else
return Element->SizePosition + EBML_CodedSizeLength(Element->DataSize,Element->SizeLength,1);
}
filepos_t EBML_ElementPositionEnd(const ebml_element *Element)
{
if (!EBML_ElementIsFiniteSize(Element))
return INVALID_FILEPOS_T; // the end position is unknown
else
return Element->SizePosition + EBML_CodedSizeLength(Element->DataSize,Element->SizeLength,1) + Element->DataSize;
}
bool_t EBML_ElementInfiniteForceSize(ebml_element *Element, filepos_t NewSize)
{
int OldSizeLen;
filepos_t OldSize;
assert(!EBML_ElementIsFiniteSize(Element));
if (EBML_ElementIsFiniteSize(Element))
return 0;
OldSizeLen = EBML_CodedSizeLength(Element->DataSize, Element->SizeLength, EBML_ElementIsFiniteSize(Element));
OldSize = Element->DataSize;
Element->DataSize = NewSize;
if (EBML_CodedSizeLength(Element->DataSize, Element->SizeLength, EBML_ElementIsFiniteSize(Element)) == OldSizeLen)
{
EBML_ElementSetInfiniteSize(Element,1);
return 1;
}
Element->DataSize = OldSize;
return 0;
}
size_t GetIdLength(fourcc_t Id)
{
if ((Id & 0xFFFFFF00)==0)
return 1;
if ((Id & 0xFFFF0000)==0)
return 2;
if ((Id & 0xFF000000)==0)
return 3;
return 4;
}
size_t EBML_FillBufferID(uint8_t *Buffer, size_t BufSize, fourcc_t Id)
{
size_t i,FinalHeadSize = GetIdLength(Id);
if (BufSize < FinalHeadSize)
return 0;
for (i=0;i<FinalHeadSize;++i)
Buffer[FinalHeadSize-i-1] = (uint8_t)(Id >> (i<<3));
return FinalHeadSize;
}
size_t EBML_IdToString(tchar_t *Out, size_t OutLen, fourcc_t Id)
{
size_t i,FinalHeadSize = GetIdLength(Id);
if (OutLen < FinalHeadSize*4+1)
return 0;
Out[0] = 0;
for (i=0;i<4;++i)
{
if (Out[0] || (Id >> 8*(3-i)) & 0xFF)
stcatprintf_s(Out,OutLen,T("[%02X]"),(Id >> 8*(3-i)) & 0xFF);
}
return FinalHeadSize*4;
}
fourcc_t EBML_BufferToID(const uint8_t *Buffer)
{
if (Buffer[0] & 0x80)
return (fourcc_t)Buffer[0];
if (Buffer[0] & 0x40)
return (fourcc_t)((Buffer[0] << 8) + Buffer[1]);
if (Buffer[0] & 0x20)
return (fourcc_t)((Buffer[0] << 16) + (Buffer[1] << 8) + Buffer[2]);
if (Buffer[0] & 0x10)
return (fourcc_t)((Buffer[0] << 24) + (Buffer[1] << 16) + (Buffer[2] << 8) + Buffer[3]);
return 0;
}
#if defined(CONFIG_EBML_WRITING)
err_t EBML_ElementRender(ebml_element *Element, stream *Output, bool_t bWithDefault, bool_t bKeepPosition, bool_t bForceWithoutMandatory, filepos_t *Rendered)
{
err_t Result;
filepos_t _Rendered,WrittenSize;
#if !defined(NDEBUG)
filepos_t SupposedSize;
#endif
if (!Rendered)
Rendered = &_Rendered;
*Rendered = 0;
assert(Element->bValueIsSet || (bWithDefault && EBML_ElementIsDefaultValue(Element))); // an element is been rendered without a value set !!!
// it may be a mandatory element without a default value
if (!(Element->bValueIsSet || (bWithDefault && EBML_ElementIsDefaultValue(Element))))
return ERR_INVALID_DATA;
if (!bWithDefault && EBML_ElementIsDefaultValue(Element))
return ERR_INVALID_DATA;
#if !defined(NDEBUG)
if (EBML_ElementNeedsDataSizeUpdate(Element, bWithDefault))
SupposedSize = EBML_ElementUpdateSize(Element, bWithDefault, bForceWithoutMandatory);
else
SupposedSize = Element->DataSize;
#else
if (EBML_ElementNeedsDataSizeUpdate(Element, bWithDefault))
EBML_ElementUpdateSize(Element, bWithDefault, bForceWithoutMandatory);
#endif
Result = EBML_ElementRenderHead(Element, Output, bKeepPosition, &WrittenSize);
*Rendered += WrittenSize;
if (Result != ERR_NONE)
return Result;
Result = EBML_ElementRenderData(Element, Output, bForceWithoutMandatory, bWithDefault, &WrittenSize);
#if !defined(NDEBUG)
if (SupposedSize != INVALID_FILEPOS_T) assert(WrittenSize == SupposedSize);
#endif
*Rendered += WrittenSize;
return Result;
}
err_t EBML_ElementRenderHead(ebml_element *Element, stream *Output, bool_t bKeepPosition, filepos_t *Rendered)
{
err_t Err;
uint8_t FinalHead[4+8]; // Class D + 64 bits coded size
size_t i,FinalHeadSize;
int CodedSize;
filepos_t PosAfter,PosBefore = Stream_Seek(Output,0,SEEK_CUR);
FinalHeadSize = EBML_FillBufferID(FinalHead,sizeof(FinalHead),Element->Context->Id);
CodedSize = EBML_CodedSizeLength(Element->DataSize, Element->SizeLength, EBML_ElementIsFiniteSize(Element));
EBML_CodedValueLength(Element->DataSize, CodedSize, &FinalHead[FinalHeadSize], EBML_ElementIsFiniteSize(Element));
FinalHeadSize += CodedSize;
Err = Stream_Write(Output, FinalHead, FinalHeadSize, &i);
PosAfter = Stream_Seek(Output,0,SEEK_CUR);
if (!bKeepPosition) {
Element->ElementPosition = PosAfter - FinalHeadSize;
Element->SizePosition = Element->ElementPosition + GetIdLength(Element->Context->Id);
}
if (Rendered)
*Rendered = PosAfter - PosBefore;
return Err;
}
#endif
void EBML_ElementGetName(const ebml_element *Element, tchar_t *Out, size_t OutLen)
{
Node_FromStr(Element,Out,OutLen,Element->Context->ElementName);
}
const char *EBML_ElementGetClassName(const ebml_element *Element)
{
return Element->Context->ElementName;
}