On Mon, Aug 01, 2011 at 08:31:50AM +0200, GOUJON Alexandre wrote:
Sorry to disturb your conversation but the subject is worth discussing.
I'm currently trying to add UDF support on wine based on Steven Wallace work. Quoting the specification : "On the media the UDF structures are stored little endian" as windows API. But wine is not limited on x86 so what's the rule ? Currently, my code is
int i = 1; char *p = (char *)&i; BOOL isBigEndian = p[0]==1; /* Tag location (Uint32) at offset 12, little-endian */ *offs = (bloc[20+0] & 0xFF) << ( isBigEndian ? 0 : 24); *offs += (bloc[20+1] & 0xFF) << ( isBigEndian ? 8 : 16); *offs += (bloc[20+2] & 0xFF) << ( isBigEndian ? 16 : 8); *offs += (bloc[20+3] & 0xFF) << ( isBigEndian ? 24 : 0);
Is it correct ?
Depends what the data you are playing with is.... But it looks a bit dubious to me.
Any thoughts ?
1) You want endianness to be a compile time constant, not run time. 2) If that code is trying to read a 32bit LE value from a disk sector it is wrong. 3) If you care how fast the code runs, don't repeatedly write through a pointer.
If you have 'unsigned char bloc[]' and want to read a 32 bit LE value you can do: value = bloc[20 + 0]; value |= bloc[20 + 1] << 8; value |= bloc[20 + 2] << 16; value |= bloc[20 + 3] << 24; *offs = value; And that is correct on all architectures.
To write a LE value use: buf[0] = value; buf[1] = value >>= 8; buf[2] = value >>= 8; buf[3] = value >>= 8;
(For BE reverse the indexes)
If the item is known to be correctly aligned (or the architecture supports mis-aligned reads) then you can just do (eg): value = *(uint32_t *)(bloc + 20); value = le32toh(value); but you'll have to chase around the OS headers to find how to spell le32toh(). If you define a C struct that matches the data area (packed if it might have misaligned data), the compiler will generate the shifts and masks to read a native word - so you only need the le32toh() macro. (le32toh() is from NetBSD, can't remember what Linux calls it!)
It is also worth noting that some architectures (eg ppc) have instructions for reading and writing memory with byteswap, but no instruction for swapping a register. Newer gccs can be taught how to use these instructions for specific source sequences.
David