📄 cxpersistence.cpp
字号:
}
static char*
icvYMLParseKey( CvFileStorage* fs, char* ptr,
CvFileNode* map_node, CvFileNode** value_placeholder )
{
CV_FUNCNAME( "icvYMLParseKey" );
__BEGIN__;
char c;
char *endptr = ptr - 1, *saveptr;
CvStringHashNode* str_hash_node;
if( *ptr == '-' )
CV_PARSE_ERROR( "Key may not start with \'-\'" );
do c = *++endptr;
while( cv_isprint(c) && c != ':' );
if( c != ':' )
CV_PARSE_ERROR( "Missing \':\'" );
saveptr = endptr + 1;
do c = *--endptr;
while( c == ' ' );
++endptr;
if( endptr == ptr )
CV_PARSE_ERROR( "An empty key" );
CV_CALL( str_hash_node = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 ));
CV_CALL( *value_placeholder = cvGetFileNode( fs, map_node, str_hash_node, 1 ));
ptr = saveptr;
__END__;
return ptr;
}
static char*
icvYMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
int parent_flags, int min_indent )
{
CV_FUNCNAME( "icvYMLParseValue" );
__BEGIN__;
char buf[CV_FS_MAX_LEN + 1024];
char* endptr = 0;
char c = ptr[0], d = ptr[1];
int is_parent_flow = CV_NODE_IS_FLOW(parent_flags);
int value_type = CV_NODE_NONE;
int len;
memset( node, 0, sizeof(*node) );
if( c == '!' ) // handle explicit type specification
{
if( d == '!' || d == '^' )
{
ptr++;
value_type |= CV_NODE_USER;
}
endptr = ptr++;
do d = *++endptr;
while( cv_isprint(d) && d != ' ' );
len = (int)(endptr - ptr);
if( len == 0 )
CV_PARSE_ERROR( "Empty type name" );
d = *endptr;
*endptr = '\0';
if( len == 3 && !CV_NODE_IS_USER(value_type) )
{
if( memcmp( ptr, "str", 3 ) == 0 )
value_type = CV_NODE_STRING;
else if( memcmp( ptr, "int", 3 ) == 0 )
value_type = CV_NODE_INT;
else if( memcmp( ptr, "seq", 3 ) == 0 )
value_type = CV_NODE_SEQ;
else if( memcmp( ptr, "map", 3 ) == 0 )
value_type = CV_NODE_MAP;
}
else if( len == 5 && !CV_NODE_IS_USER(value_type) )
{
if( memcmp( ptr, "float", 5 ) == 0 )
value_type = CV_NODE_REAL;
}
else if( CV_NODE_IS_USER(value_type) )
{
CV_CALL( node->info = cvFindType( ptr ));
if( !node->info )
node->tag &= ~CV_NODE_USER;
}
*endptr = d;
CV_CALL( ptr = icvYMLSkipSpaces( fs, endptr, min_indent, INT_MAX ));
c = *ptr;
if( !CV_NODE_IS_USER(value_type) )
{
if( value_type == CV_NODE_STRING && c != '\'' && c != '\"' )
goto force_string;
if( value_type == CV_NODE_INT )
goto force_int;
if( value_type == CV_NODE_REAL )
goto force_real;
}
}
if( isdigit(c) ||
(c == '-' || c == '+') && (isdigit(d) || d == '.') ||
c == '.' && isalnum(d)) // a number
{
double fval;
int ival;
endptr = ptr + (c == '-' || c == '+');
while( isdigit(*endptr) )
endptr++;
if( *endptr == '.' || *endptr == 'e' )
{
force_real:
fval = icv_strtod( fs, ptr, &endptr );
/*if( endptr == ptr || isalpha(*endptr) )
CV_CALL( icvProcessSpecialDouble( fs, endptr, &fval, &endptr ));*/
node->tag = CV_NODE_REAL;
node->data.f = fval;
}
else
{
force_int:
ival = (int)strtol( ptr, &endptr, 0 );
node->tag = CV_NODE_INT;
node->data.i = ival;
}
if( !endptr || endptr == ptr )
CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" );
ptr = endptr;
}
else if( c == '\'' || c == '\"' ) // an explicit string
{
node->tag = CV_NODE_STRING;
if( c == '\'' )
for( len = 0; len < CV_FS_MAX_LEN; )
{
c = *++ptr;
if( isalnum(c) || (c != '\'' && cv_isprint(c)))
buf[len++] = c;
else if( c == '\'' )
{
c = *++ptr;
if( c != '\'' )
break;
buf[len++] = c;
}
else
CV_PARSE_ERROR( "Invalid character" );
}
else
for( len = 0; len < CV_FS_MAX_LEN; )
{
c = *++ptr;
if( isalnum(c) || (c != '\\' && c != '\"' && cv_isprint(c)))
buf[len++] = c;
else if( c == '\"' )
{
++ptr;
break;
}
else if( c == '\\' )
{
d = *++ptr;
if( d == '\'' )
buf[len++] = d;
else if( d == '\"' || d == '\\' || d == '\'' )
buf[len++] = d;
else if( d == 'n' )
buf[len++] = '\n';
else if( d == 'r' )
buf[len++] = '\r';
else if( d == 't' )
buf[len++] = '\t';
else if( d == 'x' || isdigit(d) && d < '8' )
{
int val, is_hex = d == 'x';
c = ptr[3];
ptr[3] = '\0';
val = strtol( ptr + is_hex, &endptr, is_hex ? 8 : 16 );
ptr[3] = c;
if( endptr == ptr + is_hex )
buf[len++] = 'x';
else
{
buf[len++] = (char)val;
ptr = endptr;
}
}
}
else
CV_PARSE_ERROR( "Invalid character" );
}
if( len >= CV_FS_MAX_LEN )
CV_PARSE_ERROR( "Too long string literal" );
CV_CALL( node->data.str = cvMemStorageAllocString( fs->memstorage, buf, len ));
}
else if( c == '[' || c == '{' ) // collection as a flow
{
int new_min_indent = min_indent + !is_parent_flow;
int struct_flags = CV_NODE_FLOW + (c == '{' ? CV_NODE_MAP : CV_NODE_SEQ);
int is_simple = 1;
CV_CALL( icvFSCreateCollection( fs, CV_NODE_TYPE(struct_flags) +
(node->info ? CV_NODE_USER : 0), node ));
d = c == '[' ? ']' : '}';
for( ++ptr ;;)
{
CvFileNode* elem = 0;
CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX ));
if( *ptr == '}' || *ptr == ']' )
{
if( *ptr != d )
CV_PARSE_ERROR( "The wrong closing bracket" );
ptr++;
break;
}
if( node->data.seq->total != 0 )
{
if( *ptr != ',' )
CV_PARSE_ERROR( "Missing , between the elements" );
CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr + 1, new_min_indent, INT_MAX ));
}
if( CV_NODE_IS_MAP(struct_flags) )
{
CV_CALL( ptr = icvYMLParseKey( fs, ptr, node, &elem ));
CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX ));
}
else
{
if( *ptr == ']' )
break;
elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
}
CV_CALL( ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, new_min_indent ));
if( CV_NODE_IS_MAP(struct_flags) )
elem->tag |= CV_NODE_NAMED;
is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
}
node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0;
}
else
{
int indent, struct_flags, is_simple;
if( is_parent_flow || c != '-' )
{
// implicit (one-line) string or nested block-style collection
if( !is_parent_flow )
{
if( c == '?' )
CV_PARSE_ERROR( "Complex keys are not supported" );
if( c == '|' || c == '>' )
CV_PARSE_ERROR( "Multi-line text literals are not supported" );
}
force_string:
endptr = ptr - 1;
do c = *++endptr;
while( cv_isprint(c) &&
(!is_parent_flow || c != ',' && c != '}' && c != ']') &&
(is_parent_flow || c != ':' || value_type == CV_NODE_STRING));
if( endptr == ptr )
CV_PARSE_ERROR( "Invalid character" );
if( is_parent_flow || c != ':' )
{
char* str_end = endptr;
node->tag = CV_NODE_STRING;
// strip spaces in the end of string
do c = *--str_end;
while( str_end > ptr && c == ' ' );
str_end++;
CV_CALL( node->data.str = cvMemStorageAllocString( fs->memstorage, ptr, (int)(str_end - ptr) ));
ptr = endptr;
EXIT;
}
struct_flags = CV_NODE_MAP;
}
else
struct_flags = CV_NODE_SEQ;
CV_CALL( icvFSCreateCollection( fs, struct_flags +
(node->info ? CV_NODE_USER : 0), node ));
indent = (int)(ptr - fs->buffer_start);
is_simple = 1;
for(;;)
{
CvFileNode* elem = 0;
if( CV_NODE_IS_MAP(struct_flags) )
{
CV_CALL( ptr = icvYMLParseKey( fs, ptr, node, &elem ));
}
else
{
c = *ptr++;
if( c != '-' )
CV_PARSE_ERROR( "Block sequence elements must be preceded with \'-\'" );
CV_CALL( elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 ));
}
CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, indent + 1, INT_MAX ));
CV_CALL( ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, indent + 1 ));
if( CV_NODE_IS_MAP(struct_flags) )
elem->tag |= CV_NODE_NAMED;
is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ));
if( ptr - fs->buffer_start != indent )
{
if( ptr - fs->buffer_start < indent )
break;
else
CV_PARSE_ERROR( "Incorrect indentation" );
}
if( memcmp( ptr, "...", 3 ) == 0 )
break;
}
node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0;
}
__END__;
return ptr;
}
static void
icvYMLParse( CvFileStorage* fs )
{
CV_FUNCNAME( "icvYMLParse" );
__BEGIN__;
char* ptr = fs->buffer_start;
int is_first = 1;
for(;;)
{
// 0. skip leading comments and directives and ...
// 1. reach the first item
for(;;)
{
CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ));
if( !ptr )
EXIT;
if( *ptr == '%' )
{
if( memcmp( ptr, "%YAML:", 6 ) == 0 &&
memcmp( ptr, "%YAML:1.", 8 ) != 0 )
CV_PARSE_ERROR( "Unsupported YAML version (it must be 1.x)" );
*ptr = '\0';
}
else if( *ptr == '-' )
{
if( memcmp(ptr, "---", 3) == 0 )
{
ptr += 3;
break;
}
else if( is_first )
break;
}
else if( isalnum(*ptr) || *ptr=='_')
{
if( !is_first )
CV_PARSE_ERROR( "The YAML streams must start with '---', except the first one" );
break;
}
else
CV_PARSE_ERROR( "Invalid or unsupported syntax" );
}
CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ));
if( memcmp( ptr, "...", 3 ) != 0 )
{
// 2. parse the collection
CvFileNode* root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 );
CV_CALL( ptr = icvYMLParseValue( fs, ptr, root_node, CV_NODE_NONE, 0 ));
if( !CV_NODE_IS_COLLECTION(root_node->tag) )
CV_PARSE_ERROR( "Only collections as YAML streams are supported by this parser" );
// 3. parse until the end of file or next collection
CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ));
if( !ptr )
EXIT;
}
if( fs->dummy_eof )
break;
ptr += 3;
is_first = 0;
}
__END__;
}
/****************************************************************************************\
* YAML Emitter *
\****************************************************************************************/
static void
icvYMLWrite( CvFileStorage* fs, const char* key, const char* data, const char* cvFuncName )
{
//CV_FUNCNAME( "icvYMLWrite" );
__BEGIN__;
int i, keylen = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -