Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   Leer DWORDs invertidos (https://www.clubdelphi.com/foros/showthread.php?t=92542)

aguml 22-11-2017 21:44:45

Leer DWORDs invertidos
 
Hola amigos, cuando se lee un int de un archivo binario se pasa al int invertido, osea que si en el archivo vemos 21 33 55 44 y leo esa memoria a un int se pasa como 0x44553321. La cuestion es que quiero leerlo como 0x21335544 y no tengo ni idea de como hacer eso. ¿alguien sabria ayudarme?

escafandra 23-11-2017 07:08:57

Cita:

Empezado por aguml (Mensaje 522786)
Hola amigos, cuando se lee un int de un archivo binario se pasa al int invertido, osea que si en el archivo vemos 21 33 55 44 y leo esa memoria a un int se pasa como 0x44553321. La cuestion es que quiero leerlo como 0x21335544 y no tengo ni idea de como hacer eso. ¿alguien sabria ayudarme?

Eso no siempre es así, depende de la arquitectura del procesador. Me temo que tendrás que cambiar las posiciones a mano, o leer byte a byte. El problema lo vas a tener en los cast por lo que tendrás que pensar bien que quieres hacer, porqué, como y cuando.

Saludos

aguml 23-11-2017 07:56:18

Se me ocurre algo así:
Código PHP:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    
int valor=0x12345678;
    
int i;
    
char cadena[11];
    
char aux[3];
    
sprintf(cadena,"0x%X",valor);
    
printf("%s\n",cadena);
    for(
i=2;i<6;i+=2){
        
strncpy(aux,&cadena[i],2);
        
strncpy(&cadena[i],&cadena[8-(i-2)], 2);
        
strncpy(&cadena[8-(i-2)],aux,2);
    }
    
printf("%s\n",cadena);
    
valor=atoi(cadena);
    
printf("%x\n",valor);
    return 
0;


Solo que atoi no me devuelve un valor bueno aunque quiero hacerlo con AnsiString y tiene su método ToInt() y podría usar SubString en lugar de strncpy pero tengo que ver cómo adaptarlo. El fallo que veo es que trabajar con strings es lento en comparación con trabajar con números.
Otra opción que se me ocurre es leer del fichero 4 bytes como char[4] y luego convertir con algún Cast esos 4 bytes en un entero ¿Con eso obtendría el valor invertido? ¿Cómo se haría ese Cast?

escafandra 23-11-2017 09:27:26

No entiendo que tengas que usar cambios a cadenas de caracteres, ¿Te interesan los datos en caracteres o numéricos?

Saludos.

aguml 23-11-2017 12:57:26

A ver si me explico, este archivo es leido por la PS3 y es donde se guarda la partida de un juego en concreto. La empresa que ha creado el juego lo ha protegido con un checksum que por lo visto se llama DWADD que no es mas que ir sumando DWORDs del archivo uno detras de otro en un rango especifico y el valor obtenido es el checksum el cual lo guarda en otra parte del archivo para saber si ha sido modificado. El problema me lo encontré con que mi checksum no tenia nada que ver con el correcto y despues de muchas vueltas alguien me dijo ;) que el modo en que se lee la memoria depende de la arquitectura del procesador y me dije ¿y si la ps3 lo hace al reves?
O sea, si miras en binario el archivo verias algo como
11 22 33 44 55 66 77 88
Si lees dos dwords obtendrias:
0x44332211
0x88776655
Al menos en mi pc es asi.
Pues bien, la suma al final si que era invirtiendolo con lo que quedarian como:
0x11223344
0x55667788
Lo he conseguido con esta pequeña funcion que me he creado para esto:
Código PHP:

int TForm1::InvertirValor(int valor)
{
    
union{
        
int valor;
        
unsigned char cadena[5];
    }
u;
    
int aux;

    
u.valor=valor;

    
aux u.cadena[0];
    
u.cadena[0]=u.cadena[3];
    
u.cadena[3]=aux;

    
aux=u.cadena[1];
    
u.cadena[1]=u.cadena[2];
    
u.cadena[2]=aux;

    return 
u.valor;
}
//--------------------------------------------------------------------------- 

Con eso consigo lo que quiero, primero invirtiendo cada DWORD que leo y luego, antes de guardar el checksum en el archivo invierto tambien el checksum para que se guarde correctamente y con eso va perfecto.
De todos modos soy todo oidos.

escafandra 23-11-2017 13:43:48

Si, esa puede ser una forma de hacerlo pero en la unión que usas, la parte de cadena deben ser 4 uchar y no 5 que son 32 bits, el tamaño de int.

Otra forma es usar funciones que ya tenemos disponibles como htonl de la librería Winsock2 y que está disañada para compatibilizar los sistemas en red (Little Endian a Big Endian)


Saludos.

aguml 24-11-2017 18:10:55

¿Podrías poner algún ejemplo de uso de htonl?
No lo había escuchado nunca pero la verdad es que para algo tan trivial tener que añadir toda una librería...
Una duda que tengo es si podría hacerlo de otra manera que sería leer, con la misma unión pero usando la cadena, directamente con FileRead cogiendo como cadena de 4 bytes y al leer el int que hay en la unión ya estaría invertido o tendría que invertirlo igualmente.

escafandra 24-11-2017 18:56:09

Cita:

Empezado por aguml (Mensaje 522879)
¿Podrías poner algún ejemplo de uso de htonl?
No lo había escuchado nunca pero la verdad es que para algo tan trivial tener que añadir toda una librería...

Realmente solo debes incluir el archivo cabera Winsock2.h y usar htonl normalmente. Convierte un ulong (DWORD) Little Endian a Big Endian.
Código PHP:

DWORD htonl(DWORD little); 

Cita:

Empezado por aguml (Mensaje 522879)
Una duda que tengo es si podría hacerlo de otra manera que sería leer, con la misma unión pero usando la cadena, directamente con FileRead cogiendo como cadena de 4 bytes y al leer el int que hay en la unión ya estaría invertido o tendría que invertirlo igualmente.

Eso no funciona, el procesador siempre interpretará lo mismo.


Saludos.

aguml 27-11-2017 14:56:31

Ok gracias.

Ñuño Martínez 29-11-2017 18:46:43

Digo yo que leer byte a byte y usar operadores de bit funcionará, ¿no?

A ver si me acuerdo de cómo era la cosa esta:
[edito] He releido la pregunta:
Código:

  int i;
  long Valor;
  FILE *ElArchivo;

  for (i = 0, Valor = 0; i < 4; ++i)
    Valor = (Valor << 8) | (getc (ElArchivo) & 0x000000FF);

Era así, ¿no?

escafandra 29-11-2017 23:17:19

Cita:

Empezado por Ñuño Martínez (Mensaje 523003)
Digo yo que leer byte a byte y usar operadores de bit funcionará, ¿no?

A ver si me acuerdo de cómo era la cosa esta:
[edito] He releido la pregunta:
Código:

  int i;
  long Valor;
  FILE *ElArchivo;

  for (i = 0, Valor = 0; i < 4; ++i)
    Valor = (Valor << 8) | (getc (ElArchivo) & 0x000000FF);

Era así, ¿no?

Falta abrir el archivo (fopen), supongo que es omisión deliberada. El trabajo con desplazamiento de bits claro que funciona.

Saludos.


La franja horaria es GMT +2. Ahora son las 10:57:28.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi