1

Okay, so I've got a game map creater programmed in Java which writes the map out to file using ObjectOutputStream.writeInt()

Now I'm converting the game engine to C# XNA and I'm trying to load the map. I'm getting numerical errors though, so I'm wondering if anyone knows what I'm doing wrong?

Java writes as int 32 Big Endian I believe (I could be wrong though).

Here is the code I'm using to read the height and width of the map in C#.

Edit: br is BinaryReader.

width = (int)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(br.ReadBytes(sizeof(int)), 0));
height = (int)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(br.ReadBytes(sizeof(int)), 0));

Can anyone please tell me what I'm doing wrong? Or how to read the bytes from ObjectOutputStream.writeInt() properly in C#?

Edit: 2nd try failed. here is the current code:

public byte[] ReadBigEndianBytes(int count, BinaryReader br)
        {
            byte[] bytes = new byte[count];
            for (int i = count - 1; i >= 0; i--)
                bytes[i] = br.ReadByte();

            return bytes;
        }

        public void loadFile(int level)
        {
            FileStream fs = new FileStream("map" + level + ".lv", FileMode.Open, FileAccess.Read);
            BinaryReader br = new BinaryReader(fs, System.Text.Encoding.BigEndianUnicode);

            width =  BitConverter.ToInt32(ReadBigEndianBytes(4, br), 0);
            height = BitConverter.ToInt32(ReadBigEndianBytes(4, br), 0);

            tile = new int[width, height];

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    tile[x, y] = BitConverter.ToInt32(ReadBigEndianBytes(4, br), 0);
                }
            }

        }
    }
CyanPrime
  • 5,096
  • 12
  • 58
  • 79
  • Personally, I would be reading this with shift operators, rather than assuming the machine's endianness. – Marc Gravell Sep 12 '11 at 20:46
  • The BinaryReader has `ReadXXX` methods, for example `BinaryReader.ReadInt32` (http://msdn.microsoft.com/en-us/library/system.io.binaryreader.readint32.aspx), but note that ReadUint32 reads in little-endian – SwDevMan81 Sep 12 '11 at 20:47
  • Here is an example Big-Endian BinaryReader wrapper that has minimal functionality: http://stackoverflow.com/questions/123918/how-can-one-simplify-network-byte-order-conversion-from-a-binaryreader/155297#155297 or Jon Skeet's MiscUtils EndianBinaryReader (http://www.yoda.arachsys.com/csharp/miscutil/) – SwDevMan81 Sep 12 '11 at 20:53
  • Tried using the SO one, and it didn't work, but the other one's src is so big I dunno where to begin. – CyanPrime Sep 12 '11 at 21:08

3 Answers3

2
ObjectOutputStream.writeInt()

Don't use that. Use DataOutputStream.writeInt(). It does the same thing, in network byte order, but it doesn't add the Serialziation header that ObjectOutputStream adds, so you won't have to skip it at the .NET end.

user207421
  • 305,947
  • 44
  • 307
  • 483
1

Absolutely correct:

Java writes as int 32 Big Endian I believe (I could be wrong though).

Remember, though: a .Net Int32 is Little-Endian ;)

[Edit] SOLUTION:

1) Here is Java code that writes 10 integers (Java int's are 32-bit, Big-endian))


    import java.io.*;

    public class WriteBinary {

      public static void main (String[] args) {
        int[] data = {
          1, 2, 3, 4, 5, 6, 7, 8, 9, 10
        };

        String fname = "myfile.bin";
        try
        {
          System.out.println("Opening " + fname + "...");      
          FileOutputStream fos = 
            new FileOutputStream(fname);
          int ibyte;
          for (int i = 0; i < data.length; i++) {
            ibyte = ((data[i] >>> 24) & 0xff); fos.write(ibyte);
            ibyte = ((data[i] >>> 16) & 0xff); fos.write(ibyte);
            ibyte = ((data[i] >>> 8) & 0xff); fos.write(ibyte);
            ibyte = (data[i] & 0xff); fos.write(ibyte);
          }
          fos.close();
          System.out.println("File write complete.");      
        }
        catch (IOException e) {
          System.out.println ("I/O error: " + e.getMessage());
        }
      }
    }

2) Here is the C# code that reads it. You'll notice the "using System.Net", in order to get .Net's equivalent of "ntohl()":



using System;
using System.IO;
using System.Net;

namespace ReadBinary
{
    class Program
    {
        static void Main(string[] args)
        {
            string fname = "myfile.bin";
            try
            {
                Console.WriteLine("Opening " + fname + "...");
                BinaryReader br =
                  new BinaryReader(
                        File.Open(fname, FileMode.Open));
                for (int i = 0; i < (int)(br.BaseStream.Length / 4); i++)
                {
                    int j =
                        System.Net.IPAddress.NetworkToHostOrder (br.ReadInt32());
                    Console.WriteLine("array[" + i + "]=" + j + "...");
                }
                br.Close();
                Console.WriteLine("Read complete.");
            }
            catch (IOException ex)
            {
                Console.WriteLine("I/O error" + ex.Message);
            }
        }
    }
}
paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • Actually a .NET `int` isn't really *defined* as either-endian. MS .NET does happen to be little endian pretty much everywhere, but that isn't guaranteed on mono. – Marc Gravell Sep 12 '11 at 20:45
  • Can you give an example of output C# side in what doesn't work in this example? The above code looks dead on for writing the stream. Also, how "garbled" is the input? Are you using ObjectOutputStream (Java side)? My guess here is that you have additional information at the top and bottom of your streams, but without that information I can't really say. ObjectOutputStream is dangerous in this situation. It really should be a standard OutputStream. – Daniel B. Chapman Sep 13 '11 at 15:54
  • @CyanPrime - Please take a look at the code example I added last night. – paulsm4 Sep 13 '11 at 19:17
0

I think a proper way is to use IPAddress.NetworkToHostOrder(Int32) method.

public void loadFile(int level)
    {
        ...

        width =  IPAddress.NetworkToHostOrder(br.ReadInt32());
        height = IPAddress.NetworkToHostOrder(br.ReadInt32());

        ...

    }
emre
  • 73
  • 1
  • 8