Chicken-NBT: A Minecraft NBT reader for Chicken Scheme

I didn’t see any Scheme code to read Minecraft NBT data files, so I made one. And in doing so, I see why there weren’t any NBT readers in Scheme. (Haskell programmers can use Adam Foltzer’s much cleaner Haskell version.)

When I found out that there was a gzip egg called z3, I thought my troubles were over. Not quite, because although z3 made it ridiculously easy to read compressed data, the only real procedure I had to read data from the gzip stream was read-byte. And not only did I have to read only one byte at a time, but they were all promoted to ints anyways, since there is no notion of different-width integers in Chicken (only fixnums).

To read a 32-bit int, I read in 4 bytes and reassembled them into a fixnum. To read floats, well…
[clojure]
(define (readFloat)
(let ([c-read-float
(foreign-lambda* float
((int i1)
(int i2)
(int i3)
(int i4))
"uint8_t b1 = (uint8_t) i1;
uint8_t b2 = (uint8_t) i2;
uint8_t b3 = (uint8_t) i3;
uint8_t b4 = (uint8_t) i4;

uint32_t i = 0;

i = b1;
i = (i << 8) | b2;
i = (i << 8) | b3;
i = (i << 8) | b4;

float f = *(float*)&i;

C_return(f);")])
(let* ([i1 (read-byte)]
[i2 (read-byte)]
[i3 (read-byte)]
[i4 (read-byte)])
(c-read-float i1 i2 i3 i4))))
[/clojure]

Not only that, but Chicken seems to compile internal defines incorrectly, and I haven’t been able to figure out if that’s documented anywhere.

Anyways, the code works (for certain values of “works”) now and is on Github: chicken-nbt. Time permitting, I may package it into an egg.

Leave a Reply