2

I am writing a binary file in C# using the BinaryWriter class

using (var b = new System.IO.BinaryWriter(System.IO.File.Open("C:\\TextureAtlas0.txa", 
       System.IO.FileMode.Create)))
{
  int count;

  // Write the number of source rectangle entries
  count = textureAtlas.Rectangles.Count;

  b.Write(count);

  for (int i = 0; i < count; ++i)
  {
    b.Write(textureAtlas.SpriteNames[i]);
    b.Write(textureAtlas.Rectangles[i].X);
    b.Write(textureAtlas.Rectangles[i].Y);
    b.Write(textureAtlas.Rectangles[i].Width);
    b.Write(textureAtlas.Rectangles[i].Height);
  }
}

I then try and read the same file into C++ using the following steps.

I have a struct that holds the data in the same order it was written.

struct TextureAtlasEntry 
{
    std::string name;
    int x;
    int y;
    int width;
    int height;
};

The count is read first

int count;

fread(&count, sizeof(int), 1, LoadFile);

I then attempt to use the count value to determine the list size that will hold the data. I can't seem to use an array as the value for count will be different depending on the file that is read.

std::list<TextureAtlasEntry> entries;
fread(&entries, sizeof(TextureAtlasEntry), count, LoadFile);

fclose(LoadFile);

The code above does not work. I can get the count to be read correctly but the memcpy command causes an access violation with fread and the entries list.

How can I read the data correctly and should I swap fread with a C++ equivalent?

EDIT:

I can now read the entire binary file into memory using the following code

ifstream::pos_type size;
char *memblock;

ifstream file ("TextureAtlas0.txa", ios::in|ios::binary|ios::ate);

if (file.is_open())
{
    size = file.tellg();
    memblock = new char[size];
    file.seekg (0, ios::beg);
    file.read (memblock, size);
    file.close();

    printf("File content is in memory");

    delete[] memblock;
}
else 
{
    printf("Unable to open file");
}

Now the file is in memory, how do I convert the char[] data into struct data?

2
  • 1
    have you tried using a fixed sized buffer to store the name, as opposed to a string? Commented Sep 6, 2012 at 23:04
  • Do you mean using textureAtlas.SpriteNames[i].ToCharArray() in C#? That doesn't work for me. Commented Sep 7, 2012 at 0:54

2 Answers 2

2

According to the documentation, BinaryWriter(String) writes...

A length-prefixed string represents the string length by prefixing to the string a single byte or word that contains the length of that string. This method first writes the length of the string as a UTF-7 encoded unsigned integer, and then writes that many characters to the stream by using the BinaryWriter instance's current encoding.

In your C++ code, you are just trying to read in a number of bytes the size of your struct, which is a different format than BinaryWriter uses.

Are you using .NET for the C++ code? If so, just use the BinaryReader class to read in the file instead.

If not, you'll have to split up the read a little bit. When you are ready to read the name, you'll first have to read a "UTF-7 encoded unsigned integer", then read that many more bytes to get the string.

EDIT

Based on your comment below, it seems you will not be using C++.NET, so I think you have two options. 1) Write out the data in C# in a way you will be able to read it into C++ (using fixed-length strings) 2) Figure out the way BinaryWriter.Write() writes the data so you can read it properly in C++.

Pseudocode - I think it's something like this. Like I said in a comment below, my C++ is rusty, but this is basic algorithm should be close.

read from file int num - number of items
for (i=0;i<num;i++){
   read int stringBytes - size of string
   read string stringBytes bytes - the name
   read int X4
   create your struct and add to list/array/dictionary
}
Sign up to request clarification or add additional context in comments.

3 Comments

What is the meaning of the ^ symbol in that documentation? e.g. FileStream^
BinaryWriter uses mscorlib. This will not be cross platform in its current form.
The FileStream^ is syntax specific to C++.NET. I haven't used C++.NET very much, but basically it's a "handle" to a managed data type. See en.wikipedia.org/wiki/C++/CLI#Handles
0

Rather than a string data type problem explained in another answer, here is one more thing. std::list is a doubly linked list which contains extra pointers by nature, so direct fread/memcpy probably doesn't give you what you have stored in c# snippet.

5 Comments

My C++ is a little rusty, but what I was intending in my answer was to read each of the elements separately to create the struct, and then appending the struct to the list, instead of reading them directly into the list<struct>, which obviously wont work.
@AndrewR I hope you got the point why they won't work as you thought.
Reading each of the elements individually makes sense. Should I use std::vector instead of std::list?
@user1423893 depends on your purpose
Well ideally I would like to end up with a std::map of std::string for key entries and rectangles (x, y, width, height) for the elements.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.