Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The input stream is not a valid binary format. The starting contents

I've seen this type of question asked before but not sure what the root cause of the problem was or how to fix it.

I am modifying an existing class to be able to load data into the member variables from flash. Right now, the class loads data from a file through the load function. This function has been overloaded to take in byte array.

The data read back from the flash is put into this byte array.
The error that is thrown is (happens at the line ... = formatter.Deserialize(stream)):

The input stream is not a valid binary format. The starting contents (in bytes) are: 93-E3-E6-3F-C3-F5-E4-41-00-C0-8D-C3-14-EE-4A-C3-00 ...

The interesting thing here is that the contents are exactly the contents of the byte array that is being passed into the stream. In other words, this is the data from the flash and this is exactly what I want serialized. I'm not sure why the error is being thrown.

Or a better question is what is a is a valid binary format for a BinaryFormatter? Does it need a certain size? Is there specific end value needed? Are certain values invalid? The current size of the byte array input is 24 bytes.

Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Media.Imaging;
using System.IO;
using Galileo.Data;
using System.Xml.Serialization;
using System.Reflection;
using System.Runtime.InteropServices;
using UComm;
using System.Runtime.Serialization.Formatters.Binary;
using ULog;

public void Load(byte[] spCalfromPrimary)
{
    try
    {

        Type settingsType = this.GetType();

        object tmp = Activator.CreateInstance(settingsType);
        Stream stream = new MemoryStream();
        stream.Write(spCalfromPrimary, 0, spCalfromPrimary.Length);
        stream.Position = 0;
        BinaryFormatter formatter = new BinaryFormatter();

        //tmp = formatter.Deserialize(stream);
        formatter.Deserialize(stream);            //**<--- throws error here**


        // Use reflection to copy all public properties from the temporary object into this one.                
        PropertyInfo[] properties = settingsType.GetProperties();
        foreach (PropertyInfo property in properties)
        {

            object value = property.GetValue(tmp, null);

            if (value == null)
            {
                throw new FileFormatException("Null value encountered in settings file");
            }
            else
            {
                property.SetValue(this, value, null);
            }
        }
    }
    catch (Exception ex)
    {
        _logger.DebugException("Failed to load spatial cal value from FW", ex);
        Console.WriteLine(ex.Message);
    }

}



// <summary>
/// Loads the setting from file
/// </summary>
public void Load()
{
    Type settingsType = this.GetType();

    XmlSerializer xser = new XmlSerializer(settingsType);
    object tmp = Activator.CreateInstance(settingsType);

    using (StreamReader reader = new StreamReader(_filename)) { tmp = xser.Deserialize(reader); }
    // Use reflection to copy all public properties from the temporary object into this one.                
    PropertyInfo[] properties = settingsType.GetProperties();
    foreach (PropertyInfo property in properties)
    {
        object value = property.GetValue(tmp, null);

        if (value == null)
        {
            throw new FileFormatException("Null value encountered in settings file");
        }
        else
        {
            property.SetValue(this, value, null);
        }
    }
}

Note that I have also tried the a Convert byte array to object function (I found on stackoverflow). When I used this function, an exception was still thrown at .Deserialize(memStream).

// Convert a byte array to an Object
private Object ByteArrayToObject(byte[] arrBytes)
{
    MemoryStream memStream = new MemoryStream();
    BinaryFormatter binForm = new BinaryFormatter();
    memStream.Write(arrBytes, 0, arrBytes.Length);
    memStream.Seek(0, SeekOrigin.Begin);
    Object obj = (Object) binForm.Deserialize(memStream);
    return obj;
}

Apparently I left out some important information.

Serialization happens in a different application from deserialization. Serialization uses a bitconverter to take the data, convert to a byte array and upload it to flash. Let me explain. The data that is being serialized / deserialized & stored in flash is calibration data. Calibration is performed at the factory with Application1 by production. This uses a bitconverter to put every field into a stream and then serialize the stream.

CFlatInterface.FloatToStream(bData, ref i, rtsMappingData.ScaleTrackingDMD);
CFlatInterface.FloatToStream(bData, ref i, rtsMappingData.RotationAngle);
CFlatInterface.FloatToStream(bData, ref i, rtsMappingData.CenterOfRotation.dx);

where the function FloatToStream is defined as:

public static void FloatToStream(byte[] buf, ref int index, float val)
{
    Buffer.BlockCopy(BitConverter.GetBytes(val), 0, buf, index, sizeof(float));
    index += sizeof(float);
}

So every field that makes up the Calibration is put into the stream this way. The data is put into the stream and a byte array is constructed and sent to flash.

On the other side, once the product is out of the factory and in use, Application2 (user application) has a Calibration object that has all the calibration fields. This reads the flash, and gets the data that was written by Application1. Application2 is trying to deserialize the calibration data using BinaryFormatter and the code above. I am coming to the conclusion this is not possible (Thanks Rotem). The correct course of action is to use the same formatter for both serialization / deserialization - i will implement it this way and indicate if that makes a difference.

like image 753
AKT Avatar asked Feb 15 '14 03:02

AKT


1 Answers

Following your update, the obvious issue is that you are serializing and deserializing with different formatters.

BinaryFormatter serializes more than just field data. It also serializes type information and metadata so it knows how to deserialize the objects, so it is expecting more than just raw data bytes as input.

Either use a BinaryFormatter on the serializing end as well, or use a manual deserialization technique on the receiving end.

like image 77
Rotem Avatar answered Oct 21 '22 19:10

Rotem