2019-09-03 11:58:42 +02:00
/*
* Copyright ( c ) 2000 Apple Computer , Inc . All rights reserved .
*
* @ APPLE_LICENSE_HEADER_START @
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 ( the
* " License " ) . You may not use this file except in compliance with the
* License . Please obtain a copy of the License at
* http : //www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an " AS IS " basis , WITHOUT WARRANTY OF ANY KIND , EITHER
* EXPRESS OR IMPLIED , AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES ,
* INCLUDING WITHOUT LIMITATION , ANY WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE OR NON - INFRINGEMENT . Please see the
* License for the specific language governing rights and limitations
* under the License .
*
* @ APPLE_LICENSE_HEADER_END @
*/
/*
* plist . c - plist parsing functions
*
* Copyright ( c ) 2000 - 2005 Apple Computer , Inc .
*
* DRI : Josh de Cesare
* code split out from drivers . c by Soren Spies , 2005
*/
//Slice - rewrite for UEFI with more functions like Copyright (c) 2003 Apple Computer
2020-08-17 21:40:52 +02:00
# include <Platform.h> // Only use angled for Platform, else, xcode project won't compile
2020-04-16 09:15:26 +02:00
# include "b64cdecode.h"
2020-04-22 19:52:21 +02:00
# include "plist.h"
# include "../libeg/FloatLib.h"
2019-09-03 11:58:42 +02:00
# ifndef DEBUG_ALL
2020-08-22 15:39:24 +02:00
# define DEBUG_PLIST 1
2019-09-03 11:58:42 +02:00
# else
# define DEBUG_PLIST DEBUG_ALL
# endif
# if DEBUG_PLIST == 0
# define DBG(...)
# else
# define DBG(...) DebugLog(DEBUG_PLIST, __VA_ARGS__)
# endif
2020-08-18 18:45:44 +02:00
2019-09-03 11:58:42 +02:00
2020-04-16 11:09:22 +02:00
2019-09-03 11:58:42 +02:00
CHAR8 * buffer_start = NULL ;
// Forward declarations
2020-08-19 14:50:26 +02:00
EFI_STATUS ParseTagDict ( CHAR8 * buffer , TagStruct * * tag , UINT32 empty , UINT32 * lenPtr ) ;
EFI_STATUS ParseTagArray ( CHAR8 * buffer , TagStruct * * tag , UINT32 empty , UINT32 * lenPtr ) ;
EFI_STATUS ParseTagKey ( char * buffer , TagStruct * * tag , UINT32 * lenPtr ) ;
EFI_STATUS ParseTagString ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr ) ;
EFI_STATUS ParseTagInteger ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr ) ;
EFI_STATUS ParseTagFloat ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr ) ;
EFI_STATUS ParseTagData ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr ) ;
EFI_STATUS ParseTagDate ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr ) ;
EFI_STATUS ParseTagBoolean ( CHAR8 * buffer , TagStruct * * tag , bool value , UINT32 * lenPtr ) ;
EFI_STATUS XMLParseNextTag ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr ) ;
2020-02-17 21:41:09 +01:00
EFI_STATUS FixDataMatchingTag ( CHAR8 * buffer , CONST CHAR8 * tag , UINT32 * lenPtr ) ;
2019-09-03 11:58:42 +02:00
/* Function for basic XML character entities parsing */
2020-08-22 15:39:24 +02:00
class XMLEntity
{
public :
const XString8 name ;
size_t nameLen ;
2019-09-03 11:58:42 +02:00
CHAR8 value ;
2020-08-22 15:39:24 +02:00
XMLEntity ( ) : name ( ) , nameLen ( 0 ) , value ( 0 ) { }
XMLEntity ( const XString8 & _name , CHAR8 _value ) : name ( _name ) , nameLen ( name . length ( ) ) , value ( _value ) { }
// Not sure if default are valid. Delete them. If needed, proper ones can be created
XMLEntity ( const XMLEntity & ) = delete ;
XMLEntity & operator = ( const XMLEntity & ) = delete ;
} ;
const XMLEntity ents [ ] = {
{ " quot; " _XS8 , ' " ' } ,
{ " apos; " _XS8 , ' \' ' } ,
{ " lt; " _XS8 , ' < ' } ,
{ " gt; " _XS8 , ' > ' } ,
{ " amp; " _XS8 , ' & ' }
2019-09-03 11:58:42 +02:00
} ;
2020-08-15 15:47:56 +02:00
/* Replace XML entities by their value */
2019-09-03 11:58:42 +02:00
CHAR8 *
XMLDecode ( CHAR8 * src )
{
UINTN len ;
CONST CHAR8 * s ;
CHAR8 * out , * o ;
if ( ! src ) {
return 0 ;
}
len = AsciiStrLen ( src ) ;
#if 0
2020-08-15 15:47:56 +02:00
out = ( __typeof__ ( out ) ) AllocateZeroPool ( len + 1 ) ;
2019-09-03 11:58:42 +02:00
if ( ! out )
return 0 ;
# else // unsafe
// out is always <= src, let's overwrite src
out = src ;
# endif
o = out ;
s = src ;
while ( s < = src + len ) /* Make sure the terminator is also copied */
{
2020-04-22 19:52:21 +02:00
if ( * s = = ' & ' ) {
2019-09-03 11:58:42 +02:00
BOOLEAN entFound = FALSE ;
UINTN i ;
s + + ;
2020-04-22 19:52:21 +02:00
for ( i = 0 ; i < sizeof ( ents ) / sizeof ( ents [ 0 ] ) ; i + + ) {
2020-08-22 15:39:24 +02:00
if ( ents [ i ] . name . strncmp ( s , ents [ i ] . nameLen ) = = 0 ) {
2019-09-03 11:58:42 +02:00
entFound = TRUE ;
break ;
}
}
2020-04-22 19:52:21 +02:00
if ( entFound ) {
2019-09-03 11:58:42 +02:00
* o + + = ents [ i ] . value ;
s + = ents [ i ] . nameLen ;
continue ;
}
}
* o + + = * s + + ;
}
return out ;
}
2020-08-22 15:39:24 +02:00
/**************************************** TagStruct ****************************************/
XObjArray < TagStruct > gTagsFree ;
//UINTN newtagcount = 0;
//UINTN tagcachehit = 0;
TagStruct * TagStruct : : getEmptyTag ( )
2019-09-03 11:58:42 +02:00
{
2020-08-22 15:39:24 +02:00
TagStruct * tag ;
2019-09-03 11:58:42 +02:00
2020-08-22 15:39:24 +02:00
if ( gTagsFree . size ( ) > 0 ) {
tag = & gTagsFree [ 0 ] ;
gTagsFree . RemoveWithoutFreeingAtIndex ( 0 ) ;
//tagcachehit++;
//DBG("tagcachehit=%lld\n", tagcachehit);
return tag ;
}
tag = new TagStruct ( ) ;
//newtagcount += 1;
//DBG("newtagcount=%lld\n", newtagcount);
return tag ;
}
TagStruct * TagStruct : : getEmptyDictTag ( )
{
TagStruct * newDictTag = getEmptyTag ( ) ;
newDictTag - > type = kTagTypeDict ;
return newDictTag ;
}
TagStruct * TagStruct : : getEmptyArrayTag ( )
{
TagStruct * newArrayTag = getEmptyTag ( ) ;
newArrayTag - > type = kTagTypeArray ;
return newArrayTag ;
}
void TagStruct : : FreeTag ( )
{
// Clear and free the tag.
type = kTagTypeNone ;
_string . setEmpty ( ) ;
_intValue = 0 ;
_floatValue = 0 ;
if ( _data ) {
FreePool ( _data ) ;
_data = NULL ;
}
_dataLen = 0 ;
//while ( tagIdx < _dictOrArrayContent.notEmpty() ) {
// _dictOrArrayContent[0].FreeTag();
// _dictOrArrayContent.RemoveWithoutFreeingAtIndex(0);
//}
// this loop is better because removing objects from the end don't do any memory copying.
for ( size_t tagIdx = _dictOrArrayContent . size ( ) ; tagIdx > 0 ; ) {
tagIdx - - ;
_dictOrArrayContent [ tagIdx ] . FreeTag ( ) ;
_dictOrArrayContent . RemoveWithoutFreeingAtIndex ( tagIdx ) ;
}
gTagsFree . AddReference ( this , false ) ;
}
INTN TagStruct : : dictKeyCount ( ) const
{
if ( ! isDict ( ) ) panic ( " TagStruct::dictKeyCount() : !isDict() " ) ;
INTN count = 0 ;
for ( size_t tagIdx = 0 ; tagIdx + 1 < _dictOrArrayContent . size ( ) ; tagIdx + + ) { // tagIdx + 1 because a key as a last element cannot have value and is ignored. Can't do size()-1, because it's unsigned.
if ( _dictOrArrayContent [ tagIdx ] . isKey ( ) & & ! _dictOrArrayContent [ tagIdx + 1 ] . isKey ( ) ) { // if this key is followed by another key, it'll be ignored
count + + ;
2019-09-03 11:58:42 +02:00
}
}
2020-08-22 15:39:24 +02:00
return count ;
2019-09-03 11:58:42 +02:00
}
2020-08-22 15:39:24 +02:00
EFI_STATUS TagStruct : : dictKeyAndValueAtIndex ( INTN id , const TagStruct * * key , const TagStruct * * value ) const
2019-09-03 11:58:42 +02:00
{
INTN element = 0 ;
2020-08-22 15:39:24 +02:00
* key = NULL ;
* value = NULL ;
2019-09-03 11:58:42 +02:00
2020-08-19 14:50:26 +02:00
if ( id < 0 ) return EFI_UNSUPPORTED ;
2019-09-03 11:58:42 +02:00
2020-08-22 15:39:24 +02:00
const XObjArray < TagStruct > & tagList = _dictOrArrayContent ;
size_t tagIdx ;
for ( tagIdx = 0 ; tagIdx + 1 < tagList . size ( ) ; tagIdx + + ) { // tagIdx + 1 because a key as a last element cannot have value and is ignored. Can't do size()-1, because it's unsigned.
if ( tagList [ tagIdx ] . isKey ( ) & & ! tagList [ tagIdx + 1 ] . isKey ( ) ) {
if ( element = = id ) {
* key = & tagList [ tagIdx ] ;
* value = & tagList [ tagIdx + 1 ] ;
return EFI_SUCCESS ;
2020-08-19 14:50:26 +02:00
}
2020-08-22 15:39:24 +02:00
element + + ;
2020-08-19 14:50:26 +02:00
}
}
return EFI_UNSUPPORTED ;
2019-09-03 11:58:42 +02:00
}
2020-08-22 15:39:24 +02:00
const TagStruct * TagStruct : : dictPropertyForKey ( const CHAR8 * key ) const
{
const XObjArray < TagStruct > & tagList = _dictOrArrayContent ;
for ( size_t tagIdx = 0 ; tagIdx < tagList . size ( ) ; tagIdx + + )
{
if ( tagList [ tagIdx ] . isKey ( ) & & tagList [ tagIdx ] . keyStringValue ( ) . equalIC ( key ) ) {
if ( tagIdx + 1 > = tagList . size ( ) ) return NULL ;
if ( tagList [ tagIdx + 1 ] . isKey ( ) ) return NULL ;
return & tagList [ tagIdx + 1 ] ;
}
}
return NULL ;
}
//TagStruct* GetNextProperty(TagStruct* dict)
//{
// TagStruct* tagList, tag;
//
// if (dict->isDict()) {
// return NULL;
// }
//
// tag = NULL;
// tagList = dict->tag;
// while (tagList)
// {
// tag = tagList;
// tagList = tag->tagNext;
//
// if ( !tag->isKey() || tag->keyValue().isEmpty() ) {
// continue;
//
// }
// return tag->tag;
// }
//
// return NULL;
//}
/**************************************** XML ****************************************/
2019-09-03 11:58:42 +02:00
// Expects to see one dictionary in the XML file, the final pos will be returned
// If the pos is not equal to the strlen, then there are multiple dicts
// Puts the first dictionary it finds in the
// tag pointer and returns the end of the dic, or returns -1 if not found.
//
2020-08-19 14:50:26 +02:00
EFI_STATUS ParseXML ( const CHAR8 * buffer , TagStruct * * dict , UINT32 bufSize )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status ;
UINT32 length = 0 ;
UINT32 pos = 0 ;
2020-08-19 14:50:26 +02:00
TagStruct * tag = NULL ;
2019-09-03 11:58:42 +02:00
CHAR8 * configBuffer = NULL ;
UINT32 bufferSize = 0 ;
UINTN i ;
if ( bufSize ) {
bufferSize = bufSize ;
} else {
bufferSize = ( UINT32 ) AsciiStrLen ( buffer ) ;
}
if ( dict = = NULL ) {
return EFI_INVALID_PARAMETER ;
}
2020-08-15 15:47:56 +02:00
configBuffer = ( __typeof__ ( configBuffer ) ) AllocateZeroPool ( bufferSize + 1 ) ;
2019-09-03 11:58:42 +02:00
if ( configBuffer = = NULL ) {
return EFI_OUT_OF_RESOURCES ;
}
CopyMem ( configBuffer , buffer , bufferSize ) ;
for ( i = 0 ; i < bufferSize ; i + + ) {
if ( configBuffer [ i ] = = 0 ) {
configBuffer [ i ] = 0x20 ; //replace random zero bytes to spaces
}
}
buffer_start = configBuffer ;
while ( TRUE )
{
Status = XMLParseNextTag ( configBuffer + pos , & tag , & length ) ;
if ( EFI_ERROR ( Status ) ) {
DBG ( " error parsing next tag \n " ) ;
break ;
}
pos + = length ;
if ( tag = = NULL ) {
continue ;
}
2020-08-18 18:45:44 +02:00
if ( tag - > isDict ( ) ) {
2019-09-03 11:58:42 +02:00
break ;
}
2020-08-22 15:39:24 +02:00
tag - > FreeTag ( ) ;
tag = NULL ;
2019-09-03 11:58:42 +02:00
}
// FreePool(configBuffer);
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
* dict = tag ;
return EFI_SUCCESS ;
}
//
// xml
//
# define DOFREE 1
//==========================================================================
// ParseNextTag
2020-08-19 14:50:26 +02:00
EFI_STATUS XMLParseNextTag ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status ;
UINT32 length = 0 ;
UINT32 pos = 0 ;
CHAR8 * tagName = NULL ;
* lenPtr = 0 ;
Status = GetNextTag ( ( UINT8 * ) buffer , & tagName , 0 , & length ) ;
if ( EFI_ERROR ( Status ) ) {
2020-03-25 19:32:44 +01:00
DBG ( " NextTag error %s \n " , strerror ( Status ) ) ;
2019-09-03 11:58:42 +02:00
return Status ;
}
pos = length ;
2020-05-16 21:30:29 +02:00
if ( ! strncmp ( tagName , kXMLTagPList , 6 ) ) {
2019-09-03 11:58:42 +02:00
length = 0 ;
Status = EFI_SUCCESS ;
}
/***** dict ****/
else if ( ! AsciiStrCmp ( tagName , kXMLTagDict ) )
{
DBG ( " begin dict len=%d \n " , length ) ;
2020-08-18 18:45:44 +02:00
Status = ParseTagDict ( buffer + pos , tag , 0 , & length ) ;
2019-09-03 11:58:42 +02:00
}
else if ( ! AsciiStrCmp ( tagName , kXMLTagDict " / " ) )
{
DBG ( " end dict len=%d \n " , length ) ;
2020-08-18 18:45:44 +02:00
Status = ParseTagDict ( buffer + pos , tag , 1 , & length ) ;
2019-09-03 11:58:42 +02:00
}
2020-05-16 21:30:29 +02:00
else if ( ! strncmp ( tagName , kXMLTagDict " " , 5 ) )
2019-09-03 11:58:42 +02:00
{
DBG ( " space dict len=%d \n " , length ) ;
2020-08-18 18:45:44 +02:00
Status = ParseTagDict ( buffer + pos , tag , 0 , & length ) ;
2019-09-03 11:58:42 +02:00
}
/***** key ****/
else if ( ! AsciiStrCmp ( tagName , kXMLTagKey ) )
{
DBG ( " parse key \n " ) ;
Status = ParseTagKey ( buffer + pos , tag , & length ) ;
}
/***** string ****/
else if ( ! AsciiStrCmp ( tagName , kXMLTagString ) )
{
DBG ( " parse String \n " ) ;
Status = ParseTagString ( buffer + pos , tag , & length ) ;
}
/***** string ****/
2020-05-16 21:30:29 +02:00
else if ( ! strncmp ( tagName , kXMLTagString " " , 7 ) )
2019-09-03 11:58:42 +02:00
{
DBG ( " parse String len=%d \n " , length ) ;
Status = ParseTagString ( buffer + pos , tag , & length ) ;
}
/***** integer ****/
else if ( ! AsciiStrCmp ( tagName , kXMLTagInteger ) )
{
Status = ParseTagInteger ( buffer + pos , tag , & length ) ;
}
2020-05-16 21:30:29 +02:00
else if ( ! strncmp ( tagName , kXMLTagInteger " " , 8 ) )
2019-09-03 11:58:42 +02:00
{
Status = ParseTagInteger ( buffer + pos , tag , & length ) ;
}
2020-04-22 19:52:21 +02:00
/***** float ****/
else if ( ! AsciiStrCmp ( tagName , kXMLTagFloat ) )
{
Status = ParseTagFloat ( buffer + pos , tag , & length ) ;
}
2020-05-16 21:30:29 +02:00
else if ( ! strncmp ( tagName , kXMLTagFloat " " , 8 ) )
2020-04-22 19:52:21 +02:00
{
Status = ParseTagFloat ( buffer + pos , tag , & length ) ;
}
2019-09-03 11:58:42 +02:00
/***** data ****/
else if ( ! AsciiStrCmp ( tagName , kXMLTagData ) )
{
Status = ParseTagData ( buffer + pos , tag , & length ) ;
}
2020-05-16 21:30:29 +02:00
else if ( ! strncmp ( tagName , kXMLTagData " " , 5 ) )
2019-09-03 11:58:42 +02:00
{
Status = ParseTagData ( buffer + pos , tag , & length ) ;
}
/***** date ****/
else if ( ! AsciiStrCmp ( tagName , kXMLTagDate ) )
{
Status = ParseTagDate ( buffer + pos , tag , & length ) ;
}
/***** FALSE ****/
else if ( ! AsciiStrCmp ( tagName , kXMLTagFalse ) )
{
2020-08-18 18:45:44 +02:00
Status = ParseTagBoolean ( buffer + pos , tag , false , & length ) ;
2019-09-03 11:58:42 +02:00
}
/***** TRUE ****/
else if ( ! AsciiStrCmp ( tagName , kXMLTagTrue ) )
{
2020-08-18 18:45:44 +02:00
Status = ParseTagBoolean ( buffer + pos , tag , true , & length ) ;
2019-09-03 11:58:42 +02:00
}
/***** array ****/
else if ( ! AsciiStrCmp ( tagName , kXMLTagArray ) )
{
2020-08-18 18:45:44 +02:00
Status = ParseTagArray ( buffer + pos , tag , 0 , & length ) ;
2019-09-03 11:58:42 +02:00
}
2020-05-16 21:30:29 +02:00
else if ( ! strncmp ( tagName , kXMLTagArray " " , 6 ) )
2019-09-03 11:58:42 +02:00
{
DBG ( " begin array len=%d \n " , length ) ;
2020-08-18 18:45:44 +02:00
Status = ParseTagArray ( buffer + pos , tag , 0 , & length ) ;
2019-09-03 11:58:42 +02:00
}
else if ( ! AsciiStrCmp ( tagName , kXMLTagArray " / " ) )
{
DBG ( " end array len=%d \n " , length ) ;
2020-08-18 18:45:44 +02:00
Status = ParseTagArray ( buffer + pos , tag , 1 , & length ) ;
2019-09-03 11:58:42 +02:00
}
/***** unknown ****/
else
{
* tag = NULL ;
length = 0 ;
}
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
2020-02-17 21:41:09 +01:00
// TODO jief : seems to me that length cannot be -1. Added the cast anyway to avoid regression. If confirmed, the next 3 lines must be removed.
if ( length = = ( UINT32 ) - 1 ) {
2019-09-03 11:58:42 +02:00
DBG ( " (length == -1) \n " ) ;
return EFI_UNSUPPORTED ;
}
* lenPtr = pos + length ;
DBG ( " len after success parse next tag %d \n " , * lenPtr ) ;
return EFI_SUCCESS ;
}
//==========================================================================
// ParseTagList
2020-08-19 14:50:26 +02:00
EFI_STATUS __ParseTagList ( bool isArray , CHAR8 * buffer , TagStruct * * tag , UINT32 empty , UINT32 * lenPtr )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status = EFI_SUCCESS ;
UINT32 pos ;
2020-08-19 14:50:26 +02:00
TagStruct * tagTail ;
2019-09-03 11:58:42 +02:00
UINT32 length = 0 ;
2020-08-18 18:45:44 +02:00
if ( isArray ) {
2019-09-03 11:58:42 +02:00
DBG ( " parsing array len=%d \n " , * lenPtr ) ;
2020-08-18 18:45:44 +02:00
} else {
2019-09-03 11:58:42 +02:00
DBG ( " parsing dict len=%d \n " , * lenPtr ) ;
}
tagTail = NULL ;
pos = 0 ;
2020-08-22 15:39:24 +02:00
TagStruct * dictOrArrayTag ;
XObjArray < TagStruct > * tagListPtr ;
2020-08-19 14:50:26 +02:00
if ( isArray ) {
2020-08-22 15:39:24 +02:00
dictOrArrayTag = TagStruct : : getEmptyArrayTag ( ) ;
tagListPtr = & dictOrArrayTag - > arrayContent ( ) ;
2020-08-19 14:50:26 +02:00
} else {
2020-08-22 15:39:24 +02:00
dictOrArrayTag = TagStruct : : getEmptyDictTag ( ) ;
tagListPtr = & dictOrArrayTag - > dictContent ( ) ;
2020-08-19 14:50:26 +02:00
}
2020-08-22 15:39:24 +02:00
XObjArray < TagStruct > & tagList = * tagListPtr ;
2020-08-19 14:50:26 +02:00
2019-09-03 11:58:42 +02:00
if ( ! empty ) {
while ( TRUE ) {
2020-08-19 14:50:26 +02:00
TagStruct * newDictOrArrayTag = NULL ;
Status = XMLParseNextTag ( buffer + pos , & newDictOrArrayTag , & length ) ;
2019-09-03 11:58:42 +02:00
if ( EFI_ERROR ( Status ) ) {
2020-03-25 19:32:44 +01:00
DBG ( " error XMLParseNextTag in array: %s \n " , strerror ( Status ) ) ;
2019-09-03 11:58:42 +02:00
break ;
}
pos + = length ;
2020-08-19 14:50:26 +02:00
if ( newDictOrArrayTag = = NULL ) {
2019-09-03 11:58:42 +02:00
break ;
}
2020-08-19 14:50:26 +02:00
tagList . AddReference ( newDictOrArrayTag , true ) ;
2019-09-03 11:58:42 +02:00
}
if ( EFI_ERROR ( Status ) ) {
2020-08-22 15:39:24 +02:00
dictOrArrayTag - > FreeTag ( ) ;
2019-09-03 11:58:42 +02:00
return Status ;
}
}
2020-08-19 14:50:26 +02:00
* tag = dictOrArrayTag ;
2019-09-03 11:58:42 +02:00
* lenPtr = pos ;
DBG ( " return from ParseTagList with len=%d \n " , * lenPtr ) ;
return Status ;
}
2020-08-19 14:50:26 +02:00
EFI_STATUS ParseTagDict ( CHAR8 * buffer , TagStruct * * tag , UINT32 empty , UINT32 * lenPtr )
2020-08-18 18:45:44 +02:00
{
return __ParseTagList ( false , buffer , tag , empty , lenPtr ) ;
}
2020-08-19 14:50:26 +02:00
EFI_STATUS ParseTagArray ( CHAR8 * buffer , TagStruct * * tag , UINT32 empty , UINT32 * lenPtr )
2020-08-18 18:45:44 +02:00
{
return __ParseTagList ( true , buffer , tag , empty , lenPtr ) ;
}
2019-09-03 11:58:42 +02:00
//==========================================================================
// ParseTagKey
2020-08-19 14:50:26 +02:00
EFI_STATUS ParseTagKey ( char * buffer , TagStruct * * tag , UINT32 * lenPtr )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status ;
UINT32 length = 0 ;
UINT32 length2 = 0 ;
2020-08-19 14:50:26 +02:00
TagStruct * tmpTag ;
2020-08-22 15:39:24 +02:00
// TagStruct* subTag = NULL;
2019-09-03 11:58:42 +02:00
Status = FixDataMatchingTag ( buffer , kXMLTagKey , & length ) ;
2020-03-25 19:32:44 +01:00
DBG ( " fixing key len=%d status=%s \n " , length , strerror ( Status ) ) ;
2019-09-03 11:58:42 +02:00
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
2020-08-22 15:39:24 +02:00
// Status = XMLParseNextTag(buffer + length, &subTag, &length2);
// if (EFI_ERROR(Status)) {
// return Status;
// }
tmpTag = TagStruct : : getEmptyTag ( ) ;
tmpTag - > setKeyValue ( LString8 ( buffer ) ) ;
2019-09-03 11:58:42 +02:00
* tag = tmpTag ;
* lenPtr = length + length2 ;
2020-08-22 15:39:24 +02:00
DBG ( " parse key '%s' success len=%d \n " , tmpTag - > keyStringValue ( ) . c_str ( ) , * lenPtr ) ;
2019-09-03 11:58:42 +02:00
return EFI_SUCCESS ;
}
//==========================================================================
// ParseTagString
2020-08-19 14:50:26 +02:00
EFI_STATUS ParseTagString ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status ;
UINT32 length = 0 ;
2020-08-19 14:50:26 +02:00
TagStruct * tmpTag ;
2019-09-03 11:58:42 +02:00
Status = FixDataMatchingTag ( buffer , kXMLTagString , & length ) ;
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
2020-08-22 15:39:24 +02:00
tmpTag = TagStruct : : getEmptyTag ( ) ;
2019-09-03 11:58:42 +02:00
if ( tmpTag = = NULL ) {
return EFI_OUT_OF_RESOURCES ;
}
2020-08-18 18:45:44 +02:00
tmpTag - > setStringValue ( LString8 ( XMLDecode ( buffer ) ) ) ;
2019-09-03 11:58:42 +02:00
* tag = tmpTag ;
* lenPtr = length ;
2020-08-22 15:39:24 +02:00
DBG ( " parse string %s \n " , tmpTag - > stringValue ( ) . c_str ( ) ) ;
2019-09-03 11:58:42 +02:00
return EFI_SUCCESS ;
}
//==========================================================================
// ParseTagInteger
2020-08-19 14:50:26 +02:00
EFI_STATUS ParseTagInteger ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status ;
UINT32 length = 0 ;
INTN integer ;
UINT32 size ;
BOOLEAN negative = FALSE ;
CHAR8 * val = buffer ;
2020-08-19 14:50:26 +02:00
TagStruct * tmpTag ;
2019-09-03 11:58:42 +02:00
2020-04-22 19:52:21 +02:00
Status = FixDataMatchingTag ( buffer , kXMLTagInteger , & length ) ;
2019-09-03 11:58:42 +02:00
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
2020-08-22 15:39:24 +02:00
tmpTag = TagStruct : : getEmptyTag ( ) ;
2020-08-18 18:45:44 +02:00
tmpTag - > setIntValue ( 0 ) ;
2019-09-03 11:58:42 +02:00
2020-08-17 21:40:52 +02:00
size = length ;
2019-09-03 11:58:42 +02:00
integer = 0 ;
2020-08-17 21:40:52 +02:00
if ( buffer [ 0 ] = = ' < ' )
{
2019-09-03 11:58:42 +02:00
* tag = tmpTag ;
length = 0 ;
return EFI_SUCCESS ;
}
if ( size > 1 & & ( val [ 1 ] = = ' x ' | | val [ 1 ] = = ' X ' ) ) { // Hex value
val + = 2 ;
while ( * val ) {
if ( ( * val > = ' 0 ' & & * val < = ' 9 ' ) ) { // 0 - 9
integer = ( integer * 16 ) + ( * val + + - ' 0 ' ) ;
}
else if ( ( * val > = ' a ' & & * val < = ' f ' ) ) { // a - f
integer = ( integer * 16 ) + ( * val + + - ' a ' + 10 ) ;
}
else if ( ( * val > = ' A ' & & * val < = ' F ' ) ) { // A - F
integer = ( integer * 16 ) + ( * val + + - ' a ' + 10 ) ;
}
else {
2020-04-17 15:14:24 +02:00
MsgLog ( " ParseTagInteger hex error (0x%hhX) in buffer %s \n " , * val , buffer ) ;
2019-09-03 11:58:42 +02:00
// getchar();
2020-08-22 15:39:24 +02:00
tmpTag - > FreeTag ( ) ;
2019-09-03 11:58:42 +02:00
return EFI_UNSUPPORTED ;
}
}
}
else if ( size ) { // Decimal value
if ( * val = = ' - ' ) {
negative = TRUE ;
val + + ;
size - - ;
}
for ( integer = 0 ; size > 0 ; size - - ) {
if ( * val ) { // UGLY HACK, fix me.
if ( * val < ' 0 ' | | * val > ' 9 ' ) {
2020-04-17 15:14:24 +02:00
MsgLog ( " ParseTagInteger decimal error (0x%hhX) in buffer %s \n " , * val , buffer ) ;
2019-09-03 11:58:42 +02:00
// getchar();
2020-08-22 15:39:24 +02:00
tmpTag - > FreeTag ( ) ;
2019-09-03 11:58:42 +02:00
return EFI_UNSUPPORTED ;
}
integer = ( integer * 10 ) + ( * val + + - ' 0 ' ) ;
}
}
if ( negative ) {
integer = - integer ;
}
}
2020-08-18 18:45:44 +02:00
tmpTag - > setIntValue ( integer ) ;
2019-09-03 11:58:42 +02:00
* tag = tmpTag ;
* lenPtr = length ;
return EFI_SUCCESS ;
}
2020-04-22 19:52:21 +02:00
//==========================================================================
// ParseTagFloat
2020-08-19 14:50:26 +02:00
EFI_STATUS ParseTagFloat ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr )
2020-04-22 19:52:21 +02:00
{
EFI_STATUS Status ;
2020-08-18 18:45:44 +02:00
UINT32 length ;
2020-08-19 14:50:26 +02:00
TagStruct * tmpTag ;
2020-04-22 19:52:21 +02:00
Status = FixDataMatchingTag ( buffer , kXMLTagFloat , & length ) ;
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
2020-08-22 15:39:24 +02:00
tmpTag = TagStruct : : getEmptyTag ( ) ;
2020-04-22 19:52:21 +02:00
if ( tmpTag = = NULL ) {
return EFI_OUT_OF_RESOURCES ;
}
//----
2020-08-18 18:45:44 +02:00
float f ;
AsciiStrToFloat ( buffer , NULL , & f ) ;
2020-04-22 19:52:21 +02:00
//----
2020-08-18 18:45:44 +02:00
tmpTag - > setFloatValue ( f ) ;
2020-04-22 19:52:21 +02:00
* tag = tmpTag ;
* lenPtr = length ;
return EFI_SUCCESS ;
}
2019-09-03 11:58:42 +02:00
//==========================================================================
// ParseTagData
2020-08-19 14:50:26 +02:00
EFI_STATUS ParseTagData ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status ;
UINT32 length = 0 ;
2020-08-19 14:50:26 +02:00
TagStruct * tmpTag ;
2019-09-03 11:58:42 +02:00
Status = FixDataMatchingTag ( buffer , kXMLTagData , & length ) ;
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
2020-08-22 15:39:24 +02:00
tmpTag = TagStruct : : getEmptyTag ( ) ;
2019-09-03 11:58:42 +02:00
if ( tmpTag = = NULL ) {
return EFI_OUT_OF_RESOURCES ;
}
//Slice - correction as Apple 2003
2020-08-18 18:45:44 +02:00
// tmpTag->setStringValue(LString8(buffer));
2019-09-03 11:58:42 +02:00
// dmazar: base64 decode data
2020-08-18 18:45:44 +02:00
UINTN len = 0 ;
UINT8 * data = ( UINT8 * ) Base64DecodeClover ( buffer , & len ) ;
tmpTag - > setDataValue ( data , len ) ;
2019-09-03 11:58:42 +02:00
* tag = tmpTag ;
* lenPtr = length ;
return EFI_SUCCESS ;
}
//==========================================================================
// ParseTagDate
2020-08-19 14:50:26 +02:00
EFI_STATUS ParseTagDate ( CHAR8 * buffer , TagStruct * * tag , UINT32 * lenPtr )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status ;
UINT32 length = 0 ;
2020-08-19 14:50:26 +02:00
TagStruct * tmpTag ;
2019-09-03 11:58:42 +02:00
Status = FixDataMatchingTag ( buffer , kXMLTagDate , & length ) ;
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
2020-08-22 15:39:24 +02:00
tmpTag = TagStruct : : getEmptyTag ( ) ;
2019-09-03 11:58:42 +02:00
if ( tmpTag = = NULL ) {
return EFI_OUT_OF_RESOURCES ;
}
2020-08-18 18:45:44 +02:00
tmpTag - > setDateValue ( LString8 ( buffer ) ) ;
2019-09-03 11:58:42 +02:00
* tag = tmpTag ;
* lenPtr = length ;
return EFI_SUCCESS ;
}
//==========================================================================
// ParseTagBoolean
2020-08-19 14:50:26 +02:00
EFI_STATUS ParseTagBoolean ( CHAR8 * buffer , TagStruct * * tag , bool value , UINT32 * lenPtr )
2019-09-03 11:58:42 +02:00
{
2020-08-19 14:50:26 +02:00
TagStruct * tmpTag ;
2019-09-03 11:58:42 +02:00
2020-08-22 15:39:24 +02:00
tmpTag = TagStruct : : getEmptyTag ( ) ;
2019-09-03 11:58:42 +02:00
if ( tmpTag = = NULL ) {
return EFI_OUT_OF_RESOURCES ;
}
2020-08-18 18:45:44 +02:00
tmpTag - > setBoolValue ( value ) ;
2019-09-03 11:58:42 +02:00
* tag = tmpTag ;
* lenPtr = 0 ;
return EFI_SUCCESS ;
}
//==========================================================================
// GetNextTag
EFI_STATUS GetNextTag ( UINT8 * buffer , CHAR8 * * tag , UINT32 * start , UINT32 * length )
{
UINT32 cnt , cnt2 ;
if ( tag = = NULL ) {
return EFI_INVALID_PARAMETER ;
}
// Find the start of the tag.
cnt = 0 ;
while ( ( buffer [ cnt ] ! = ' \0 ' ) & & ( buffer [ cnt ] ! = ' < ' ) ) {
cnt + + ;
}
if ( buffer [ cnt ] = = ' \0 ' ) {
DBG ( " empty buffer at cnt=%d \n " , cnt ) ;
return EFI_UNSUPPORTED ;
}
// Find the end of the tag.
cnt2 = cnt + 1 ;
while ( ( buffer [ cnt2 ] ! = ' \0 ' ) & & ( buffer [ cnt2 ] ! = ' > ' ) ) {
cnt2 + + ;
}
if ( buffer [ cnt2 ] = = ' \0 ' ) {
DBG ( " empty buffer at cnt2=%d \n " , cnt2 ) ;
return EFI_UNSUPPORTED ;
}
// Fix the tag data.
* tag = ( CHAR8 * ) ( buffer + cnt + 1 ) ;
buffer [ cnt2 ] = ' \0 ' ;
if ( start ) {
* start = cnt ;
}
* length = cnt2 + 1 ; //unreal to be -1. This is UINT32
2020-02-17 21:41:09 +01:00
if ( * length = = ( UINT32 ) - 1 ) {
2019-09-03 11:58:42 +02:00
DBG ( " GetNextTag with *length == -1 \n " ) ;
return EFI_UNSUPPORTED ;
}
return EFI_SUCCESS ;
}
//==========================================================================
// FixDataMatchingTag
// Modifies 'buffer' to add a '\0' at the end of the tag matching 'tag'.
// Returns the length of the data found, counting the end tag,
// or -1 if the end tag was not found.
2020-02-17 21:41:09 +01:00
EFI_STATUS FixDataMatchingTag ( CHAR8 * buffer , CONST CHAR8 * tag , UINT32 * lenPtr )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status ;
UINT32 length ;
UINT32 start ;
UINT32 stop ;
CHAR8 * endTag ;
start = 0 ;
while ( 1 ) {
Status = GetNextTag ( ( ( UINT8 * ) buffer ) + start , & endTag , & stop , & length ) ;
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
if ( ( * endTag = = ' / ' ) & & ! AsciiStrCmp ( endTag + 1 , tag ) ) {
break ;
}
start + = length ;
}
DBG ( " fix buffer at pos=%d \n " , start + stop ) ;
buffer [ start + stop ] = ' \0 ' ;
* lenPtr = start + length ;
2020-03-11 16:44:11 +01:00
if ( * lenPtr = = ( __typeof_am__ ( * lenPtr ) ) - 1 ) { // Why is this test. -1 is UINTN_MAX.
2019-09-03 11:58:42 +02:00
return EFI_UNSUPPORTED ;
}
return EFI_SUCCESS ;
}
//==========================================================================
2020-04-16 09:15:26 +02:00
/*
return TRUE if the property present & & value = TRUE
else return FALSE
*/
BOOLEAN
2020-08-22 15:39:24 +02:00
IsPropertyNotNullAndTrue ( const TagStruct * Prop )
2020-04-16 09:15:26 +02:00
{
2020-08-18 18:45:44 +02:00
return Prop ! = NULL & & Prop - > isTrueOrYy ( ) ;
2020-04-16 09:15:26 +02:00
}
/*
return TRUE if the property present & & value = FALSE
else return FALSE
*/
BOOLEAN
2020-08-22 15:39:24 +02:00
IsPropertyNotNullAndFalse ( const TagStruct * Prop )
2020-04-16 09:15:26 +02:00
{
2020-08-18 18:45:44 +02:00
return Prop ! = NULL & & Prop - > isFalseOrNn ( ) ;
2020-04-16 09:15:26 +02:00
}
/*
Possible values
< integer > 1234 < / integer >
< integer > + 1234 < / integer >
< integer > - 1234 < / integer >
< string > 0x12abd < / string >
*/
INTN
2020-08-22 15:39:24 +02:00
GetPropertyAsInteger (
2020-08-19 14:50:26 +02:00
const TagStruct * Prop ,
2020-04-16 09:15:26 +02:00
INTN Default
)
{
if ( Prop = = NULL ) {
return Default ;
}
2020-08-18 18:45:44 +02:00
if ( Prop - > isInt ( ) ) {
return Prop - > intValue ( ) ;
} else if ( ( Prop - > isString ( ) ) & & Prop - > stringValue ( ) . notEmpty ( ) ) {
if ( Prop - > stringValue ( ) . length ( ) > 1 & & ( Prop - > stringValue ( ) [ 1 ] = = ' x ' | | Prop - > stringValue ( ) [ 1 ] = = ' X ' ) ) {
return ( INTN ) AsciiStrHexToUintn ( Prop - > stringValue ( ) ) ;
2020-04-16 09:15:26 +02:00
}
2020-08-18 18:45:44 +02:00
if ( Prop - > stringValue ( ) [ 0 ] = = ' - ' ) {
return - ( INTN ) AsciiStrDecimalToUintn ( Prop - > stringValue ( ) . c_str ( ) + 1 ) ;
2020-04-16 09:15:26 +02:00
}
2020-08-18 18:45:44 +02:00
// return (INTN)AsciiStrDecimalToUintn (Prop->stringValue());
return ( INTN ) AsciiStrDecimalToUintn ( ( Prop - > stringValue ( ) [ 0 ] = = ' + ' ) ? ( Prop - > stringValue ( ) . c_str ( ) + 1 ) : Prop - > stringValue ( ) . c_str ( ) ) ;
2020-04-16 09:15:26 +02:00
}
return Default ;
}
2020-04-22 19:52:21 +02:00
2020-08-19 14:50:26 +02:00
float GetPropertyFloat ( const TagStruct * Prop , float Default )
2020-04-22 19:52:21 +02:00
{
if ( Prop = = NULL ) {
return Default ;
}
2020-08-18 18:45:44 +02:00
if ( Prop - > isFloat ( ) ) {
return Prop - > floatValue ( ) ; //this is union char* or float
} else if ( ( Prop - > isString ( ) ) & & Prop - > stringValue ( ) . notEmpty ( ) ) {
2020-04-22 19:52:21 +02:00
float fVar = 0.f ;
2020-08-18 18:45:44 +02:00
if ( ! AsciiStrToFloat ( Prop - > stringValue ( ) . c_str ( ) , NULL , & fVar ) ) //if success then return 0
2020-04-22 19:52:21 +02:00
return fVar ;
}
return Default ;
}