views:

1196

answers:

4

I'm writing a custom .NET serializer in C# and want to read and write Array objects to XML using XmlReader and XmlWriter. I would like to base64-encode the Array. The arrays may be 1-, 2- or 3-dimensional and the elements are bool or numeric types.

I'm completely stumped. XmlReader and XmlWriter have methods for reading/writing Byte[] arrays as base64 but I can't figure out how to get from an Array to a Byte[] and back.

The arrays could be large so I would prefer a solution that does not involve copying the array or processing one element at a time. Unsafe code and managed or native C++ are fine. I could use something other than base64 if it is safe for XML.

Thanks for any help or hints.

A: 

You will have different options, depending on what kind of 'Array' you are using. Is it an Array, List<>, or ArrayList?

For List<>, you can use CopyTo() to grab parts of your List and put them into a binary array, which you could then write using XmlWriter. To read them back from the XmlReader, you can then simply use InsertRange to de-serialize the data.

A Reading Example:

// elsewhere
List<byte> bytes;

// in the deserialization
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize]; 
int index = 0;
int numRead = -1;

while (numRead != 0) // actually read stuff
{
    numRead = reader.ReadContentAsBase64(buffer,  bufferSize);
    if (numRead > 0)
    {
        bytes.CopyTo(buffer, index, numRead);
        index += numRead;
    }
}

Note: code above is not tested, but is probably close. You can do something similar, but in reverse, for encoding and writing the data to base64. For other types, you simply need to convert your array into a list of bytes.

To get other types than bytes into a byte array, you'll need to use System.BitConverter. This has two methods that will make you very happy: GetBytes which converts any basic data type into a byte array, and ToXxx, which includes ToInt32 and ToBoolean. You'll be responsible for doing that conversion yourself after you've read in the base64 information or before you write it out.

You can use BitConverter to do the per-bit conversion to a set of bytes, but it's up to you to design an algorithm for converting your arrays to a single byte array and back.

Robert P
It is a System.Array, such as byte[] or int[,].What do you mean by a "binary array"? How would I write that with XmlWriter?
Kent Johnson
See updated example. :)
Robert P
Ah, 'numeric or boolean types'. You'll then need to convert that to some byte based array before you write it out.
Robert P
Reading and writing byte[] is directly supported by XmlReader and XmlWriter, so that is not problematic. What if the source is int[] or byte[,] (2-d array)?
Kent Johnson
Also, consider using .NET's built in Xml Serialization: http://stackoverflow.com/questions/496488/xmlserialization-collection-as-array Would save you a ton of hassle. :)
Robert P
A: 

If you need a single array represented by a single XML element containing Base-64 text, the easiest way would probably be to use a BinaryFormatter to turn your data (array of any number of dimensions, List, whatever) into a byte array, and then simply base-64 encode that and stick it in your XML file. I can't think of any other easy way of turning arbitrary arrays into byte arrays.

Joel Mueller
Yes, I think that might be the best solution. Unfortunately it requires copying the array to the BinaryFormatter output which I would prefer to avoid.
Kent Johnson
A: 

A quick summary of what I ended up doing: For serialization, I use a BinaryWriter to write individual elements to a byte array wrapped in a MemoryStream. I break up the writing into small chunks so the MemoryStream array stays small. Write the chunks as individual XML elements with base64-encoded text contents.

Deserialization is pretty much the reverse; the base64 chunks are decoded to a byte array; the byte array is wrapped by a Memory stream and read by a BinaryReader to push the elements into a result array.

Kent Johnson
A: 

If you use the XmlSerializer you can specify the XmlElementAttribute with the DataType property set to "base64Binary" in a property of type byte[]. See here.