0

I'm using XmlReader to parse a XML document. One of the nodes contains base64 encoded data and I want to decode it. This is what I do:

byte[] buffer = new byte[4096];
int readBytes = 0;
using (FileStream outputFile = File.OpenWrite (path))
using (BinaryWriter bw = new BinaryWriter (outputFile)) {
    while ((readBytes = reader.ReadElementContentAsBase64 (buffer, 0, 4096)) > 0) {
        bw.Write (buffer, 0, readBytes);
    }
}

But the file is empty and has a file size of 0 kB. I also tried this without success:

byte[] buffer = new byte[4096];
int readBytes = 0;
FileStream outputFile = new FileStream (path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write);
BinaryWriter bw = new BinaryWriter (outputFile);
while ((readBytes = reader.ReadElementContentAsBase64 (buffer, 0, 4096)) > 0) {
    bw.Write (buffer, 0, readBytes);
}
outputFile.Close ();

I don't understand it. readBytes isn't empty so the data is here. If I temporary save the stream as file and convert it then it works (so I don't use ReadElementContentAsBase64). I'm using Xamarin Studio on Mac for this and this code is embedded into a dll.

Am I doing something wrong or is this a bug? I had the problem that the decoding doesn't work correctly, but an empty file? What can be the reason for this? What can I check for?

Edit:

Now I tried it without the BinaryWriter, but the file has still a size of 0 kB. Here you can see the implementation with the reader:

public async string CallWS(string path, CancellationToken cancelToken)
{
    XmlDocument soapEnvelop = new XmlDocument();
    soapEnvelop.LoadXml(someXMLDoc);

    HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(webserviceAddress);
    webRequest.Headers.Add("SOAPAction", "http://schemas.xmlsoap.org/soap/envelope");
    webRequest.ContentType = "text/xml;charset=\"utf-8\"";
    webRequest.Accept = "text/xml";
    webRequest.Method = "POST";

    using (Stream stream = webrequest.GetRequestStream())
    {
        soapEnvelop.Save(stream);
    }

    using (var response = await webRequest.GetResponseAsync ())
    using (Stream stream = response.GetResponseStream ())
    return parser.GetDocument(stream, path);
}

public string GetDocument(Stream stream, string path)
{
    // read xml and save file
    using (XmlReader reader = XmlReader.Create(stream))
    {
        while (reader.Read())
        {
            if (reader.IsStartElement() && reader.NodeType == XmlNodeType.Element)
            {
                switch (reader.Name)
                {
                    case "Document":
                        reader.ReadToDescendant("cKey");
                        string ckey = reader.ReadInnerXml();
                        switch (ckey)
                        {
                            case "base64Content":
                                reader.ReadToNextSibling("cValue");
                                byte[] buffer = new byte[4096];
                                int readBytes = 0;
                                using (FileStream outputFile = File.OpenWrite(path))
                                {
                                    while ((readBytes = reader.ReadElementContentAsBase64(buffer, 0, 4096)) > 0)
                                    {
                                        outputFile.Write(buffer, 0, readBytes);
                                    }
                                }

                                break;
                            default:
                                break;
                        }

                        break;
                    default:
                        break;
                }
            }
        }
    }

    return path;
}
Community
  • 1
  • 1
testing
  • 19,681
  • 50
  • 236
  • 417
  • We have no idea where the `reader` comes from. Please show a short but complete program demonstrating the problem, bearing in mind that we really don't need to see what you *do* with the results, beyond showing their correctness as simply as possible. – Jon Skeet May 08 '15 at 14:30
  • Additionally, it's not clear why you're using a `BinaryWriter` at all... why not just write to the stream? – Jon Skeet May 08 '15 at 14:30
  • I used the `BinaryWriter` because it was in the [example](https://msdn.microsoft.com/en-us/library/system.xml.xmlreader.readelementcontentasbase64%28v=vs.110%29.aspx). I updated my question to show you the *reader*. I'm getting a stream into this function. If you need I could show some more details about the stream. Thanks for your help! – testing May 15 '15 at 09:29
  • That's still a long way from being a short but complete program demonstrating the problem... – Jon Skeet May 15 '15 at 09:31
  • OK, now the edited question should be more complete. Let me know if you still need something. – testing May 15 '15 at 09:50
  • Nope, that's still not a short but complete program. Ideally, I'd like to see a console app with a Main method, along with a sample XML file (as simple as you can make it.) You don't actually need to call the web service in the sample code - just show what its response is. – Jon Skeet May 15 '15 at 09:51

3 Answers3

0

It seems as though there's something broken (or at least, inconsistent with .Net on Windows) with ReadElementContentAsBase64 on Xamarin.iOS. From your earlier question it appears that FromBase64Transform is available in your environment, so give this a try, it produces the same result as the ReadElementContentAsBase64 algorithm on Windows:

        // Advance to the text value of the element.
        if (reader.NodeType == XmlNodeType.Element)
            reader.Read();
        // But make sure there is text value!
        if (reader.NodeType == XmlNodeType.Text)
        {
            var charBuffer = new char[4096];
            using (var fileStream = File.OpenWrite(path))
            using (var transform = new FromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces))
            using (var cryptoStream = new CryptoStream(fileStream, transform, CryptoStreamMode.Write))
            using (var bufferedStream = new BufferedStream(cryptoStream, charBuffer.Length))
            {
                int charRead;
                while ((charRead = reader.ReadValueChunk(charBuffer, 0, charBuffer.Length)) != 0)
                {
                    for (int i = 0; i < charRead; i++)
                        bufferedStream.WriteByte(checked((byte)charBuffer[i]));
                }
            }
            Debug.WriteLine("Wrote " + path);
        }
dbc
  • 104,963
  • 20
  • 228
  • 340
0

When dealing with WRITERS there is a useful method FLUSH which sends the data to the underlying STREAM. I don't know if it will help in this case, but it is worth trying.

Brcinho
  • 321
  • 5
  • 10
  • Interesting. For a short time the had it's correct file size, but then it changed to zero again. – testing May 15 '15 at 10:22
0

Now I tried to save the file in another directory, but in the old directory there has been written at the same time. So I've gone through my code from the beginning and found the problem:

I was writing an empty string to the same path after the XMLReader has done its work. Ouch!

Now the file is written correctly, but with wrong content (that's the bug). Thank you all who tried to help me!

testing
  • 19,681
  • 50
  • 236
  • 417