
TinyXML 2.6.2 with fixes for CVE-2021-42260 and CVE-2023-34194
/** @mainpage
TinyXML é um parser XML simples, pequeno e em C++ que pode ser facilmente integrado em outros programas.
Em resumo, o TinyXML analisa um documento XML e constrói a partir dele um Modelo de Objeto de Documento (DOM) que pode ser lido, modificado e salvo.
XML significa "eXtensible Markup Language". Ele permite criar suas próprias marcações de documento. Enquanto o HTML faz um trabalho muito bom de marcar documentos para navegadores, o XML permite definir qualquer tipo de marcação de documento, por exemplo, um documento que descreve uma lista de "tarefas" para um aplicativo de organizador. XML é um formato muito estruturado e conveniente. Todos aqueles formatos de arquivo aleatórios criados para armazenar dados de aplicativos podem ser substituídos por XML. Um parser para tudo.
O melhor lugar para a especificação completa, correta e, francamente, difícil de ler está em http://www.w3.org/TR/2004/REC-xml-20040204/. Uma introdução ao XML (que eu realmente gosto) pode ser encontrada em http://skew.org/xml/tutorial.
Existem diferentes maneiras de acessar e interagir com dados XML. O TinyXML usa um Modelo de Objeto de Documento (DOM), o que significa que os dados XML são analisados em objetos C++ que podem ser navegados e manipulados, e depois gravados em disco ou em outro fluxo de saída. Você também pode construir um documento XML do zero com objetos C++ e gravá-lo em disco ou em outro fluxo de saída.
O TinyXML foi projetado para ser fácil e rápido de aprender. São dois cabeçalhos e quatro arquivos cpp. Basta adicioná-los ao seu projeto e pronto. Há um arquivo de exemplo - xmltest.cpp - para você começar.
O TinyXML é lançado sob a licença ZLib, para que você possa usá-lo em código aberto ou comercial. Os detalhes da licença estão no topo de cada arquivo de origem.
O TinyXML tenta ser um parser flexível, mas com saída XML verdadeiramente correta e compatível. O TinyXML deve compilar em qualquer sistema razoavelmente compatível com C++. Ele não depende de exceções ou RTTI. Pode ser compilado com ou sem suporte a STL. O TinyXML suporta totalmente a codificação UTF-8 e as primeiras 64 mil entidades de caracteres.
O TinyXML não analisa nem usa DTDs (Definições de Tipo de Documento) ou XSLs (Linguagem de Folha de Estilo Extensível). Existem outros parsers por aí (confira www.sourceforge.org, procure por XML) que são muito mais completos. Mas eles também são muito maiores, demoram mais para configurar no seu projeto, têm uma curva de aprendizado mais alta e geralmente têm uma licença mais restritiva. Se você está trabalhando com navegadores ou tem necessidades de XML mais completas, o TinyXML não é o parser para você.
A seguinte sintaxe DTD não será analisada neste momento no TinyXML:
@verbatim ]> @endverbatim
porque o TinyXML vê isso como um nó !DOCTYPE com um nó !ELEMENT embutido ilegalmente. Isso pode ser resolvido no futuro.
Para os impacientes, aqui está um tutorial para começar. Uma ótima maneira de começar, mas vale a pena ler este manual (muito curto) completamente.
O TinyXML é um código maduro e testado. É muito estável. Se você encontrar bugs, por favor, registre um relatório de bug no site sourceforge (www.sourceforge.net/projects/tinyxml). Nós os resolveremos o mais rápido possível.
Existem algumas áreas de melhoria; por favor, verifique o sourceforge se você estiver interessado em trabalhar no TinyXML.
Projetos TinyXML que você pode achar úteis! (Descrições fornecidas pelos projetos.)
O TinyXML pode ser compilado para usar ou não usar STL. Ao usar STL, o TinyXML utiliza a classe std::string e suporta totalmente std::istream, std::ostream, operator<< e operator>>. Muitos métodos da API têm ambas as formas 'const char*' e 'const std::string&'.
Quando o suporte a STL é compilado sem ele, nenhum arquivo STL é incluído. Todas as classes de string são implementadas pelo próprio TinyXML. Os métodos da API usam a forma 'const char*' para entrada.
Use a diretiva de compilação #define:
TIXML_USE_STL
para compilar uma versão ou outra. Isso pode ser passado pelo compilador ou definido como primeira linha de "tinyxml.h".
Observação: Ao compilar o código de teste no Linux, definir a variável de ambiente TINYXML_USE_STL=YES/NO controlará a compilação STL. No arquivo de projeto do Windows, são fornecidos alvos STL e não STL. No seu projeto, provavelmente é mais fácil adicionar a linha "#define TIXML_USE_STL" como primeira linha de tinyxml.h.
O TinyXML suporta UTF-8, permitindo manipular arquivos XML em qualquer idioma. O TinyXML também suporta "modo legado" - a codificação usada antes do suporte a UTF-8 e provavelmente melhor descrita como "ascii estendido".
Normalmente, o TinyXML tentará detectar a codificação correta e usá-la. No entanto, definindo o valor de TIXML_DEFAULT_ENCODING no arquivo de cabeçalho, o TinyXML pode ser forçado a usar sempre uma codificação.
O TinyXML assumirá o Modo Legado até que uma das seguintes situações ocorra:
O que acontece se a codificação for definida ou detectada incorretamente? O TinyXML tentará ler e passar texto visto como codificado incorretamente. Você pode obter alguns resultados estranhos ou caracteres distorcidos. Talvez você queira forçar o TinyXML para o modo correto.
Você pode forçar o TinyXML ao Modo Legado usando LoadFile( TIXML_ENCODING_LEGACY ) ou LoadFile( filename, TIXML_ENCODING_LEGACY ). Você pode forçá-lo a usar o modo legado o tempo todo definindo TIXML_DEFAULT_ENCODING = TIXML_ENCODING_LEGACY. Da mesma forma, você pode forçá-lo a TIXML_ENCODING_UTF8 com a mesma técnica.
Para usuários de inglês, usando XML em inglês, UTF-8 é o mesmo que low-ASCII. Você não precisa estar ciente do UTF-8 ou alterar seu código de forma alguma. Você pode pensar no UTF-8 como um "superconjunto" do ASCII.
UTF-8 não é um formato de byte duplo - mas é uma codificação padrão do Unicode! O TinyXML não usa nem suporta diretamente wchar, TCHAR ou _UNICODE da Microsoft neste momento. É comum ver o termo "Unicode" referido incorretamente ao UTF-16, uma codificação de byte largo do Unicode. Isso é uma fonte de confusão.
Para idiomas "high-ASCII" - praticamente tudo que não é inglês - o TinyXML pode lidar com todos os idiomas, ao mesmo tempo, desde que o XML esteja codificado em UTF-8. Isso pode ser um pouco complicado, programas e sistemas operacionais mais antigos tendem a usar a página de código "padrão" ou "tradicional". Muitos aplicativos (e quase todos os modernos) podem gerar UTF-8, mas os mais antigos ou teimosos (ou simplesmente quebrados) ainda geram texto na página de código padrão.
Por exemplo, sistemas japoneses tradicionalmente usam a codificação SHIFT-JIS. Texto codificado como SHIFT-JIS não pode ser lido pelo TinyXML. Um bom editor de texto pode importar SHIFT-JIS e depois salvar como UTF-8.
O link do Skew.org faz um ótimo trabalho cobrindo a questão da codificação.
O arquivo de teste "utf8test.xml" é um XML contendo inglês, espanhol, russo e chinês simplificado. (Espero que estejam traduzidos corretamente). O arquivo "utf8test.gif" é uma captura de tela do arquivo XML, renderizado no IE. Observe que se você não tiver as fontes corretas (chinês simplificado ou russo) no seu sistema, você não verá uma saída que corresponda ao arquivo GIF, mesmo se conseguir analisá-lo corretamente. Observe também que (pelo menos na minha máquina Windows) a saída do console está em uma página de código ocidental, então Print() ou printf() não podem exibir o arquivo corretamente. Isso não é um bug no TinyXML - apenas uma questão de sistema operacional. Nenhum dado é perdido ou destruído pelo TinyXML. O console apenas não renderiza UTF-8.
@verbatim & & < < > > " " ' ' @endverbatim
Elas são reconhecidas quando o documento XML é lido e traduzidas para seus equivalentes UTF-8. Por exemplo, texto com o XML de:
@verbatim Far & Away @endverbatim
terá o Valor() de "Far & Away" quando consultado do objeto TiXmlText, e será escrito de volta no fluxo/arquivo XML como um e comercial. Versões antigas do TinyXML "preservavam" entidades de caractere, mas as versões mais recentes as traduzirão em caracteres.
Além disso, qualquer caractere pode ser especificado por seu ponto de código Unicode: A sintaxe " " ou " " ambos se referem ao caractere de espaço sem quebra.
Print( FILE* ). Saída para um fluxo std-C, que inclui todos os arquivos C, bem como stdout.
operator<<. Saída para um fluxo c++.
TiXmlPrinter. Saída para um std::string ou buffer de memória.
Saída no estilo C: - baseada em FILE* - os métodos Print() e SaveFile()
Gera saída formatada, com bastante espaço em branco, destinada a ser o mais legível possível por humanos. São muito rápidos e tolerantes a documentos XML mal formados. Por exemplo, um documento XML que contém 2 elementos raiz e 2 declarações ainda será impresso.
Entrada no estilo C: - baseada em FILE* - os métodos Parse() e LoadFile()
Uma leitura rápida e tolerante. Use sempre que não precisar dos fluxos C++.
Saída no estilo C++: - baseada em std::ostream - operator<<
Gera saída condensada, destinada à transmissão de rede em vez de legibilidade. Dependendo da implementação da classe ostream do seu sistema, podem ser um pouco mais lentos. (Ou não.) Não tolera XML mal formado: um documento deve conter o elemento raiz correto. Elementos adicionais no nível raiz não serão transmitidos.
Entrada no estilo C++: - baseada em std::istream - operator>>
Lê XML de um fluxo, tornando-o útil para transmissão de rede. A parte complicada é saber quando o documento XML está completo, pois quase certamente haverá outros dados no fluxo. O TinyXML assumirá que os dados XML estão completos após ler o elemento raiz. Em outras palavras, documentos mal construídos com mais de um elemento raiz não serão lidos corretamente. Observe também que operator>> é um pouco mais lento que Parse, devido tanto à implementação da STL quanto às limitações do TinyXML.
É uma questão que não foi resolvida para minha satisfação. O TinyXML suporta as primeiras 2 abordagens. Chame TiXmlBase::SetCondenseWhiteSpace( bool ) para definir o comportamento desejado. O padrão é condensar espaço em branco.
Se você alterar o padrão, deve chamar TiXmlBase::SetCondenseWhiteSpace( bool ) antes de fazer qualquer chamada para analisar dados XML, e não recomendo alterá-lo depois de definido.
Ao navegar em um documento XML de forma robusta, é importante verificar se há retornos nulos de chamadas de método. Uma implementação segura contra erros pode gerar muito código como:
@verbatim TiXmlElement* root = document.FirstChildElement( "Document" ); if ( root ) { TiXmlElement* element = root->FirstChildElement( "Element" ); if ( element ) { TiXmlElement* child = element->FirstChildElement( "Child" ); if ( child ) { TiXmlElement* child2 = child->NextSiblingElement( "Child" ); if ( child2 ) { // Finalmente faça algo útil. @endverbatim
Handles foram introduzidos para limpar isso. Usando a classe TiXmlHandle, o código anterior se reduz a:
@verbatim TiXmlHandle docHandle( &document ); TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); if ( child2 ) { // faça algo útil @endverbatim
O que é muito mais fácil de lidar. Veja TiXmlHandle para mais informações.
O TinyXML pode rastrear a origem de linha e coluna de todos os nós e atributos em um arquivo de texto. Os métodos TiXmlBase::Row() e TiXmlBase::Column() retornam a origem do nó no texto fonte. As tabulações corretas podem ser configuradas em TiXmlDocument::SetTabSize().
Para Compilar e Executar xmltest:
Um Makefile Linux e um arquivo .dsw do Windows Visual C++ são fornecidos. Simplesmente compile e execute. Ele escreverá o arquivo demotest.xml no seu disco e gerará saída na tela. Também testa a navegação pelo DOM imprimindo o número de nós encontrados usando diferentes técnicas.
O makefile Linux é muito genérico e roda em muitos sistemas - atualmente é testado no mingw e MacOSX. Você não precisa executar 'make depend'. As dependências foram codificadas.
PROFILE, DEBUG e TINYXML_USE_STL. Detalhes (tais como são) estão no makefile.
No diretório tinyxml, digite "make clean" e depois "make". O arquivo executável 'xmltest' será criado.
Adicione tinyxml.cpp, tinyxml.h, tinyxmlerror.cpp, tinyxmlparser.cpp, tinystr.cpp e tinystr.h ao seu projeto ou arquivo make. É isso! Deve compilar em qualquer sistema razoavelmente compatível com C++. Você não precisa habilitar exceções ou RTTI para TinyXML.
Um exemplo é provavelmente a melhor maneira. Veja: @verbatim <?xml version="1.0" standalone=no> Vá ao Brinquedos Baratos! Pagar contas @endverbatim
Não é uma grande lista de tarefas, mas serve. Para ler este arquivo (digamos "demo.xml") você criaria um documento e o analisaria: @verbatim TiXmlDocument doc( "demo.xml" ); doc.LoadFile(); @endverbatim
E está pronto. Agora vamos ver algumas linhas e como elas se relacionam com o DOM.
@verbatim
@endverbatim A primeira linha é uma declaração e se torna a classe TiXmlDeclaration. Será o primeiro filho do nó documento. Esta é a única diretiva/tag especial analisada pelo TinyXML. Geralmente, tags de diretiva são armazenadas em TiXmlUnknown para que os comandos não sejam perdidos quando salvos de volta no disco. @verbatim @endverbatim Um comentário. Se tornará um objeto TiXmlComment. @verbatim @endverbatim A tag "ToDo" define um objeto TiXmlElement. Este não possui atributos, mas contém 2 outros elementos. @verbatim @endverbatim Cria outro TiXmlElement que é filho do elemento "ToDo". Este elemento tem 1 atributo, com o nome "priority" e o valor "1". @verbatim Vá ao @endverbatim Um TiXmlText. Este é um nó folha e não pode conter outros nós. É filho do TiXmlElement "Item". @verbatim @endverbatim Outro TiXmlElement, este filho do elemento "Item". Etc. Olhando para toda a árvore de objetos, você termina com: @verbatim TiXmlDocument "demo.xml" TiXmlDeclaration "version='1.0'" "standalone=no" TiXmlComment " Nossos dados da lista de tarefas" TiXmlElement "ToDo" TiXmlElement "Item" Atributos: priority = 1 TiXmlText "Vá ao " TiXmlElement "bold" TiXmlText "Brinquedos Baratos!" TiXmlElement "Item" Atributos: priority=2 TiXmlText "Pagar contas" @endverbatim