Commit message: core(persistence): added null ptr checks
CVE: CVE-2019-14493
CWE: CWE-476
Vulnerability description: An issue was discovered in OpenCV before 4.1.1. There is a NULL pointer dereference in the function cv::XMLParser::parse at modules/core/src/persistence.cpp.

Project: opencv
File: persistence_xml.cpp

    bool getBase64Row(char* ptr, int /*indent*/, char* &beg, char* &end)
    {
        beg = end = ptr = skipSpaces(ptr, CV_XML_INSIDE_TAG);
        if( !ptr || !*ptr )
            return false;

        // closing XML tag
        if ( *beg == '<' )
            return false;

        // find end of the row
        while( cv_isprint(*ptr) )
            ++ptr;
        if ( *ptr == '\0' )
            CV_PARSE_ERROR_CPP( "Unexpected end of line" );

        end = ptr;
        return true;
    }

Project: opencv
File: persistence_json.cpp

    void writeComment(const char* comment, bool eol_comment)
    {
        if( !comment )
            CV_Error( CV_StsNullPtr, "Null comment" );

        int len = static_cast<int>(strlen(comment));
        char* ptr = fs->bufferPtr();
        const char* eol = strchr(comment, '\n');
        bool multiline = eol != 0;

        if( !eol_comment || multiline || fs->bufferEnd() - ptr < len || ptr == fs->bufferStart() )
            ptr = fs->flush();
        else
            *ptr++ = ' ';

        while( comment )
        {
            *ptr++ = '/';
            *ptr++ = '/';
            *ptr++ = ' ';
            if( eol )
            {
                ptr = fs->resizeWriteBuffer( ptr, (int)(eol - comment) + 1 );
                memcpy( ptr, comment, eol - comment + 1 );
                fs->setBufferPtr(ptr + (eol - comment));
                comment = eol + 1;
                eol = strchr( comment, '\n' );
            }
            else
            {
                len = (int)strlen(comment);
                ptr = fs->resizeWriteBuffer( ptr, len );
                memcpy( ptr, comment, len );
                fs->setBufferPtr(ptr + len);
                comment = 0;
            }
            ptr = fs->flush();
        }
    }

Project: opencv
File: persistence_json.cpp

Ptr<FileStorageParser> createJSONParser(FileStorage_API* fs)
{
    return makePtr<JSONParser>(fs);
}

Project: opencv
File: persistence_yml.cpp

    bool getBase64Row(char* ptr, int indent, char* &beg, char* &end)
    {
        if (!ptr)
            CV_PARSE_ERROR_CPP("Invalid input");

        beg = end = ptr = skipSpaces(ptr, 0, INT_MAX);
        if (!ptr || !*ptr)
            return false; // end of file

        if (ptr - fs->bufferStart() != indent)
            return false; // end of base64 data

        /* find end */
        while(cv_isprint(*ptr)) /* no check for base64 string */
            ++ptr;
        if (*ptr == '\0')
            CV_PARSE_ERROR_CPP("Unexpected end of line");

        end = ptr;
        return true;
    }

Project: opencv
File: persistence_yml.cpp

    FStructData startWriteStruct(const FStructData& parent, const char* key,
                                 int struct_flags, const char* type_name=0)
    {
        char buf[CV_FS_MAX_LEN + 1024];
        const char* data = 0;

        if ( type_name && *type_name == '\0' )
            type_name = 0;

        struct_flags = (struct_flags & (FileNode::TYPE_MASK|FileNode::FLOW)) | FileNode::EMPTY;
        if( !FileNode::isCollection(struct_flags))
            CV_Error( CV_StsBadArg,
                     "Some collection type - FileNode::SEQ or FileNode::MAP, must be specified" );

        if (type_name && memcmp(type_name, "binary", 6) == 0)
        {
            /* reset struct flag. in order not to print ']' */
            struct_flags = FileNode::SEQ;
            sprintf(buf, "!!binary |");
            data = buf;
        }
        else if( FileNode::isFlow(struct_flags))
        {
            char c = FileNode::isMap(struct_flags) ? '{' : '[';
            struct_flags |= FileNode::FLOW;

            if( type_name )
                sprintf( buf, "!!%s %c", type_name, c );
            else
            {
                buf[0] = c;
                buf[1] = '\0';
            }
            data = buf;
        }
        else if( type_name )
        {
            sprintf( buf, "!!%s", type_name );
            data = buf;
        }

        writeScalar( key, data );

        FStructData fsd;
        fsd.indent = parent.indent;
        fsd.flags = struct_flags;

        if( !FileNode::isFlow(parent.flags) )
            fsd.indent += CV_YML_INDENT + FileNode::isFlow(struct_flags);

        return fsd;
    }

Project: opencv
File: persistence_json.cpp

    JSONParser(FileStorage_API* _fs) : fs(_fs)
    {
    }

Project: opencv
File: persistence_yml.cpp

Ptr<FileStorageParser> createYAMLParser(FileStorage_API* fs)
{
    return makePtr<YAMLParser>(fs);
}

Project: opencv
File: persistence_xml.cpp

    void write( const char* key, double value )
    {
        char buf[128];
        writeScalar( key, fs::doubleToString( buf, value, false ) );
    }

Project: opencv
File: persistence_xml.cpp

    char* skipSpaces( char* ptr, int mode )
    {
        if (!ptr)
            CV_PARSE_ERROR_CPP("Invalid input");

        int level = 0;

        for(;;)
        {
            char c;
            ptr--;

            if( mode == CV_XML_INSIDE_COMMENT )
            {
                do c = *++ptr;
                while( cv_isprint_or_tab(c) && (c != '-' || ptr[1] != '-' || ptr[2] != '>') );

                if( c == '-' )
                {
                    assert( ptr[1] == '-' && ptr[2] == '>' );
                    mode = 0;
                    ptr += 3;
                }
            }
            else if( mode == CV_XML_INSIDE_DIRECTIVE )
            {
                // !!!NOTE!!! This is not quite correct, but should work in most cases
                do
                {
                    c = *++ptr;
                    level += c == '<';
                    level -= c == '>';
                    if( level < 0 )
                        return ptr;
                } while( cv_isprint_or_tab(c) );
            }
            else
            {
                do c = *++ptr;
                while( c == ' ' || c == '\t' );

                if( c == '<' && ptr[1] == '!' && ptr[2] == '-' && ptr[3] == '-' )
                {
                    if( mode != 0 )
                        CV_PARSE_ERROR_CPP( "Comments are not allowed here" );
                    mode = CV_XML_INSIDE_COMMENT;
                    ptr += 4;
                }
                else if( cv_isprint(c) )
                    break;
            }

            if( !cv_isprint(*ptr) )
            {
                if( *ptr != '\0' && *ptr != '\n' && *ptr != '\r' )
                    CV_PARSE_ERROR_CPP( "Invalid character in the stream" );
                ptr = fs->gets();
                if( !ptr || *ptr == '\0' )
                    break;
            }
        }
        return ptr;
    }

