2010-07-06 18 views
7

Así que aquí está el problema, estoy leyendo un archivo de nivel de mi juego, funciona bien en Linux:fread/ftell aparentemente roto bajo Windows, funciona bien en Linux

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

Pero debajo de las ventanas me sale el siguiente resultado:

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

¿Uh? Las ventanas muestran estadísticas con un desplazamiento de 200? La lectura del archivo aparentemente produce los mismos datos, pero fread usa (?) El valor de ftell para determinar cuántos bytes quedan en el archivo que se pueden leer. Así que por supuesto que estoy corriendo en problemas cuando se lee al final del archivo:

@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. 

Este es el código correspondiente (en la actualidad un poco feo debido a todas las impresiones de depuración ..):

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; 
} 

Realmente no tengo ni idea de lo que está pasando aquí. Los compiladores son Visual Studio 10 one y GCC 4.4 bajo Linux.

Respuesta

20

Abra el archivo en modo binario:

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

En el modo de texto, puede haber traducciones pasando para que coincida con la codificación del sistema operativo depende de, por ejemplo, alimentaciones de línea a la biblioteca de C.

+0

Uh ..... mi cerebro debe haber recibido daño grave en los últimos días debido al calor ... -.- "Funciona ahora, gracias! –

4

ftell y fseek sólo se va a trabajar como desplazamientos de bytes si se abre el archivo en modo binario, (es decir, en lugar de "rb""r"). De lo contrario, solo puede fseek a cosas que previamente han sido devueltas por ftell; el resultado de fseek no va a ser un desplazamiento de bytes.

El modo binario hace una diferencia en las ventanas donde el modo de texto asigna el retorno de carro de dos caracteres, la secuencia de alimentación de línea a un solo carácter de nueva línea. No se necesita mapeo en Linux.

+0

Eso funcionó, aunque todavía me parece un poco extraño que fread simplemente confíe en el valor de ftell. Pero queda una pregunta, ¿por qué? ¿utiliza el primer byte (C8) en el archivo como un desplazamiento? –

0

No se debe utilizar ftell y fseek para determinar el tamaño de un archivo, ya que podría ser la fuente de vurnerabilities:

https://www.securecoding.cert.org/confluence/display/c/FIO19-C.+Do+not+use+fseek%28%29+and+ftell%28%29+to+compute+the+size+of+a+regular+file

+0

El contenido se movió a https://www.securecoding.cert.org/confluence/display/c/FIO19-C.+Do+not+use+fseek % 28% 29+ y + ftell% 28% 29 + to + compute + the + size + of + a + regular + file – dnet

+0

Ok Cambié la URL – Joakim

Cuestiones relacionadas