Question about reading Milkshape 3D models.

Hey, I have a little problem with reading a binary file. Maybe someone can help me? I hope this topic is OK on this board.

The thing is, I am trying to read a Milkshape ms3d file. I have a C script that does it, but I want to try to port it to Java. I have tried to just read the header so far, and I allready have a problem. In C, the header is read like this. There is a lot more, off course, but I only focus on the header first in hopes of getting that right means the rest will follow:


// Define the struct of the header first:
typedef struct MS3DHeader
{
	char ID[10];
	int version;
}MS3DHEADER;

// Read the whole file into a byte buffer (some code omitted):
byte *pBuffer = malloc(fileSize);
fread(pBuffer, fileSize, 1, file );

// Set a pointer to the buffer:
const byte *pPtr = pBuffer;

// Read the header and move the pointer
MS3DHEADER *pHeader = ( MS3DHEADER* )pPtr;
pPtr += sizeof( MS3DHEADER );

// Now, id and version are accesible through:
pHeader->ID; pHeader->version;


This is the gist of it. I tried to read the file in Java using RandomAccessFile in this way:


// Define a nested class for the header inside the reader class
private final class Ms3dHeader {
    private char[] id;
    private int version;
        
    private Ms3dHeader() {
        id = new char[10];
    }
        
    private String idStr() {
        return new String(id);
    }
}

// Read the header (some code omitted):
file = new RandomAccessFile(filename, "r");

Ms3dHeader head = new Ms3dHeader();
for(int i = 0; i < head.id.length; i++) {
    head.id[i] = (char) ((byte)file.read());
}

head.version = file.readInt();

System.out.println("Head id: " + head.idStr());
System.out.println("Head ver: " + head.version);

Printout is:
Head id: MS3D000000
Head ver: 67108864

Id is correct, but the version is wrong. It should be 4, but as you can see it is 67108864, which is 4 << 24. The readInt() method reads 4 bytes as ints and adds them: (b1 << 24) + (b2 << 16) + (b3 << 8) + b4. And sure enough: When i read the proper 4 bytes from the file, I get 4 0 0 0.

So my question is this: How can I read the int from the file properly, indeed, how can I read the rest properly when int seems to be wrong? The C code apparently gets it right, but I can’t see it being done any other way there. The integer should take up 4 bytes in the C reading as well (at least, it does on my machine). Am I just not understanding the C code properly here or am I reading the file wrong in Java?

I also tried readChar() for the ID, but that also became wrong, so I had to read bytes and convert, and a char is generally 2 bytes (last time I checked). And I also know the byte after 4 should not be 0, because that number is part of an unsigned short representing the number of vertices in the model, and that is not 0.

If anyone have any suggestions / alternate ways of reading, it would be appreciated.

Thanks alot,
Richared

Java likes to read things in in Big endian byte ordering. Your PC is Little endian ordered.

Here’s the doc for readInt()

Basically you need to swap every 2 bytes on input. I’ve done this myself but not in a very clean way. Some expert here might know of a standard way of throwing Java into little endian mode, or some kind of Reader/Input class that does it for you.

Thanks. That really helped.

In case anyone else has this problem, I did some research on the net and found this useful site:

http://mindprod.com/jgloss/endian.html

-r

Heck, that is really useful.

His code is similar to mine, maybe a bit cleaner. I like the history section. I’m definitely a Blefuscudians (big-endian). This is how I comprehend binary numbers, and I suppose most people do as well.

The ByteBuffer trick is neat but seems a bit, uh, clunky. Not to mention potentially expensive looking to a C++ programmer. :slight_smile:

OTOH When I use Milkshape I just export to wavefront OBJ and read those into my app :slight_smile: