views:

39

answers:

2

So here's the problem, I'm reading a level file for my game, works fine under linux:

@0
@12
200x200 version 3
@16
973 blocks
@989
@993
18 zones

But under windows I get the following result:

@0
@212
200x200 version 3
@216
973 blocks
@1200
@1204
18 zones

Uh? The windows ftell stats with an offset of 200? Reading the file apparently yields the same data, but fread uses(?) the value of ftell to determine the how many bytes are left in the file that can be read. So of course I'm running into problems when reading at the end of the file:

@1425
zone#9 2x3 @ 66/9
@1425
zone#10 2x3 @ 66/9
@1425
zone#11 2x3 @ 66/9
@1425
zone#12 2x3 @ 66/9
@1425
zone#13 2x3 @ 66/9
@1425
zone#14 2x3 @ 66/9
etc.

This is the corresponding code(currently a bit ugly due to all the debug prints..):

void fread_all(void *ptr, size_t size, size_t count, FILE *stream) {
    fread(ptr, size, count, stream);
    printf("@%ld\n", ftell(stream));
}


bool map_load(struct Map *map, const char *file_name) {
    FILE *fp = fopen(file_name, "r");
    if (fp != NULL) {
        fseek(fp, 0, SEEK_SET);
        printf("@%ld\n", ftell(fp));

        // Header
        int *header = (int*)calloc(sizeof(int), 3);
        fread_all(header, sizeof(int), 3, fp);
        printf("%dx%d version %d\n", header[0], header[1], header[2]);

        map->pos_x = 0;
        map->pos_y = 0;
        map->map_x = 0;
        map->map_y = 0;
        map->size_x = header[0];
        map->size_y = header[1];
        map_zones_remove(map);        
        free(header);

        // Blocks
        unsigned int *block_size = (unsigned int*)malloc(sizeof(unsigned int));
        fread_all(block_size, sizeof(int), 1, fp);
        printf("%d blocks\n", *block_size);

        unsigned char *block_data = (unsigned char*)calloc(sizeof(unsigned char), *block_size);
        fread_all(block_data, sizeof(unsigned char), *block_size, fp);

        unsigned char *tmp = map->blocks;
        map->blocks = rle_decode(block_data, *block_size);
        free(tmp);
        free(block_size);
        free(block_data);

        // Zones
        int *zone_count = (int*)malloc(sizeof(int));
        fread_all(zone_count, sizeof(int), 1, fp);
        printf("%d zones\n", *zone_count);

        int *d = (int*)calloc(sizeof(int), 6);
        for(int i = 0, l = *zone_count; i < l; i++) {
            fread_all(d, sizeof(int), 6, fp);
            map_zone_create(map, d[0], d[1], d[2], d[3], d[4], d[5]);
            printf("zone#%d %dx%d @ %d/%d\n", i, d[2], d[3], d[0], d[1]);
        }
        map_platforms_create(map);

        free(zone_count);
        free(d);
        fclose(fp);
        return true;
    }
    return false;
}

I really have no clue what's going on here. Compilers are the Visual Studio 10 one and GCC 4.4 under Linux.

+2  A: 

Open your file in binary mode:

FILE *fp = fopen(file_name, "rb");

In text mode, there might be translations going on to match the operating system-dependent encoding of e.g. line feeds to the C library's.

unwind
Uh..... my brain must have taken serious damage in the last days due to the heat... -.-" It works now, thanks!
Ivo Wetzel
+1  A: 

ftell and fseek are only going to work as byte offsets if you open the file in binary mode, (i.e. "rb" instead of "r"). Otherwise you can only fseek to things that have previously be returned by ftell; the result of fseek isn't going to be a byte offset.

Binary mode makes a difference on windows where text mode maps the two character carriage return, line feed sequence to a single new-line character. No mapping is needed on linux.

Charles Bailey
That did the trick, even though I still find it a bit strange that fread simply trusts the value of ftell. But one question remains, why does it use the first byte(C8) in the file as an offset?
Ivo Wetzel