Project: opencv
File: persistence_yml.cpp

    void write(const char* key, const char* str, bool quote)
    {
        char buf[CV_FS_MAX_LEN*4+16];
        char* data = (char*)str;
        int i, len;

        if( !str )
            CV_Error( CV_StsNullPtr, "Null string pointer" );

        len = (int)strlen(str);
        if( len > CV_FS_MAX_LEN )
            CV_Error( CV_StsBadArg, "The written string is too long" );

        if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') )
        {
            int need_quote = quote || len == 0 || str[0] == ' ';
            data = buf;
            *data++ = '\"';
            for( i = 0; i < len; i++ )
            {
                char c = str[i];

                if( !need_quote && !cv_isalnum(c) && c != '_' && c != ' ' && c != '-' &&
                   c != '(' && c != ')' && c != '/' && c != '+' && c != ';' )
                    need_quote = 1;

                if( !cv_isalnum(c) && (!cv_isprint(c) || c == '\\' || c == '\'' || c == '\"') )
                {
                    *data++ = '\\';
                    if( cv_isprint(c) )
                        *data++ = c;
                    else if( c == '\n' )
                        *data++ = 'n';
                    else if( c == '\r' )
                        *data++ = 'r';
                    else if( c == '\t' )
                        *data++ = 't';
                    else
                    {
                        sprintf( data, "x%02x", c );
                        data += 3;
                    }
                }
                else
                    *data++ = c;
            }
            if( !need_quote && (cv_isdigit(str[0]) ||
                                str[0] == '+' || str[0] == '-' || str[0] == '.' ))
                need_quote = 1;

            if( need_quote )
                *data++ = '\"';
            *data++ = '\0';
            data = buf + !need_quote;
        }

        writeScalar( key, data);
    }

Project: opencv
File: persistence_xml.cpp

    XMLEmitter(FileStorage_API* _fs) : fs(_fs)
    {
    }

Project: opencv
File: persistence_xml.cpp

    XMLParser(FileStorage_API* _fs) : fs(_fs)
    {
    }

Project: opencv
File: persistence_json.cpp

    bool getBase64Row(char*, int /*indent*/, char*&, char*&)
    {
        CV_PARSE_ERROR_CPP("Currently, JSON parser does not support base64 data");
        return false;
    }

Project: opencv
File: persistence_yml.cpp

    char* skipSpaces( char* ptr, int min_indent, int max_comment_indent )
    {
        if (!ptr)
            CV_PARSE_ERROR_CPP("Invalid input");

        for(;;)
        {
            while( *ptr == ' ' )
                ptr++;
            if( *ptr == '#' )
            {
                if( ptr - fs->bufferStart() > max_comment_indent )
                    return ptr;
                *ptr = '\0';
            }
            else if( cv_isprint(*ptr) )
            {
                if( ptr - fs->bufferStart() < min_indent )
                    CV_PARSE_ERROR_CPP( "Incorrect indentation" );
                break;
            }
            else if( *ptr == '\0' || *ptr == '\n' || *ptr == '\r' )
            {
                ptr = fs->gets();
                if( !ptr )
                {
                    // emulate end of stream
                    ptr = fs->bufferStart();
                    ptr[0] = ptr[1] = ptr[2] = '.';
                    ptr[3] = '\0';
                    fs->setEof();
                    break;
                }
                else
                {
                    int l = (int)strlen(ptr);
                    if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !fs->eof() )
                        CV_PARSE_ERROR_CPP( "Too long string or a last string w/o newline" );
                }
            }
            else
                CV_PARSE_ERROR_CPP( *ptr == '\t' ? "Tabs are prohibited in YAML!" : "Invalid character" );
        }

        return ptr;
    }

Project: opencv
File: persistence_json.cpp

    void write(const char* key, int value)
    {
        char buf[128];
        writeScalar( key, fs::itoa( value, buf, 10 ));
    }

Project: opencv
File: persistence_xml.cpp

    void writeScalar(const char* key, const char* data)
    {
        int len = (int)strlen(data);
        if( key && *key == '\0' )
            key = 0;

        FStructData& current_struct = fs->getCurrentStruct();
        int struct_flags = current_struct.flags;

        if( FileNode::isMap(struct_flags) ||
           (!FileNode::isCollection(struct_flags) && key) )
        {
            writeTag( key, CV_XML_OPENING_TAG );
            char* ptr = fs->resizeWriteBuffer( fs->bufferPtr(), len );
            memcpy( ptr, data, len );
            fs->setBufferPtr( ptr + len );
            writeTag( key, CV_XML_CLOSING_TAG );
        }
        else
        {
            char* ptr = fs->bufferPtr();
            int new_offset = (int)(ptr - fs->bufferStart()) + len;

            if( key )
                CV_Error( CV_StsBadArg, "elements with keys can not be written to sequence" );

            current_struct.flags = FileNode::SEQ;

            if( (new_offset > fs->wrapMargin() && new_offset - current_struct.indent > 10) ||
               (ptr > fs->bufferStart() && ptr[-1] == '>') )
            {
                ptr = fs->flush();
            }
            else if( ptr > fs->bufferStart() + current_struct.indent && ptr[-1] != '>' )
                *ptr++ = ' ';

            memcpy( ptr, data, len );
            fs->setBufferPtr(ptr + len);
        }
    }

Project: opencv
File: persistence_json.cpp

    bool parse( char* ptr )
    {
        if (!ptr)
            CV_PARSE_ERROR_CPP("Invalid input");

        ptr = skipSpaces( ptr );
        if ( !ptr || !*ptr )
            return false;

        FileNode root_collection(fs->getFS(), 0, 0);

        if( *ptr == '{' )
        {
            FileNode root_node = fs->addNode(root_collection, std::string(), FileNode::MAP);
            parseMap( ptr, root_node );
        }
        else if ( *ptr == '[' )
        {
            FileNode root_node = fs->addNode(root_collection, std::string(), FileNode::SEQ);
            parseSeq( ptr, root_node );
        }
        else
        {
            CV_PARSE_ERROR_CPP( "left-brace of top level is missing" );
        }

        if( !ptr || !*ptr )
            CV_PARSE_ERROR_CPP( "Unexpected End-Of-File" );
        return true;
    }

Project: opencv
File: persistence_json.cpp

    char* skipSpaces( char* ptr )
    {
        bool is_eof = false;
        bool is_completed = false;

        while ( is_eof == false && is_completed == false )
        {
            if (!ptr)
                CV_PARSE_ERROR_CPP("Invalid input");
            switch ( *ptr )
            {
                /* comment */
                case '/' : {
                    ptr++;
                    if ( *ptr == '\0' )
                    {
                        ptr = fs->gets();
                        if( !ptr || !*ptr ) { is_eof = true; break; }
                    }

                    if ( *ptr == '/' )
                    {
                        while ( *ptr != '\n' && *ptr != '\r' )
                        {
                            if ( *ptr == '\0' )
                            {
                                ptr = fs->gets();
                                if( !ptr || !*ptr ) { is_eof = true; break; }
                            }
                            else
                            {
                                ptr++;
                            }
                        }
                    }
                    else if ( *ptr == '*' )
                    {
                        ptr++;
                        for (;;)
                        {
                            if ( *ptr == '\0' )
                            {
                                ptr = fs->gets();
                                if( !ptr || !*ptr ) { is_eof = true; break; }
                            }
                            else if ( *ptr == '*' )
                            {
                                ptr++;
                                if ( *ptr == '\0' )
                                {
                                    ptr = fs->gets();
                                    if( !ptr || !*ptr ) { is_eof = true; break; }
                                }
                                if ( *ptr == '/' )
                                {
                                    ptr++;
                                    break;
                                }
                            }
                            else
                            {
                                ptr++;
                            }
                        }
                    }
                    else
                    {
                        CV_PARSE_ERROR_CPP( "Not supported escape character" );
                    }
                } break;
                    /* whitespace */
                case '\t':
                case ' ' : {
                    ptr++;
                } break;
                    /* newline || end mark */
                case '\0':
                case '\n':
                case '\r': {
                    ptr = fs->gets();
                    if( !ptr || !*ptr ) { is_eof = true; break; }
                } break;
                    /* other character */
                default: {
                    if( !cv_isprint(*ptr) )
                        CV_PARSE_ERROR_CPP( "Invalid character in the stream" );
                    is_completed = true;
                } break;
            }
        }

        if ( is_eof || !is_completed )
        {
            ptr = fs->bufferStart();
            CV_Assert(ptr);
            *ptr = '\0';
            fs->setEof();
            if( !is_completed )
                CV_PARSE_ERROR_CPP( "Abort at parse time" );
        }

        return ptr;
    }

