Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

does not support files in big endian [feature] [willing to help] #9

Open
ifeelagood opened this issue Mar 17, 2024 · 5 comments
Open

Comments

@ifeelagood
Copy link

The game in question is PS3/XB360 Skate 3

Bad header magic! Expected: 0x50464478, Got: 0x78444650, which is clearly due to the generation of consoles being big endian.

I suggest adding another flag to read in big endian.

I am willing to add this myself.

@xan1242
Copy link
Owner

xan1242 commented Mar 17, 2024

It's a duplicate of this issue: #7

I simply didn't have the time to add it in yet.

I'd like to rework the codebase eventually into something a bit more split up and also go from a custom format to a JSON wherever possible.

Nevertheless, adding in byteswaps to the file IO operations shouldn't be too hard. (Although I'm contemplating to also go from standard C file funcs to C++ fstream)

But as it is right now, it does still work so it's not a big problem. All it needs is a shim for fread/fwrite that can byteswap AFAIR.

Also no need for a explicit flag (except maybe for a forced read). It can be easily autodetected from the header magic as you can tell.

Feel free to submit a pull request if you wanna add in byteswaps yourself. I can do the reworks later.

@2banditos
Copy link

I'm following the project with great interest. Hope to handle big endian files soon with this gerat tool

@ifeelagood
Copy link
Author

I simply didn't have the time to add it in yet.

I wrote some pretty overly-complex shit code a couple weeks ago but here it is. Completely untested. I identified already that adding fread and fwrite functions was the way to go. Feel free to gut it for me and gut me.

endianess.h

#pragma once

#include <stdio.h>
#include <cstdint>

#include "bswap.h" // bswap_16, bswap_32, bswap_64

enum class ENDIANNESS { BIG, LITTLE };

inline ENDIANNESS host_byteorder_le(); // Quake 3 swaptest

struct EndianContext
{
	EndianContext(ENDIANNESS target_endian);
	ENDIANNESS host;   // Endianness of the host machine
	ENDIANNESS target; // Endianness of the target machine
};

size_t fread_endian(void* ptr, size_t size, size_t count, FILE* stream, EndianContext& context);
size_t fwrite_endian(const void* ptr, size_t size, size_t count, FILE* stream, EndianContext& context);

endianess.cpp

#include "endianness.h"

ENDIANNESS host_byteorder_le()
{
	int8_t swaptest[2] = { 1,0 };
	return (*(int16_t*)swaptest == 1) ? ENDIANNESS::LITTLE : ENDIANNESS::BIG;
}

EndianContext::EndianContext(ENDIANNESS target_endian)
	: host(host_byteorder_le()), target(target_endian)
{
}

size_t fread_endian(void* ptr, size_t size, size_t count, FILE* stream, EndianContext& context)
{
	size_t n = fread(ptr, size, count, stream);
	if (context.host != context.target)
	{
        for (size_t i = 0; i < n; i++)
        {
            auto cast_ptr = reinterpret_cast<uint8_t*>(ptr) + i * size;
            switch (size)
            {
                case sizeof(uint16_t) :
                    *reinterpret_cast<uint16_t*>(cast_ptr) = bswap_16(*reinterpret_cast<uint16_t*>(cast_ptr));
                    break;
                case sizeof(uint32_t) :
                    *reinterpret_cast<uint32_t*>(cast_ptr) = bswap_32(*reinterpret_cast<uint32_t*>(cast_ptr));
                     break;
                case sizeof(uint64_t) :
                     *reinterpret_cast<uint64_t*>(cast_ptr) = bswap_64(*reinterpret_cast<uint64_t*>(cast_ptr));
                     break;
            }
        }
	}
	return n;
}

size_t fwrite_endian(const void* ptr, size_t size, size_t count, FILE* stream, EndianContext& context)
{
    if (context.host != context.target) 
    {
        void* buffer = malloc(size * count);
        if (!buffer) 
        {
            fprintf(stderr, "Failed to allocate memory for fwrite_endian.\n");
            return 0;
        }

        memcpy(buffer, ptr, size * count);

        for (size_t i = 0; i < count; i++)
        {
            auto cast_ptr = reinterpret_cast<uint8_t*>(buffer) + i * size;
            switch (size)
            {
                case sizeof(uint16_t) :
                    *reinterpret_cast<uint16_t*>(cast_ptr) = bswap_16(*reinterpret_cast<uint16_t*>(cast_ptr));
                    break;
                case sizeof(uint32_t) :
                    *reinterpret_cast<uint32_t*>(cast_ptr) = bswap_32(*reinterpret_cast<uint32_t*>(cast_ptr));
                    break;
                case sizeof(uint64_t) :
                    *reinterpret_cast<uint64_t*>(cast_ptr) = bswap_64(*reinterpret_cast<uint64_t*>(cast_ptr));
                    break;
            }
        }

        size_t n = fwrite(buffer, size, count, stream);
        free(buffer);
        return n;
    }
    else 
    {
        return fwrite(ptr, size, count, stream);
    }
}

told you

@2banditos
Copy link

@ifeelagood i have zero programming skills man :)

@2banditos
Copy link

@ifeelagood Bro could you add your code with the big endian support to exe file and send it to me? Would be awesome daniel.sul [at] hotmail.de

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants