c# XmlReader with base64 innertext
Ok here is my problem. I am trying to take a screenshot, add it to an xmldocument, send it over a socket, and read it with a XmlReader.
Here's some code...
Server Side
private void SendRandomData(object data)
{
XMLShitSock sock = data as XMLShitSock;
if(sock != null)
{
int incnum = 0;
while(sock.Connected)
{
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);
XmlNode productsNode = doc.CreateElement("image");
productsNode.InnerText = Convert.ToBase64String(Program.CaptureImageToBytes(new Point(0, 0), new Rectangle(0, 0, Screen.PrimaryScreen.WorkingArea.Width, Screen.PrimaryScreen.WorkingArea.Height), ImageFormat.Png));
doc.AppendChild(productsNode);
string s = XMLShitSock.GetXmlString(doc);
doc.Save("temp.xml");
sock.WriteXMLMessage(doc);
incnum++;
Thread.Sleep(5000);
}
}
}
sock.WriteXMLMessage
public bool WriteXMLMessage(XmlDocument doc)
{
try
{
ShittySocket.Client.Send(Encoding.ASCII.GetBytes(GetXmlString(doc)));
return true;
}
catch(SocketException se)
{
this.Close();
return false;
}
}
To Read input
private void doInput()
{
MemoryStream ms = new MemoryStream();
NetworkStream ns = new NetworkStream(ShittySocket.Client, false);
while(_connected)
{
if(ns.DataAvailable)
{
StreamReader sr = new StreamReader(ns);
char[] b = new char[512];
int nread = sr.Read(b, 0, 512);
ms.Write(System.Text.Encoding.ASCII.GetBytes(b, 0, nread), 0, nread);
ms.Seek(0, System.IO.SeekOrigin.Begin);
XmlReaderSettings xrs = new XmlReaderSettings();
XmlReader reader = XmlReader.Create(ms);
if(reader.Read())
{
XmlDocument objXmlDocument = new XmlDocument();
objXmlDocument.Load(reader);
onInput(this, objXmlDocument);
ms.Close();
ms = new MemoryStream();
}
}
Thread.Sleep(100);
}
}
Problem I'm having is I get an error in doInput() saying the end of the document was reached without find the tag. I saved the xml file and looked through it and it exists, and I didn't even find any < characters beside开发者_StackOverflows those in the actual tags, so I'm not sure what's going on here. I'm obviously missing something.
Also, if you have concerns with the semantics or coding style, or anything that doesn't actually answer the question, please leave it as a comment, since it's not an answer.
Also I've look through this ->> http://msdn.microsoft.com/en-us/library/system.xml.xmltextreader.readbase64.aspx and I'm hoping that there is a better way to deal with base64 data than separating it from the XMLDocument itself. Thanks.
It looks like you're assuming the entire data will be read in one 512-byte chunk. Therefore, if the actual data is, say, 513 bytes long then you won't get the closing angle bracket > at the end of the document, thus the XML parser fails.
I don't know exactly what type of network stream you're using but if it's plain vanilla sockets then you need some kind of delimiter to know when you've reached the end of one "send" and the start of the next, because vanilla sockets are just a pipeline of data. With one read you could be receiving half, one, two, three-and-a-bit actual blocks.
Handily, you have a delimiter in the form of the closing tag.
Two things regarding doInput()
:
XmlReaderSettings xrs = new XmlReaderSettings();
is not needed since you don't use it in subsequentXmlReader.Create()
. And there would be no need to unless you set some properties of it first.You can't assume that
reader.Read()
read the whole xml right there. WithXmlReader
you have to doRead()
until you getfalse
in response.
It's also a good idea to using(var reader = XmlReader.Create(...)) { ... }
so everything is nicely wrapped up when it's done reading.
try
ms.Position = 0;
instead of
ms.Seek(0, System.IO.SeekOrigin.Begin);
in doInput()
also you can try to replace
Encoding.ASCII
with
Encoding.UTF8
or just replace a lot of code with just:
private void doInput()
{
NetworkStream ns = new NetworkStream(ShittySocket.Client, false);
while (_connected)
{
if (ns.DataAvailable)
{
using (StreamReader sr = new StreamReader(ns, System.Text.Encoding.UTF8))
{
XmlDocument objXmlDocument = new XmlDocument();
objXmlDocument.LoadXml(sr.ReadToEnd());
onInput(this, objXmlDocument);
}
}
Thread.Sleep(100);
}
}
Ok so I've came up with a solution. Here's the function
public static XmlDocument GrabXmlDocFromStream(StreamReader reader)
{
using(MemoryStream ms = new MemoryStream())
{
byte b = 0;
while(!reader.EndOfStream)
{
b = (byte)reader.Read();
ms.WriteByte(b);
ms.Seek(0, System.IO.SeekOrigin.Begin);
using(XmlReader xmlreader = XmlReader.Create(ms))
{
XmlDocument doc = new XmlDocument();
try
{
if(Encoding.ASCII.GetChars(new byte[1] { b })[0] == '>')
{
if(xmlreader.Read())
{
XmlDocument objXmlDocument = new XmlDocument();
objXmlDocument.Load(xmlreader);
return objXmlDocument;
}
}
}
catch(XmlException xe) { }
}
}
}
return null;
}
You use it like this
using(NetworkStream ns = new NetworkStream(ShittySocket.Client, false))
{
using(StreamReader sr = new StreamReader(ns))
{
XmlDocument xdoc = new XmlDocument();
while(xdoc != null)
{
xdoc = Program.GrabXmlDocFromStream(sr);
if(xdoc != null)
Program.Handle_Document(xdoc);
}
}
}
Here are the other two function mentioned in the code
public static string GetXmlString(XmlDocument doc)
{
StringWriter sw = new StringWriter();
XmlTextWriter xw = new XmlTextWriter(sw);
doc.WriteTo(xw);
return sw.ToString();
}
public static void Handle_Document(XmlDocument doc)
{
MessageBox.Show(GetXmlString(doc));
}
This probably isn't the best solution, but I used the line if(Encoding.ASCII.GetChars(new byte[1] { b })[0] == '>') so that I don't get an exception every character. From what I understand using try-catch in this manner isn't exactly the "right" way to solve problems, but it works, and I think I can suffer the minor time penalty involved. Any ideas would be nice, if you see something wrong with this let me know. Thanks.
精彩评论