Project: opencv
File: persistence_json.cpp

    void endWriteStruct(const FStructData& current_struct)
    {
        int struct_flags = current_struct.flags;
        CV_Assert( FileNode::isCollection(struct_flags) );

        if( !FileNode::isFlow(struct_flags) )
        {
#if 0
            if ( fs->bufferPtr() <= fs->bufferStart() + fs->space )
            {
                /* some bad code for base64_writer... */
                ptr = fs->bufferPtr();
                *ptr++ = '\n';
                *ptr++ = '\0';
                fs->puts( fs->bufferStart() );
                fs->setBufferPtr(fs->bufferStart());
            }
#endif
            fs->flush();
        }

        char* ptr = fs->bufferPtr();
        if( ptr > fs->bufferStart() + current_struct.indent && !FileNode::isEmptyCollection(struct_flags) )
            *ptr++ = ' ';
        *ptr++ = FileNode::isMap(struct_flags) ? '}' : ']';
        fs->setBufferPtr(ptr);
    }

Project: opencv
File: persistence_xml.cpp

    FStructData startWriteStruct(const FStructData& parent, const char* key,
                                 int struct_flags, const char* type_name=0)
    {
        std::vector<std::string> attrlist;
        if( type_name && *type_name )
        {
            attrlist.push_back("type_id");
            attrlist.push_back(type_name);
        }

        writeTag( key, CV_XML_OPENING_TAG, attrlist );

        FStructData current_struct;
        current_struct.tag = key ? std::string(key) : std::string();
        current_struct.flags = struct_flags;
        current_struct.indent = parent.indent + CV_XML_INDENT;

        return current_struct;
    }

Project: opencv
File: persistence_xml.cpp

    void write(const char* key, int value)
    {
        char buf[128], *ptr = fs::itoa( value, buf, 10 );
        writeScalar( key, ptr);
    }

Project: opencv
File: persistence_yml.cpp

Ptr<FileStorageEmitter> createYAMLEmitter(FileStorage_API* fs)
{
    return makePtr<YAMLEmitter>(fs);
}

Project: opencv
File: persistence_xml.cpp

    void writeTag( const char* key, int tag_type, const std::vector<std::string>& attrlist=std::vector<std::string>() )
    {
        char* ptr = fs->bufferPtr();
        int i, len = 0;
        FStructData& current_struct = fs->getCurrentStruct();
        int struct_flags = current_struct.flags;

        if( key && key[0] == '\0' )
            key = 0;

        if( tag_type == CV_XML_OPENING_TAG || tag_type == CV_XML_EMPTY_TAG )
        {
            if( FileNode::isCollection(struct_flags) )
            {
                if( FileNode::isMap(struct_flags) ^ (key != 0) )
                    CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
                             "or add element with key to sequence" );
            }
            else
            {
                struct_flags = FileNode::EMPTY + (key ? FileNode::MAP : FileNode::SEQ);
                //fs->is_first = 0;
            }

            if( !FileNode::isEmptyCollection(struct_flags) )
                ptr = fs->flush();
        }

        if( !key )
            key = "_";
        else if( key[0] == '_' && key[1] == '\0' )
            CV_Error( CV_StsBadArg, "A single _ is a reserved tag name" );

        len = (int)strlen( key );
        *ptr++ = '<';
        if( tag_type == CV_XML_CLOSING_TAG )
        {
            if( !attrlist.empty() )
                CV_Error( CV_StsBadArg, "Closing tag should not include any attributes" );
            *ptr++ = '/';
        }

        if( !cv_isalpha(key[0]) && key[0] != '_' )
            CV_Error( CV_StsBadArg, "Key should start with a letter or _" );

        ptr = fs->resizeWriteBuffer( ptr, len );
        for( i = 0; i < len; i++ )
        {
            char c = key[i];
            if( !cv_isalnum(c) && c != '_' && c != '-' )
                CV_Error( CV_StsBadArg, "Key name may only contain alphanumeric characters [a-zA-Z0-9], '-' and '_'" );
            ptr[i] = c;
        }
        ptr += len;

        int nattr = (int)attrlist.size();
        CV_Assert( nattr % 2 == 0 );

        for( i = 0; i < nattr; i += 2 )
        {
            size_t len0 = attrlist[i].size();
            size_t len1 = attrlist[i+1].size();
            CV_Assert( len0 > 0 );

            ptr = fs->resizeWriteBuffer( ptr, (int)(len0 + len1 + 4) );
            *ptr++ = ' ';

            memcpy( ptr, attrlist[i].c_str(), len0 );
            ptr += len0;
            *ptr++ = '=';
            *ptr++ = '\"';
            if( len1 > 0 )
                memcpy( ptr, attrlist[i+1].c_str(), len1 );
            ptr += len1;
            *ptr++ = '\"';
        }

        if( tag_type == CV_XML_EMPTY_TAG )
            *ptr++ = '/';
        *ptr++ = '>';
        fs->setBufferPtr(ptr);
        current_struct.flags = struct_flags & ~FileNode::EMPTY;
    }

Project: opencv
File: persistence_json.cpp

    JSONEmitter(FileStorage_API* _fs) : fs(_fs)
    {
    }

Project: opencv
File: persistence_json.cpp

Ptr<FileStorageEmitter> createJSONEmitter(FileStorage_API* fs)
{
    return makePtr<JSONEmitter>(fs);
}

