Caracteres estranhos no arquivo XML (da entrada do usuário?)
-
25-09-2019 - |
Pergunta
Ei pessoal, eu tenho um aplicativo que salva dados usando XML. Recentemente, recebi um relatório de bug de um usuário que não consegue abrir seu arquivo de dados. O analisador aparentemente falhou quando encontrou um caráter ruim.
Felizmente, tenho uma cópia do arquivo de dados dela, por isso pude encontrar o culpado, mas não entendo o que é ou como chegou lá. (Como tudo isso é a entrada do teclado do usuário.) Os caracteres ofensivos são:
attributeName="Some text then XXX"
Onde está o "xxx", de acordo com um editor hexadecimal:
0A 0A 00
O 0A é um feed de linha, tanto quanto eu sei, mas como diabos um personagem nulo acabaria lá?! Este é o primeiro bug que eu já vi dessa natureza.
Solução
Eu acho que o problema que você está vendo é um pouco conhecido, mas uma falha muito séria no XML. Em poucas palavras: os valores XML não podem conter certos caracteres, e não apenas eles não podem estar no texto XML, mas também não podem ser escapados usando &#dddd; notação.
O Charset XML válido pode ser encontrado aqui: http://www.w3.org/tr/rec-xml/#charsets, e é: #x9 | #xa | #xd | [#x20-#xd7ff] | [#xe000-#xfffd] | [#x10000-#x10ffff].
Isso significa que, se sua string tiver algum caractere não incluído neste charset, ela não poderá ser serializada no valor XML. A única maneira de armazenar essa string é serializar -a no Base64 como dados binários.
Muitas estruturas populares, incluindo MSXML e .NET, permitiriam colocar dados ruins nos valores XML e, em seguida, se recusariam a desserializar esse XML. Aqui está um exemplo, captura de tela: http://vvcap.net/db/db94w-13uwcknxsztito.htp, e código -fonte:
using System;
using System.Xml.Serialization;
using System.Xml;
[Serializable] public class TestClass
{
[XmlAttribute]
public string Member { get; set; }
}
class Program
{
static void Main(string[] args)
{
var ser = new XmlSerializer(typeof(TestClass));
var tc = new TestClass() { Member = "zzz \x19 zzz" };
var stream = new System.IO.StringWriter();
ser.Serialize(stream, tc);
var xml = stream.ToString();
var stream2 = new System.IO.StringReader(stream.ToString());
var tc2 = ser.Deserialize(stream2);
}
}