Project: opencv
File: persistence_xml.cpp

    char* parseTag( char* ptr, std::string& tag_name,
                    std::string& type_name, int& tag_type )
    {
        if (!ptr)
            CV_PARSE_ERROR_CPP("Invalid tag input");

        if( *ptr == '\0' )
            CV_PARSE_ERROR_CPP( "Unexpected end of the stream" );

        if( *ptr != '<' )
            CV_PARSE_ERROR_CPP( "Tag should start with \'<\'" );

        ptr++;
        CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP();

        if( cv_isalnum(*ptr) || *ptr == '_' )
            tag_type = CV_XML_OPENING_TAG;
        else if( *ptr == '/' )
        {
            tag_type = CV_XML_CLOSING_TAG;
            ptr++;
        }
        else if( *ptr == '?' )
        {
            tag_type = CV_XML_HEADER_TAG;
            ptr++;
        }
        else if( *ptr == '!' )
        {
            tag_type = CV_XML_DIRECTIVE_TAG;
            assert( ptr[1] != '-' || ptr[2] != '-' );
            ptr++;
        }
        else
            CV_PARSE_ERROR_CPP( "Unknown tag type" );

        tag_name.clear();
        type_name.clear();

        for(;;)
        {
            char c, *endptr;
            if( !cv_isalpha(*ptr) && *ptr != '_' )
                CV_PARSE_ERROR_CPP( "Name should start with a letter or underscore" );

            endptr = ptr - 1;
            do c = *++endptr;
            while( cv_isalnum(c) || c == '_' || c == '-' );

            std::string attrname(ptr, (size_t)(endptr - ptr));
            ptr = endptr;
            CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP();

            if( tag_name.empty() )
                tag_name = attrname;
            else
            {
                if( tag_type == CV_XML_CLOSING_TAG )
                    CV_PARSE_ERROR_CPP( "Closing tag should not contain any attributes" );

                if( *ptr != '=' )
                {
                    ptr = skipSpaces( ptr, CV_XML_INSIDE_TAG );
                    if (!ptr)
                        CV_PARSE_ERROR_CPP("Invalid attribute");
                    if( *ptr != '=' )
                        CV_PARSE_ERROR_CPP( "Attribute name should be followed by \'=\'" );
                }

                c = *++ptr;
                if( c != '\"' && c != '\'' )
                {
                    ptr = skipSpaces( ptr, CV_XML_INSIDE_TAG );
                    if( *ptr != '\"' && *ptr != '\'' )
                        CV_PARSE_ERROR_CPP( "Attribute value should be put into single or double quotes" );
                }

                char quote = *ptr++;
                endptr = ptr;
                for(;;)
                {
                    c = *endptr++;
                    if( c == quote )
                        break;
                    if( c == '\0' )
                        CV_PARSE_ERROR_CPP( "Unexpected end of line" );
                }

                if( attrname == "type_id" )
                {
                    CV_Assert( type_name.empty() );
                    type_name = std::string(ptr, (size_t)(endptr - 1 - ptr));
                }

                ptr = endptr;
            }

            c = *ptr;
            bool have_space = cv_isspace(c) || c == '\0';

            if( c != '>' )
            {
                ptr = skipSpaces( ptr, CV_XML_INSIDE_TAG );
                if (!ptr)
                    CV_PARSE_ERROR_CPP("Invalid input");
                c = *ptr;
            }

            if( c == '>' )
            {
                if( tag_type == CV_XML_HEADER_TAG )
                    CV_PARSE_ERROR_CPP( "Invalid closing tag for <?xml ..." );
                ptr++;
                break;
            }
            else if( c == '?' && tag_type == CV_XML_HEADER_TAG )
            {
                if( ptr[1] != '>'  )  // FIXIT ptr[1] - out of bounds read without check
                    CV_PARSE_ERROR_CPP( "Invalid closing tag for <?xml ..." );
                ptr += 2;
                break;
            }
            else if( c == '/' && ptr[1] == '>' && tag_type == CV_XML_OPENING_TAG )  // FIXIT ptr[1] - out of bounds read without check
            {
                tag_type = CV_XML_EMPTY_TAG;
                ptr += 2;
                break;
            }

            if( !have_space )
                CV_PARSE_ERROR_CPP( "There should be space between attributes" );
        }

        return ptr;
    }

Project: opencv
File: persistence_xml.cpp

    bool parse(char* ptr)
    {
        CV_Assert( fs != 0 );

        std::string key, key2, type_name;
        int tag_type = 0;
        bool ok = false;

        // CV_XML_INSIDE_TAG is used to prohibit leading comments
        ptr = skipSpaces( ptr, CV_XML_INSIDE_TAG );
        if (!ptr)
            CV_PARSE_ERROR_CPP("Invalid input");

        if( memcmp( ptr, "<?xml", 5 ) != 0 )  // FIXIT ptr[1..] - out of bounds read without check
            CV_PARSE_ERROR_CPP( "Valid XML should start with \'<?xml ...?>\'" );

        ptr = parseTag( ptr, key, type_name, tag_type );
        FileNode root_collection(fs->getFS(), 0, 0);

        while( ptr && *ptr != '\0' )
        {
            ptr = skipSpaces( ptr, 0 );
            if (!ptr)
                CV_PARSE_ERROR_CPP("Invalid input");

            if( *ptr != '\0' )
            {
                ptr = parseTag( ptr, key, type_name, tag_type );
                if( tag_type != CV_XML_OPENING_TAG || key != "opencv_storage" )
                    CV_PARSE_ERROR_CPP( "<opencv_storage> tag is missing" );
                FileNode root = fs->addNode(root_collection, std::string(), FileNode::MAP, 0);
                ptr = parseValue( ptr, root );
                ptr = parseTag( ptr, key2, type_name, tag_type );
                if( tag_type != CV_XML_CLOSING_TAG || key != key2 )
                    CV_PARSE_ERROR_CPP( "</opencv_storage> tag is missing" );
                ptr = skipSpaces( ptr, 0 );
                ok = true;
            }
        }
        CV_Assert( fs->eof() );
        return ok;
    }

Project: opencv
File: persistence_xml.cpp

Ptr<FileStorageEmitter> createXMLEmitter(FileStorage_API* fs)
{
    return makePtr<XMLEmitter>(fs);
}

Project: opencv
File: persistence_json.cpp

    char* parseMap( char* ptr, FileNode& node )
    {
        if (!ptr)
            CV_PARSE_ERROR_CPP("ptr is NULL");

        if ( *ptr != '{' )
            CV_PARSE_ERROR_CPP( "'{' - left-brace of map is missing" );
        else
            ptr++;

        fs->convertToCollection(FileNode::MAP, node);

        for( ;; )
        {
            ptr = skipSpaces( ptr );
            if( !ptr || !*ptr )
                break;

            if ( *ptr == '"' )
            {
                FileNode child;
                ptr = parseKey( ptr, node, child );
                if( !ptr || !*ptr )
                    break;
                ptr = skipSpaces( ptr );
                if( !ptr || !*ptr )
                    break;

                if ( *ptr == '[' )
                    ptr = parseSeq( ptr, child );
                else if ( *ptr == '{' )
                    ptr = parseMap( ptr, child );
                else
                    ptr = parseValue( ptr, child );
            }

            ptr = skipSpaces( ptr );
            if( !ptr || !*ptr )
                break;

            if ( *ptr == ',' )
                ptr++;
            else if ( *ptr == '}' )
                break;
            else
                CV_PARSE_ERROR_CPP( "Unexpected character" );
        }

        if (!ptr)
            CV_PARSE_ERROR_CPP("ptr is NULL");

        if ( *ptr != '}' )
            CV_PARSE_ERROR_CPP( "'}' - right-brace of map is missing" );
        else
            ptr++;

        fs->finalizeCollection(node);
        return ptr;
    }

Project: opencv
File: persistence_yml.cpp

    YAMLEmitter(FileStorage_API* _fs) : fs(_fs)
    {
    }

Project: opencv
File: persistence_json.cpp

    FStructData startWriteStruct( const FStructData& parent, const char* key,
                                  int struct_flags, const char* type_name=0 )
    {
        char data[CV_FS_MAX_LEN + 1024];

        struct_flags = (struct_flags & (FileNode::TYPE_MASK|FileNode::FLOW)) | FileNode::EMPTY;
        if( !FileNode::isCollection(struct_flags))
            CV_Error( CV_StsBadArg,
                     "Some collection type - FileNode::SEQ or FileNode::MAP, must be specified" );

        if( type_name && *type_name == '\0' )
            type_name = 0;

        bool is_real_collection = true;
        if (type_name && memcmp(type_name, "binary", 6) == 0)
        {
            struct_flags = FileNode::STR;
            data[0] = '\0';
            is_real_collection = false;
        }

        if ( is_real_collection )
        {
            char c = FileNode::isMap(struct_flags) ? '{' : '[';
            data[0] = c;
            data[1] = '\0';
        }

        writeScalar( key, data );
        FStructData current_struct("", struct_flags, parent.indent + 4);

        return current_struct;
    }

Project: opencv
File: persistence_yml.cpp

    char* parseValue( char* ptr, FileNode& node, int min_indent, bool is_parent_flow )
    {
        if (!ptr)
            CV_PARSE_ERROR_CPP("Invalid input");

        char* endptr = 0;
        char c = ptr[0], d = ptr[1];
        int value_type = FileNode::NONE;
        int len;
        bool is_binary_string = false;
        bool is_user = false;

        if( c == '!' ) // handle explicit type specification
        {
            if( d == '!' || d == '^' )
            {
                ptr++;
                is_user = true;
                //value_type |= FileNode::USER;
            }
            if ( d == '<') //support of full type heading from YAML 1.2
            {
                const char* yamlTypeHeading = "<tag:yaml.org,2002:";
                const size_t headingLenght = strlen(yamlTypeHeading);

                char* typeEndPtr = ++ptr;

                do d = *++typeEndPtr;
                while( cv_isprint(d) && d != ' ' && d != '>' );

                if ( d == '>' && (size_t)(typeEndPtr - ptr) > headingLenght )
                {
                    if ( memcmp(ptr, yamlTypeHeading, headingLenght) == 0 )
                    {
                        *typeEndPtr = ' ';
                        ptr += headingLenght - 1;
                        is_user = true;
                        //value_type |= FileNode::USER;
                    }
                }
            }

            endptr = ptr++;
            do d = *++endptr;
            while( cv_isprint(d) && d != ' ' );
            len = (int)(endptr - ptr);
            if( len == 0 )
                CV_PARSE_ERROR_CPP( "Empty type name" );
            d = *endptr;
            *endptr = '\0';

            if( len == 3 && !is_user )
            {
                if( memcmp( ptr, "str", 3 ) == 0 )
                    value_type = FileNode::STRING;
                else if( memcmp( ptr, "int", 3 ) == 0 )
                    value_type = FileNode::INT;
                else if( memcmp( ptr, "seq", 3 ) == 0 )
                    value_type = FileNode::SEQ;
                else if( memcmp( ptr, "map", 3 ) == 0 )
                    value_type = FileNode::MAP;
            }
            else if( len == 5 && !is_user )
            {
                if( memcmp( ptr, "float", 5 ) == 0 )
                    value_type = FileNode::REAL;
            }
            else if (len == 6 && is_user)
            {
                if( memcmp( ptr, "binary", 6 ) == 0 ) {
                    value_type = FileNode::SEQ;
                    is_binary_string = true;

                    /* for ignore '|' */

                    /**** operation with endptr ****/
                    *endptr = d;

                    do {
                        d = *++endptr;
                        if (d == '|')
                            break;
                    } while (d == ' ');

                    d = *++endptr;
                    *endptr = '\0';
                }
            }

            *endptr = d;
            ptr = skipSpaces( endptr, min_indent, INT_MAX );
            if (!ptr)
                CV_PARSE_ERROR_CPP("Invalid input");

            c = *ptr;

            if( !is_user )
            {
                if (value_type == FileNode::STRING && c != '\'' && c != '\"')
                    goto force_string;
                if( value_type == FileNode::INT )
                    goto force_int;
                if( value_type == FileNode::REAL )
                    goto force_real;
            }
        }

        if (is_binary_string)
        {
            int indent = static_cast<int>(ptr - fs->bufferStart());
            ptr = fs->parseBase64(ptr, indent, node);
        }
        else if( cv_isdigit(c) ||
                ((c == '-' || c == '+') && (cv_isdigit(d) || d == '.')) ||
                (c == '.' && cv_isalnum(d))) // a number
        {
            endptr = ptr + (c == '-' || c == '+');
            while( cv_isdigit(*endptr) )
                endptr++;
            if( *endptr == '.' || *endptr == 'e' )
            {
            force_real:
                double fval = fs->strtod( ptr, &endptr );
                node.setValue(FileNode::REAL, &fval);
            }
            else
            {
            force_int:
                int ival = (int)strtol( ptr, &endptr, 0 );
                node.setValue(FileNode::INT, &ival);
            }

            if( !endptr || endptr == ptr )
                CV_PARSE_ERROR_CPP( "Invalid numeric value (inconsistent explicit type specification?)" );

            ptr = endptr;
            CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP();
        }
        else if( c == '\'' || c == '\"' ) // an explicit string
        {
            if( c == '\'' )
                for( len = 0; len < CV_FS_MAX_LEN; )
                {
                    c = *++ptr;
                    if( cv_isalnum(c) || (c != '\'' && cv_isprint(c)))
                        buf[len++] = c;
                    else if( c == '\'' )
                    {
                        c = *++ptr;
                        if( c != '\'' )
                            break;
                        buf[len++] = c;
                    }
                    else
                        CV_PARSE_ERROR_CPP( "Invalid character" );
                }
            else
                for( len = 0; len < CV_FS_MAX_LEN; )
                {
                    c = *++ptr;
                    if( cv_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' || (cv_isdigit(d) && d < '8') )
                        {
                            int val, is_hex = d == 'x';
                            c = ptr[3];
                            ptr[3] = '\0';
                            val = (int)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_CPP( "Invalid character" );
                }

            if( len >= CV_FS_MAX_LEN )
                CV_PARSE_ERROR_CPP( "Too long string literal" );

            node.setValue(FileNode::STRING, buf, len);
        }
        else if( c == '[' || c == '{' ) // collection as a flow
        {
            int new_min_indent = min_indent + !is_parent_flow;
            int struct_type = c == '{' ? FileNode::MAP : FileNode::SEQ;
            int nelems = 0;

            fs->convertToCollection(struct_type, node);
            d = c == '[' ? ']' : '}';

            for( ++ptr ;; nelems++ )
            {
                FileNode elem;

                ptr = skipSpaces( ptr, new_min_indent, INT_MAX );
                if (!ptr)
                    CV_PARSE_ERROR_CPP("Invalid input");
                if( *ptr == '}' || *ptr == ']' )
                {
                    if( *ptr != d )
                        CV_PARSE_ERROR_CPP( "The wrong closing bracket" );
                    ptr++;
                    break;
                }

                if( nelems != 0 )
                {
                    if( *ptr != ',' )
                        CV_PARSE_ERROR_CPP( "Missing , between the elements" );
                    ptr = skipSpaces( ptr + 1, new_min_indent, INT_MAX );
                    if (!ptr)
                        CV_PARSE_ERROR_CPP("Invalid input");
                }

                if( struct_type == FileNode::MAP )
                {
                    ptr = parseKey( ptr, node, elem );
                    ptr = skipSpaces( ptr, new_min_indent, INT_MAX );
                }
                else
                {
                    if( *ptr == ']' )
                        break;
                    elem = fs->addNode(node, std::string(), FileNode::NONE);
                }
                ptr = parseValue( ptr, elem, new_min_indent, true );
            }
            fs->finalizeCollection(node);
        }
        else
        {
            int indent, struct_type;

            if( is_parent_flow || c != '-' )
            {
                // implicit (one-line) string or nested block-style collection
                if( !is_parent_flow )
                {
                    if( c == '?' )
                        CV_PARSE_ERROR_CPP( "Complex keys are not supported" );
                    if( c == '|' || c == '>' )
                        CV_PARSE_ERROR_CPP( "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 == FileNode::STRING));

                if( endptr == ptr )
                    CV_PARSE_ERROR_CPP( "Invalid character" );

                if( is_parent_flow || c != ':' )
                {
                    char* str_end = endptr;
                    // strip spaces in the end of string
                    do c = *--str_end;
                    while( str_end > ptr && c == ' ' );
                    str_end++;
                    node.setValue(FileNode::STRING, ptr, (int)(str_end - ptr));
                    ptr = endptr;
                    return ptr;
                }
                struct_type = FileNode::MAP;
            }
            else
                struct_type = FileNode::SEQ;

            fs->convertToCollection( struct_type, node );
            indent = (int)(ptr - fs->bufferStart());

            for(;;)
            {
                FileNode elem;

                if( struct_type == FileNode::MAP )
                {
                    ptr = parseKey( ptr, node, elem );
                }
                else
                {
                    c = *ptr++;
                    if( c != '-' )
                        CV_PARSE_ERROR_CPP( "Block sequence elements must be preceded with \'-\'" );

                    elem = fs->addNode(node, std::string(), FileNode::NONE);
                }
                ptr = skipSpaces( ptr, indent + 1, INT_MAX );
                ptr = parseValue( ptr, elem, indent + 1, false );
                ptr = skipSpaces( ptr, 0, INT_MAX );
                if( ptr - fs->bufferStart() != indent )
                {
                    if( ptr - fs->bufferStart() < indent )
                        break;
                    else
                        CV_PARSE_ERROR_CPP( "Incorrect indentation" );
                }
                if( memcmp( ptr, "...", 3 ) == 0 )
                    break;
            }
            fs->finalizeCollection(node);
        }

        return ptr;
    }

Project: opencv
File: persistence_json.cpp

    char* parseSeq( char* ptr, FileNode& node )
    {
        if (!ptr)
            CV_PARSE_ERROR_CPP( "ptr is NULL" );

        if ( *ptr != '[' )
            CV_PARSE_ERROR_CPP( "'[' - left-brace of seq is missing" );
        else
            ptr++;

        fs->convertToCollection(FileNode::SEQ, node);

        for (;;)
        {
            ptr = skipSpaces( ptr );
            if( !ptr || !*ptr )
                break;

            if ( *ptr != ']' )
            {
                FileNode child = fs->addNode(node, std::string(), FileNode::NONE );

                if ( *ptr == '[' )
                    ptr = parseSeq( ptr, child );
                else if ( *ptr == '{' )
                    ptr = parseMap( ptr, child );
                else
                    ptr = parseValue( ptr, child );
            }

            ptr = skipSpaces( ptr );
            if( !ptr || !*ptr )
                break;

            if ( *ptr == ',' )
                ptr++;
            else if ( *ptr == ']' )
                break;
            else
                CV_PARSE_ERROR_CPP( "Unexpected character" );
        }

        if (!ptr)
            CV_PARSE_ERROR_CPP("ptr is NULL");

        if ( *ptr != ']' )
            CV_PARSE_ERROR_CPP( "']' - right-brace of seq is missing" );
        else
            ptr++;

        fs->finalizeCollection(node);
        return ptr;
    }

Project: opencv
File: persistence_yml.cpp

    char* parseKey( char* ptr, FileNode& map_node, FileNode& value_placeholder )
    {
        if (!ptr)
            CV_PARSE_ERROR_CPP("Invalid input");

        char c;
        char *endptr = ptr - 1, *saveptr;

        if( *ptr == '-' )
            CV_PARSE_ERROR_CPP( "Key may not start with \'-\'" );

        do c = *++endptr;
        while( cv_isprint(c) && c != ':' );

        if( c != ':' )
            CV_PARSE_ERROR_CPP( "Missing \':\'" );

        saveptr = endptr + 1;
        do c = *--endptr;
        while( c == ' ' );

        ++endptr;
        if( endptr == ptr )
            CV_PARSE_ERROR_CPP( "An empty key" );

        value_placeholder = fs->addNode(map_node, std::string(ptr, endptr - ptr), FileNode::NONE);
        ptr = saveptr;

        return ptr;
    }

Project: opencv
File: persistence_xml.cpp

    void write(const char* key, const char* str, bool quote)
    {
        char buf[CV_FS_MAX_LEN*6+16];
        char* data = (char*)str;
        int i, len;

        if( !str )
            CV_Error( CV_StsNullPtr, "Null string pointer" );

        len = (int)strlen(str);
        if( len > CV_FS_MAX_LEN )
            CV_Error( CV_StsBadArg, "The written string is too long" );

        if( quote || len == 0 || str[0] != '\"' || str[0] != str[len-1] )
        {
            bool need_quote = quote || len == 0;
            data = buf;
            *data++ = '\"';
            for( i = 0; i < len; i++ )
            {
                char c = str[i];

                if( (uchar)c >= 128 || c == ' ' )
                {
                    *data++ = c;
                    need_quote = true;
                }
                else if( !cv_isprint(c) || c == '<' || c == '>' || c == '&' || c == '\'' || c == '\"' )
                {
                    *data++ = '&';
                    if( c == '<' )
                    {
                        memcpy(data, "lt", 2);
                        data += 2;
                    }
                    else if( c == '>' )
                    {
                        memcpy(data, "gt", 2);
                        data += 2;
                    }
                    else if( c == '&' )
                    {
                        memcpy(data, "amp", 3);
                        data += 3;
                    }
                    else if( c == '\'' )
                    {
                        memcpy(data, "apos", 4);
                        data += 4;
                    }
                    else if( c == '\"' )
                    {
                        memcpy( data, "quot", 4);
                        data += 4;
                    }
                    else
                    {
                        sprintf( data, "#x%02x", (uchar)c );
                        data += 4;
                    }
                    *data++ = ';';
                    need_quote = 1;
                }
                else
                    *data++ = c;
            }
            if( !need_quote && (cv_isdigit(str[0]) ||
                                str[0] == '+' || str[0] == '-' || str[0] == '.' ))
                need_quote = true;

            if( need_quote )
                *data++ = '\"';
            len = (int)(data - buf) - !need_quote;
            *data++ = '\0';
            data = buf + (int)!need_quote;
        }

        writeScalar( key, data );
    }

Project: opencv
File: persistence_xml.cpp

    void writeComment(const char* comment, bool eol_comment)
    {
        FStructData& current_struct = fs->getCurrentStruct();
        int len;
        int multiline;
        const char* eol;
        char* ptr;

        if( !comment )
            CV_Error( CV_StsNullPtr, "Null comment" );

        if( strstr(comment, "--") != 0 )
            CV_Error( CV_StsBadArg, "Double hyphen \'--\' is not allowed in the comments" );

        len = (int)strlen(comment);
        eol = strchr(comment, '\n');
        multiline = eol != 0;
        ptr = fs->bufferPtr();

        if( multiline || !eol_comment || fs->bufferEnd() - ptr < len + 5 )
            ptr = fs->flush();
        else if( ptr > fs->bufferStart() + current_struct.indent )
            *ptr++ = ' ';

        if( !multiline )
        {
            ptr = fs->resizeWriteBuffer( ptr, len + 9 );
            sprintf( ptr, "<!-- %s -->", comment );
            len = (int)strlen(ptr);
        }
        else
        {
            strcpy( ptr, "<!--" );
            len = 4;
        }

        fs->setBufferPtr(ptr + len);
        ptr = fs->flush();

        if( multiline )
        {
            while( comment )
            {
                if( eol )
                {
                    ptr = fs->resizeWriteBuffer( ptr, (int)(eol - comment) + 1 );
                    memcpy( ptr, comment, eol - comment + 1 );
                    ptr += eol - comment;
                    comment = eol + 1;
                    eol = strchr( comment, '\n' );
                }
                else
                {
                    len = (int)strlen(comment);
                    ptr = fs->resizeWriteBuffer( ptr, len );
                    memcpy( ptr, comment, len );
                    ptr += len;
                    comment = 0;
                }
                fs->setBufferPtr(ptr);
                ptr = fs->flush();
            }
            sprintf( ptr, "-->" );
            fs->setBufferPtr(ptr + 3);
            fs->flush();
        }
    }

Project: opencv
File: persistence_yml.cpp

    void writeComment(const char* comment, bool eol_comment)
    {
        if( !comment )
            CV_Error( CV_StsNullPtr, "Null comment" );

        int len = (int)strlen(comment);
        const char* eol = strchr(comment, '\n');
        bool multiline = eol != 0;
        char* ptr = fs->bufferPtr();

        if( !eol_comment || multiline ||
            fs->bufferEnd() - ptr < len || ptr == fs->bufferStart() )
            ptr = fs->flush();
        else
            *ptr++ = ' ';

        while( comment )
        {
            *ptr++ = '#';
            *ptr++ = ' ';
            if( eol )
            {
                ptr = fs->resizeWriteBuffer( ptr, (int)(eol - comment) + 1 );
                memcpy( ptr, comment, eol - comment + 1 );
                fs->setBufferPtr(ptr + (eol - comment));
                comment = eol + 1;
                eol = strchr( comment, '\n' );
            }
            else
            {
                len = (int)strlen(comment);
                ptr = fs->resizeWriteBuffer( ptr, len );
                memcpy( ptr, comment, len );
                fs->setBufferPtr(ptr + len);
                comment = 0;
            }
            ptr = fs->flush();
        }
    }

Project: opencv
File: persistence_yml.cpp

    bool parse( char* ptr )
    {
        if (!ptr)
            CV_PARSE_ERROR_CPP("Invalid input");

        bool first = true;
        bool ok = true;
        FileNode root_collection(fs->getFS(), 0, 0);

        for(;;)
        {
            // 0. skip leading comments and directives  and ...
            // 1. reach the first item
            for(;;)
            {
                ptr = skipSpaces( ptr, 0, INT_MAX );
                if( !ptr || *ptr == '\0' )
                {
                    ok = !first;
                    break;
                }

                if( *ptr == '%' )
                {
                    if( memcmp( ptr, "%YAML", 5 ) == 0 &&
                        memcmp( ptr, "%YAML:1.", 8 ) != 0 &&
                        memcmp( ptr, "%YAML 1.", 8 ) != 0)
                        CV_PARSE_ERROR_CPP( "Unsupported YAML version (it must be 1.x)" );
                    *ptr = '\0';
                }
                else if( *ptr == '-' )
                {
                    if( memcmp(ptr, "---", 3) == 0 )
                    {
                        ptr += 3;
                        break;
                    }
                    else if( first )
                        break;
                }
                else if( cv_isalnum(*ptr) || *ptr=='_')
                {
                    if( !first )
                        CV_PARSE_ERROR_CPP( "The YAML streams must start with '---', except the first one" );
                    break;
                }
                else if( fs->eof() )
                    break;
                else
                    CV_PARSE_ERROR_CPP( "Invalid or unsupported syntax" );
            }

            if( ptr )
                ptr = skipSpaces( ptr, 0, INT_MAX );
            if( !ptr || !ptr[0] )
                break;
            if( memcmp( ptr, "...", 3 ) != 0 )
            {
                // 2. parse the collection
                FileNode root_node = fs->addNode(root_collection, std::string(), FileNode::NONE);

                ptr = parseValue( ptr, root_node, 0, false );
                if( !root_node.isMap() && !root_node.isSeq() )
                    CV_PARSE_ERROR_CPP( "Only collections as YAML streams are supported by this parser" );

                // 3. parse until the end of file or next collection
                ptr = skipSpaces( ptr, 0, INT_MAX );
                if( !ptr )
                    break;
            }

            if( fs->eof() )
                break;
            ptr += 3;
            first = false;
        }

        return ok;
    }

Project: opencv
File: persistence_xml.cpp

    virtual ~XMLParser() {}

Project: opencv
File: persistence_yml.cpp

    YAMLParser(FileStorage_API* _fs) : fs(_fs)
    {
    }

Project: opencv
File: persistence_xml.cpp

    void endWriteStruct(const FStructData& current_struct)
    {
        writeTag( current_struct.tag.c_str(), CV_XML_CLOSING_TAG );
    }

Project: opencv
File: persistence_xml.cpp

Ptr<FileStorageParser> createXMLParser(FileStorage_API* fs)
{
    return makePtr<XMLParser>(fs);
}

Project: opencv
File: persistence_json.cpp

    char* parseKey( char* ptr, FileNode& collection, FileNode& value_placeholder )
    {
        if (!ptr)
            CV_PARSE_ERROR_CPP("Invalid input");

        if( *ptr != '"' )
            CV_PARSE_ERROR_CPP( "Key must start with \'\"\'" );

        char * beg = ptr + 1;

        do {
            ++ptr;
            CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP();
        } while( cv_isprint(*ptr) && *ptr != '"' );

        if( *ptr != '"' )
            CV_PARSE_ERROR_CPP( "Key must end with \'\"\'" );

        const char * end = ptr;
        ptr++;
        ptr = skipSpaces( ptr );
        if( !ptr || !*ptr )
            return 0;

        if( *ptr != ':' )
            CV_PARSE_ERROR_CPP( "Missing \':\' between key and value" );

        /* [beg, end) */
        if( end <= beg )
            CV_PARSE_ERROR_CPP( "Key is empty" );

        value_placeholder = fs->addNode(collection, std::string(beg, (size_t)(end - beg)), FileNode::NONE);
        return ++ptr;
    }

Project: opencv
File: persistence_xml.cpp

    void startNextStream()
    {
        fs->puts( "\n<!-- next stream -->\n" );
    }

Project: opencv
File: persistence_json.cpp

    virtual ~JSONEmitter() {}

Project: opencv
File: persistence_yml.cpp

    virtual ~YAMLParser() {}

Project: opencv
File: persistence_yml.cpp

    virtual ~YAMLEmitter() {}

Project: opencv
File: persistence_json.cpp

    virtual ~JSONParser() {}

Project: opencv
File: persistence_json.cpp

    void write( const char* key, double value )
    {
        char buf[128];
        writeScalar( key, fs::doubleToString( buf, value, true ));
    }

Project: opencv
File: persistence_json.cpp

    void writeScalar(const char* key, const char* data)
    {
        size_t key_len = 0u;
        if( key && *key == '\0' )
            key = 0;
        if ( key )
        {
            key_len = strlen(key);
            if ( key_len == 0u )
                CV_Error( CV_StsBadArg, "The key is an empty" );
            else if ( static_cast<int>(key_len) > CV_FS_MAX_LEN )
                CV_Error( CV_StsBadArg, "The key is too long" );
        }

        size_t data_len = 0u;
        if ( data )
            data_len = strlen(data);

        FStructData& current_struct = fs->getCurrentStruct();
        int struct_flags = current_struct.flags;
        if( FileNode::isCollection(struct_flags) )
        {
            if ( (FileNode::isMap(struct_flags) ^ (key != 0)) )
                CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
                         "or add element with key to sequence" );
        } else {
            fs->setNonEmpty();
            struct_flags = FileNode::EMPTY | (key ? FileNode::MAP : FileNode::SEQ);
        }

        // start to write
        char* ptr = 0;

        if( FileNode::isFlow(struct_flags) )
        {
            int new_offset;
            ptr = fs->bufferPtr();
            if( !FileNode::isEmptyCollection(struct_flags) )
                *ptr++ = ',';
            new_offset = static_cast<int>(ptr - fs->bufferStart() + key_len + data_len);
            if( new_offset > fs->wrapMargin() && new_offset - current_struct.indent > 10 )
            {
                fs->setBufferPtr(ptr);
                ptr = fs->flush();
            }
            else
                *ptr++ = ' ';
        }
        else
        {
            if ( !FileNode::isEmptyCollection(struct_flags) )
            {
                ptr = fs->bufferPtr();
                *ptr++ = ',';
                *ptr++ = '\n';
                *ptr++ = '\0';
                fs->puts( fs->bufferStart() );
                fs->setBufferPtr(fs->bufferStart());
            }
            ptr = fs->flush();
        }

        if( key )
        {
            if( !cv_isalpha(key[0]) && key[0] != '_' )
                CV_Error( CV_StsBadArg, "Key must start with a letter or _" );

            ptr = fs->resizeWriteBuffer( ptr, static_cast<int>(key_len) );
            *ptr++ = '\"';

            for( size_t i = 0u; i < key_len; i++ )
            {
                char c = key[i];

                ptr[i] = c;
                if( !cv_isalnum(c) && c != '-' && c != '_' && c != ' ' )
                    CV_Error( CV_StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" );
            }

            ptr += key_len;
            *ptr++ = '\"';
            *ptr++ = ':';
            *ptr++ = ' ';
        }

        if( data )
        {
            ptr = fs->resizeWriteBuffer( ptr, static_cast<int>(data_len) );
            memcpy( ptr, data, data_len );
            ptr += data_len;
        }

        fs->setBufferPtr(ptr);
        current_struct.flags &= ~FileNode::EMPTY;
    }

Project: opencv
File: persistence_xml.cpp

    virtual ~XMLEmitter() {}

Project: opencv
File: persistence_yml.cpp

    void endWriteStruct(const FStructData& current_struct)
    {
        char* ptr;

        int struct_flags = current_struct.flags;

        if( FileNode::isFlow(struct_flags) )
        {
            ptr = fs->bufferPtr();
            if( ptr > fs->bufferStart() + current_struct.indent && !FileNode::isEmptyCollection(struct_flags) )
                *ptr++ = ' ';
            *ptr++ = FileNode::isMap(struct_flags) ? '}' : ']';
            fs->setBufferPtr(ptr);
        }
        else if( FileNode::isEmptyCollection(struct_flags) )
        {
            ptr = fs->flush();
            memcpy( ptr, FileNode::isMap(struct_flags) ? "{}" : "[]", 2 );
            fs->setBufferPtr(ptr + 2);
        }
        /*
        if( !FileNode::isFlow(parent_flags) )
            fs->struct_indent -= CV_YML_INDENT + FileNode::isFlow(struct_flags);
        assert( fs->struct_indent >= 0 );*/
    }

Project: opencv
File: persistence_yml.cpp

    void writeScalar(const char* key, const char* data)
    {
        int i, keylen = 0;
        int datalen = 0;
        char* ptr;

        FStructData& current_struct = fs->getCurrentStruct();

        int struct_flags = current_struct.flags;

        if( key && key[0] == '\0' )
            key = 0;

        if( FileNode::isCollection(struct_flags) )
        {
            if( (FileNode::isMap(struct_flags) ^ (key != 0)) )
                CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
                         "or add element with key to sequence" );
        }
        else
        {
            fs->setNonEmpty();
            struct_flags = FileNode::EMPTY | (key ? FileNode::MAP : FileNode::SEQ);
        }

        if( key )
        {
            keylen = (int)strlen(key);
            if( keylen == 0 )
                CV_Error( CV_StsBadArg, "The key is an empty" );

            if( keylen > CV_FS_MAX_LEN )
                CV_Error( CV_StsBadArg, "The key is too long" );
        }

        if( data )
            datalen = (int)strlen(data);

        if( FileNode::isFlow(struct_flags) )
        {
            ptr = fs->bufferPtr();
            if( !FileNode::isEmptyCollection(struct_flags) )
                *ptr++ = ',';
            int new_offset = (int)(ptr - fs->bufferStart()) + keylen + datalen;
            if( new_offset > fs->wrapMargin() && new_offset - current_struct.indent > 10 )
            {
                fs->setBufferPtr(ptr);
                ptr = fs->flush();
            }
            else
                *ptr++ = ' ';
        }
        else
        {
            ptr = fs->flush();
            if( !FileNode::isMap(struct_flags) )
            {
                *ptr++ = '-';
                if( data )
                    *ptr++ = ' ';
            }
        }

        if( key )
        {
            if( !cv_isalpha(key[0]) && key[0] != '_' )
                CV_Error( CV_StsBadArg, "Key must start with a letter or _" );

            ptr = fs->resizeWriteBuffer( ptr, keylen );

            for( i = 0; i < keylen; i++ )
            {
                char c = key[i];

                ptr[i] = c;
                if( !cv_isalnum(c) && c != '-' && c != '_' && c != ' ' )
                    CV_Error( CV_StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" );
            }

            ptr += keylen;
            *ptr++ = ':';
            if( !FileNode::isFlow(struct_flags) && data )
                *ptr++ = ' ';
        }

        if( data )
        {
            ptr = fs->resizeWriteBuffer( ptr, datalen );
            memcpy( ptr, data, datalen );
            ptr += datalen;
        }

        fs->setBufferPtr(ptr);
        current_struct.flags &= ~FileNode::EMPTY;
    }

Project: opencv
File: persistence_json.cpp

    void startNextStream()
    {
        fs->puts( "...\n" );
        fs->puts( "---\n" );
    }

Project: opencv
File: persistence_json.cpp

    void write(const char* key, const char* str, bool quote)
    {
        char buf[CV_FS_MAX_LEN*4+16];
        char* data = (char*)str;
        int i, len;

        if( !str )
            CV_Error( CV_StsNullPtr, "Null string pointer" );

        len = (int)strlen(str);
        if( len > CV_FS_MAX_LEN )
            CV_Error( CV_StsBadArg, "The written string is too long" );

        if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') )
        {
            int need_quote = 1;
            data = buf;
            *data++ = '\"';
            for( i = 0; i < len; i++ )
            {
                char c = str[i];

                switch ( c )
                {
                case '\\':
                case '\"':
                case '\'': { *data++ = '\\'; *data++ = c;   break; }
                case '\n': { *data++ = '\\'; *data++ = 'n'; break; }
                case '\r': { *data++ = '\\'; *data++ = 'r'; break; }
                case '\t': { *data++ = '\\'; *data++ = 't'; break; }
                case '\b': { *data++ = '\\'; *data++ = 'b'; break; }
                case '\f': { *data++ = '\\'; *data++ = 'f'; break; }
                default  : { *data++ = c; }
                }
            }

            *data++ = '\"';
            *data++ = '\0';
            data = buf + !need_quote;
        }

        writeScalar( key, data);
    }