mirror of https://github.com/AxioDL/kabufuda.git
Implement format
This commit is contained in:
parent
a2a7386a46
commit
4c2d5e7214
|
@ -1,9 +1,12 @@
|
||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
project(Card)
|
project(kabufuda)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wno-multichar -fno-exceptions")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wno-multichar -fno-exceptions")
|
||||||
include_directories(include)
|
include_directories(include)
|
||||||
|
|
||||||
add_library(card STATIC
|
add_library(kabufuda STATIC
|
||||||
include/Card.hpp src/Card.cpp)
|
include/Card.hpp src/Card.cpp
|
||||||
|
include/Util.hpp src/Util.cpp
|
||||||
|
include/SRAM.hpp src/SRAM.cpp
|
||||||
|
include/WideStringConvert.hpp src/WideStringConvert.cpp)
|
||||||
|
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|
|
@ -3,13 +3,16 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdint.h>
|
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
|
||||||
namespace card
|
#include "Util.hpp"
|
||||||
|
|
||||||
|
namespace kabufuda
|
||||||
{
|
{
|
||||||
uint32_t constexpr BlockSize = 0x2000;
|
uint32_t constexpr BlockSize = 0x2000;
|
||||||
uint32_t constexpr MaxFiles = 127;
|
uint32_t constexpr MaxFiles = 127;
|
||||||
|
uint32_t constexpr FSTBlocks = 5;
|
||||||
|
uint32_t constexpr MbitToBlocks = 0x10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The EPermissions enum
|
* @brief The EPermissions enum
|
||||||
|
@ -52,12 +55,13 @@ enum class ECardSize : uint16_t
|
||||||
*/
|
*/
|
||||||
enum class EEncoding : uint16_t
|
enum class EEncoding : uint16_t
|
||||||
{
|
{
|
||||||
ASCII, /**< Standard ASCII Encoding */
|
ASCII, /**< Standard ASCII Encoding */
|
||||||
SJIS /**< SJIS Encoding for japanese */
|
SJIS /**< SJIS Encoding for japanese */
|
||||||
};
|
};
|
||||||
|
|
||||||
class File
|
class File
|
||||||
{
|
{
|
||||||
|
#pragma pack(push, 4)
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
|
@ -76,42 +80,47 @@ class File
|
||||||
};
|
};
|
||||||
uint8_t __raw[0x40];
|
uint8_t __raw[0x40];
|
||||||
};
|
};
|
||||||
|
#pragma pop()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
File() {}
|
File() {}
|
||||||
File(char data[0x40])
|
File(char data[0x40]);
|
||||||
{
|
File(const char* filename);
|
||||||
memcpy(__raw, data, 0x40);
|
|
||||||
}
|
|
||||||
File(const char* filename)
|
|
||||||
{
|
|
||||||
memset(m_filename, 0, 0x20);
|
|
||||||
memcpy(m_filename, filename, 0x20);
|
|
||||||
}
|
|
||||||
~File() {}
|
~File() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlockAllocationTable
|
class BlockAllocationTable
|
||||||
{
|
{
|
||||||
|
friend class Card;
|
||||||
|
#pragma pack(push, 4)
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint16_t m_checksum;
|
uint16_t m_checksum;
|
||||||
uint16_t m_checksumInv;
|
uint16_t m_checksumInv;
|
||||||
|
uint16_t m_updateCounter;
|
||||||
uint16_t m_freeBlocks;
|
uint16_t m_freeBlocks;
|
||||||
uint16_t m_lastAllocated;
|
uint16_t m_lastAllocated;
|
||||||
uint16_t m_map[0xFFB];
|
uint16_t m_map[0xFFB];
|
||||||
};
|
};
|
||||||
uint8_t __raw[BlockSize];
|
uint8_t __raw[BlockSize];
|
||||||
};
|
};
|
||||||
|
#pragma pop()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BlockAllocationTable() {}
|
explicit BlockAllocationTable(uint32_t blockCount = (uint32_t(ECardSize::Card2043Mb) * MbitToBlocks));
|
||||||
BlockAllocationTable(uint8_t data[BlockSize]);
|
BlockAllocationTable(uint8_t data[BlockSize]);
|
||||||
~BlockAllocationTable() {}
|
~BlockAllocationTable() {}
|
||||||
|
|
||||||
|
uint16_t getNextBlock() const;
|
||||||
|
uint16_t nextFreeBlock(uint16_t maxBlocks, uint16_t startingBlock = FSTBlocks);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Directory
|
class Directory
|
||||||
{
|
{
|
||||||
|
friend class Card;
|
||||||
|
#pragma pack(push, 4)
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
|
@ -124,17 +133,17 @@ class Directory
|
||||||
};
|
};
|
||||||
uint8_t __raw[BlockSize];
|
uint8_t __raw[BlockSize];
|
||||||
};
|
};
|
||||||
|
#pragma pop()
|
||||||
public:
|
public:
|
||||||
Directory() {}
|
Directory();
|
||||||
Directory(uint8_t data[BlockSize])
|
|
||||||
{
|
Directory(uint8_t data[BlockSize]);
|
||||||
memcpy(__raw, data, BlockSize);
|
|
||||||
}
|
|
||||||
~Directory() {}
|
~Directory() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Card
|
class Card
|
||||||
{
|
{
|
||||||
|
#pragma pack(push, 4)
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
|
@ -154,7 +163,8 @@ class Card
|
||||||
};
|
};
|
||||||
uint8_t __raw[BlockSize];
|
uint8_t __raw[BlockSize];
|
||||||
};
|
};
|
||||||
std::string m_filename;
|
#pragma pop()
|
||||||
|
SystemString m_filename;
|
||||||
Directory m_dir;
|
Directory m_dir;
|
||||||
Directory m_dirBackup;
|
Directory m_dirBackup;
|
||||||
Directory* m_dirInUse = nullptr;
|
Directory* m_dirInUse = nullptr;
|
||||||
|
@ -166,13 +176,14 @@ class Card
|
||||||
char m_maker[3] = {'\0'};
|
char m_maker[3] = {'\0'};
|
||||||
void setChecksum(uint16_t checksum)
|
void setChecksum(uint16_t checksum)
|
||||||
{
|
{
|
||||||
m_checksum = (checksum);
|
m_checksum = SBig(checksum);
|
||||||
m_checksumInv = ~checksum;
|
m_checksumInv = SBig(checksum ^ 0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE* m_fileHandle;
|
||||||
public:
|
public:
|
||||||
Card();
|
Card();
|
||||||
Card(const std::string& filepath, const char* game = nullptr, const char* maker=nullptr);
|
Card(const SystemString& filepath, const char* game = nullptr, const char* maker=nullptr);
|
||||||
~Card();
|
~Card();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -216,21 +227,26 @@ public:
|
||||||
void getChecksum(uint16_t* checksum, uint16_t* inverse);
|
void getChecksum(uint16_t* checksum, uint16_t* inverse);
|
||||||
/**
|
/**
|
||||||
* @brief Formats the memory card and assigns a new serial
|
* @brief Formats the memory card and assigns a new serial
|
||||||
* @param size The desired size of the file
|
* @param size The desired size of the file @sa ECardSize
|
||||||
* @param size The desired encoding
|
* @param encoding The desired encoding @sa EEncoding
|
||||||
* @sa ECardSize
|
|
||||||
* @sa EEncoding
|
|
||||||
*/
|
*/
|
||||||
void format(ECardSize size = ECardSize::Card59Mb, EEncoding encoding = EEncoding::ASCII);
|
void format(EDeviceId deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getSizeMbit
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static uint32_t getSizeMbitFromFile(const SystemString& filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief calculateChecksum
|
* @brief calculateChecksum
|
||||||
* @param data
|
* @param data
|
||||||
* @param len
|
* @param len
|
||||||
* @return
|
* @param checksum
|
||||||
|
* @param checksum
|
||||||
*/
|
*/
|
||||||
uint16_t calculateChecksum(void* data, size_t len);
|
void calculateChecksum(uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __CARD_HPP__
|
#endif // __CARD_HPP__
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
#ifndef SRAM_HPP
|
||||||
|
#define SRAM_HPP
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// Modified code taken from libogc
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------
|
||||||
|
system.h -- OS functions and initialization
|
||||||
|
Copyright (C) 2004
|
||||||
|
Michael Wiedenbauer (shagkur)
|
||||||
|
Dave Murphy (WinterMute)
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
1. The origin of this software must not be misrepresented; you
|
||||||
|
must not claim that you wrote the original software. If you use
|
||||||
|
this software in a product, an acknowledgment in the product
|
||||||
|
documentation would be appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
-------------------------------------------------------------*/
|
||||||
|
|
||||||
|
namespace kabufuda
|
||||||
|
{
|
||||||
|
#pragma pack(push,1)
|
||||||
|
union SRAMFlags
|
||||||
|
{
|
||||||
|
uint8_t Hex;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t : 2;
|
||||||
|
uint8_t sound : 1; // Audio settings; 0 = Mono, 1 = Stereo
|
||||||
|
uint8_t initialized : 1; // if 0, displays prompt to set language on boot and asks user to set options and time/date
|
||||||
|
uint8_t : 2;
|
||||||
|
uint8_t boot_menu : 1; // if 1, skips logo animation and boots into the system menu regardless of if there is a disc inserted
|
||||||
|
uint8_t progressive : 1; // if 1, automatically displays Progressive Scan prompt in games that support it
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
union SRAM
|
||||||
|
{
|
||||||
|
uint8_t p_SRAM[64];
|
||||||
|
struct // Stored configuration value from the system SRAM area
|
||||||
|
{
|
||||||
|
uint16_t checksum; // Holds the block checksum.
|
||||||
|
uint16_t checksum_inv; // Holds the inverse block checksum
|
||||||
|
uint32_t ead0; // Unknown attribute
|
||||||
|
uint32_t ead1; // Unknown attribute
|
||||||
|
uint32_t counter_bias; // Bias value for the realtime clock
|
||||||
|
int8_t display_offsetH; // Pixel offset for the VI
|
||||||
|
uint8_t ntd; // Unknown attribute
|
||||||
|
uint8_t lang; // Language of system
|
||||||
|
SRAMFlags flags; // Device and operations flag
|
||||||
|
|
||||||
|
// Stored configuration value from the extended SRAM area
|
||||||
|
uint8_t flash_id[2][12]; // flash_id[2][12] 96bit memorycard unlock flash ID
|
||||||
|
uint32_t wirelessKbd_id; // Device ID of last connected wireless keyboard
|
||||||
|
uint16_t wirelessPad_id[4]; // 16-bit device ID of last connected pad.
|
||||||
|
uint8_t dvderr_code; // last non-recoverable error from DVD interface
|
||||||
|
uint8_t __padding0; // reserved
|
||||||
|
uint8_t flashID_chksum[2]; // 8-bit checksum of unlock flash ID
|
||||||
|
uint32_t __padding1; // padding
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
extern const SRAM g_SRAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SRAM_HPP
|
|
@ -0,0 +1,310 @@
|
||||||
|
#ifndef __UTIL_HPP__
|
||||||
|
#define __UTIL_HPP__
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
#else
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#endif
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include "winsupport.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#undef bswap16
|
||||||
|
#undef bswap32
|
||||||
|
#undef bswap64
|
||||||
|
|
||||||
|
namespace kabufuda
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Type-sensitive byte swappers */
|
||||||
|
template <typename T>
|
||||||
|
static inline T bswap16(T val)
|
||||||
|
{
|
||||||
|
#if __GNUC__
|
||||||
|
return __builtin_bswap16(val);
|
||||||
|
#elif _WIN32
|
||||||
|
return _byteswap_ushort(val);
|
||||||
|
#else
|
||||||
|
return (val = (val << 8) | ((val >> 8) & 0xFF));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T bswap32(T val)
|
||||||
|
{
|
||||||
|
#if __GNUC__
|
||||||
|
return __builtin_bswap32(val);
|
||||||
|
#elif _WIN32
|
||||||
|
return _byteswap_ulong(val);
|
||||||
|
#else
|
||||||
|
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
|
||||||
|
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
|
||||||
|
return val;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T bswap64(T val)
|
||||||
|
{
|
||||||
|
#if __GNUC__
|
||||||
|
return __builtin_bswap64(val);
|
||||||
|
#elif _WIN32
|
||||||
|
return _byteswap_uint64(val);
|
||||||
|
#else
|
||||||
|
return ((val & 0xFF00000000000000ULL) >> 56) |
|
||||||
|
((val & 0x00FF000000000000ULL) >> 40) |
|
||||||
|
((val & 0x0000FF0000000000ULL) >> 24) |
|
||||||
|
((val & 0x000000FF00000000ULL) >> 8) |
|
||||||
|
((val & 0x00000000FF000000ULL) << 8) |
|
||||||
|
((val & 0x0000000000FF0000ULL) << 24) |
|
||||||
|
((val & 0x000000000000FF00ULL) << 40) |
|
||||||
|
((val & 0x00000000000000FFULL) << 56);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
static inline int16_t SBig(int16_t val) {return bswap16(val);}
|
||||||
|
static inline uint16_t SBig(uint16_t val) {return bswap16(val);}
|
||||||
|
static inline int32_t SBig(int32_t val) {return bswap32(val);}
|
||||||
|
static inline uint32_t SBig(uint32_t val) {return bswap32(val);}
|
||||||
|
static inline int64_t SBig(int64_t val) {return bswap64(val);}
|
||||||
|
static inline uint64_t SBig(uint64_t val) {return bswap64(val);}
|
||||||
|
static inline float SBig(float val)
|
||||||
|
{
|
||||||
|
int32_t ival = bswap32(*((int32_t*)(&val)));
|
||||||
|
return *((float*)(&ival));
|
||||||
|
}
|
||||||
|
static inline double SBig(double val)
|
||||||
|
{
|
||||||
|
int64_t ival = bswap64(*((int64_t*)(&val)));
|
||||||
|
return *((double*)(&ival));
|
||||||
|
}
|
||||||
|
#define SBIG(q) ( ( (q) & 0x000000FF ) << 24 | ( (q) & 0x0000FF00 ) << 8 \
|
||||||
|
| ( (q) & 0x00FF0000 ) >> 8 | ( (q) & 0xFF000000 ) >> 24 )
|
||||||
|
|
||||||
|
static inline int16_t SLittle(int16_t val) {return val;}
|
||||||
|
static inline uint16_t SLittle(uint16_t val) {return val;}
|
||||||
|
static inline int32_t SLittle(int32_t val) {return val;}
|
||||||
|
static inline uint32_t SLittle(uint32_t val) {return val;}
|
||||||
|
static inline int64_t SLittle(int64_t val) {return val;}
|
||||||
|
static inline uint64_t SLittle(uint64_t val) {return val;}
|
||||||
|
static inline float SLittle(float val) {return val;}
|
||||||
|
static inline double SLittle(double val) {return val;}
|
||||||
|
#define SLITTLE(q) (q)
|
||||||
|
#else
|
||||||
|
static inline int16_t SLittle(int16_t val) {return bswap16(val);}
|
||||||
|
static inline uint16_t SLittle(uint16_t val) {return bswap16(val);}
|
||||||
|
static inline int32_t SLittle(int32_t val) {return bswap32(val);}
|
||||||
|
static inline uint32_t SLittle(uint32_t val) {return bswap32(val);}
|
||||||
|
static inline int64_t SLittle(int64_t val) {return bswap64(val);}
|
||||||
|
static inline uint64_t SLittle(uint64_t val) {return bswap64(val);}
|
||||||
|
static inline float SLittle(float val)
|
||||||
|
{
|
||||||
|
int32_t ival = bswap32(*((int32_t*)(&val)));
|
||||||
|
return *((float*)(&ival));
|
||||||
|
}
|
||||||
|
static inline double SLittle(double val)
|
||||||
|
{
|
||||||
|
int64_t ival = bswap64(*((int64_t*)(&val)));
|
||||||
|
return *((double*)(&ival));
|
||||||
|
}
|
||||||
|
#define SLITTLE(q) ( ( (q) & 0x000000FF ) << 24 | ( (q) & 0x0000FF00 ) << 8 \
|
||||||
|
| ( (q) & 0x00FF0000 ) >> 8 | ( (q) & 0xFF000000 ) >> 24 )
|
||||||
|
|
||||||
|
static inline int16_t SBig(int16_t val) {return val;}
|
||||||
|
static inline uint16_t SBig(uint16_t val) {return val;}
|
||||||
|
static inline int32_t SBig(int32_t val) {return val;}
|
||||||
|
static inline uint32_t SBig(uint32_t val) {return val;}
|
||||||
|
static inline int64_t SBig(int64_t val) {return val;}
|
||||||
|
static inline uint64_t SBig(uint64_t val) {return val;}
|
||||||
|
static inline float SBig(float val) {return val;}
|
||||||
|
static inline double SBig(double val) {return val;}
|
||||||
|
#define SBIG(q) (q)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CARD_UCS2
|
||||||
|
typedef wchar_t SystemChar;
|
||||||
|
static inline size_t StrLen(const SystemChar* str) {return wcslen(str);}
|
||||||
|
typedef std::wstring SystemString;
|
||||||
|
static inline void ToLower(SystemString& str)
|
||||||
|
{std::transform(str.begin(), str.end(), str.begin(), towlower);}
|
||||||
|
static inline void ToUpper(SystemString& str)
|
||||||
|
{std::transform(str.begin(), str.end(), str.begin(), towupper);}
|
||||||
|
class SystemUTF8View
|
||||||
|
{
|
||||||
|
std::string m_utf8;
|
||||||
|
public:
|
||||||
|
explicit SystemUTF8View(const SystemString& str)
|
||||||
|
: m_utf8(WideToUTF8(str)) {}
|
||||||
|
operator const std::string&() const {return m_utf8;}
|
||||||
|
const std::string& str() const {return m_utf8;}
|
||||||
|
const char* c_str() const {return m_utf8.c_str();}
|
||||||
|
std::string operator+(const std::string& other) const {return m_utf8 + other;}
|
||||||
|
std::string operator+(const char* other) const {return m_utf8 + other;}
|
||||||
|
};
|
||||||
|
inline std::string operator+(const std::string& lhs, const SystemUTF8View& rhs) {return lhs + std::string(rhs);}
|
||||||
|
inline std::string operator+(const char* lhs, const SystemUTF8View& rhs) {return lhs + std::string(rhs);}
|
||||||
|
class SystemStringView
|
||||||
|
{
|
||||||
|
std::wstring m_sys;
|
||||||
|
public:
|
||||||
|
explicit SystemStringView(const std::string& str)
|
||||||
|
: m_sys(UTF8ToWide(str)) {}
|
||||||
|
operator const std::wstring&() const {return m_sys;}
|
||||||
|
const std::wstring& sys_str() const {return m_sys;}
|
||||||
|
const SystemChar* c_str() const {return m_sys.c_str();}
|
||||||
|
std::wstring operator+(const std::wstring& other) const {return m_sys + other;}
|
||||||
|
std::wstring operator+(const wchar_t* other) const {return m_sys + other;}
|
||||||
|
};
|
||||||
|
inline std::wstring operator+(const std::wstring& lhs, const SystemStringView& rhs) {return lhs + std::wstring(rhs);}
|
||||||
|
inline std::wstring operator+(const wchar_t* lhs, const SystemStringView& rhs) {return lhs + std::wstring(rhs);}
|
||||||
|
#ifndef _S
|
||||||
|
#define _S(val) L ## val
|
||||||
|
#endif
|
||||||
|
typedef struct _stat Sstat;
|
||||||
|
#else
|
||||||
|
typedef char SystemChar;
|
||||||
|
static inline size_t StrLen(const SystemChar* str) {return strlen(str);}
|
||||||
|
typedef std::string SystemString;
|
||||||
|
static inline void ToLower(SystemString& str)
|
||||||
|
{std::transform(str.begin(), str.end(), str.begin(), tolower);}
|
||||||
|
static inline void ToUpper(SystemString& str)
|
||||||
|
{std::transform(str.begin(), str.end(), str.begin(), toupper);}
|
||||||
|
class SystemUTF8View
|
||||||
|
{
|
||||||
|
const std::string& m_utf8;
|
||||||
|
public:
|
||||||
|
explicit SystemUTF8View(const SystemString& str)
|
||||||
|
: m_utf8(str) {}
|
||||||
|
operator const std::string&() const {return m_utf8;}
|
||||||
|
const std::string& str() const {return m_utf8;}
|
||||||
|
const char* c_str() const {return m_utf8.c_str();}
|
||||||
|
std::string operator+(const std::string& other) const {return std::string(m_utf8) + other;}
|
||||||
|
std::string operator+(const char* other) const {return std::string(m_utf8) + other;}
|
||||||
|
};
|
||||||
|
inline std::string operator+(const std::string& lhs, const SystemUTF8View& rhs) {return lhs + std::string(rhs);}
|
||||||
|
inline std::string operator+(const char* lhs, const SystemUTF8View& rhs) {return lhs + std::string(rhs);}
|
||||||
|
class SystemStringView
|
||||||
|
{
|
||||||
|
const std::string& m_sys;
|
||||||
|
public:
|
||||||
|
explicit SystemStringView(const std::string& str)
|
||||||
|
: m_sys(str) {}
|
||||||
|
operator const std::string&() const {return m_sys;}
|
||||||
|
const std::string& sys_str() const {return m_sys;}
|
||||||
|
const SystemChar* c_str() const {return m_sys.c_str();}
|
||||||
|
std::string operator+(const std::string& other) const {return m_sys + other;}
|
||||||
|
std::string operator+(const char* other) const {return m_sys + other;}
|
||||||
|
};
|
||||||
|
inline std::string operator+(const std::string& lhs, const SystemStringView& rhs) {return lhs + std::string(rhs);}
|
||||||
|
inline std::string operator+(const char* lhs, const SystemStringView& rhs) {return lhs + std::string(rhs);}
|
||||||
|
#ifndef _S
|
||||||
|
#define _S(val) val
|
||||||
|
#endif
|
||||||
|
typedef struct stat Sstat;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint64_t getGCTime();
|
||||||
|
|
||||||
|
enum class FileLockType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Read,
|
||||||
|
Write
|
||||||
|
};
|
||||||
|
static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock=FileLockType::None)
|
||||||
|
{
|
||||||
|
#if CARD_UCS2
|
||||||
|
FILE* fp = _wfopen(path, mode);
|
||||||
|
if (!fp)
|
||||||
|
return nullptr;
|
||||||
|
#else
|
||||||
|
FILE* fp = fopen(path, mode);
|
||||||
|
if (!fp)
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (lock != FileLockType::None)
|
||||||
|
{
|
||||||
|
#if _WIN32
|
||||||
|
OVERLAPPED ov = {};
|
||||||
|
LockFileEx((HANDLE)(uintptr_t)_fileno(fp), (lock == FileLockType::Write) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1, &ov);
|
||||||
|
#else
|
||||||
|
if (flock(fileno(fp), ((lock == FileLockType::Write) ? LOCK_EX : LOCK_SH) | LOCK_NB))
|
||||||
|
fprintf(stderr, "flock %s: %s", path, strerror(errno));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int FSeek(FILE* fp, int64_t offset, int whence)
|
||||||
|
{
|
||||||
|
#if _WIN32
|
||||||
|
return _fseeki64(fp, offset, whence);
|
||||||
|
#elif __APPLE__ || __FreeBSD__
|
||||||
|
return fseeko(fp, offset, whence);
|
||||||
|
#else
|
||||||
|
return fseeko64(fp, offset, whence);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int64_t FTell(FILE* fp)
|
||||||
|
{
|
||||||
|
#if _WIN32
|
||||||
|
return _ftelli64(fp);
|
||||||
|
#elif __APPLE__ || __FreeBSD__
|
||||||
|
return ftello(fp);
|
||||||
|
#else
|
||||||
|
return ftello64(fp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int Rename(const SystemChar* oldpath, const SystemChar* newpath)
|
||||||
|
{
|
||||||
|
#if CARD_UCS2
|
||||||
|
return _wrename(oldpath, newpath);
|
||||||
|
#else
|
||||||
|
return rename(oldpath, newpath);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int Stat(const SystemChar* path, Sstat* statOut)
|
||||||
|
{
|
||||||
|
#if CARD_UCS2
|
||||||
|
size_t pos;
|
||||||
|
for (pos=0 ; pos<3 && path[pos] != L'\0' ; ++pos) {}
|
||||||
|
if (pos == 2 && path[1] == L':')
|
||||||
|
{
|
||||||
|
SystemChar fixPath[4] = {path[0], L':', L'/', L'\0'};
|
||||||
|
return _wstat(fixPath, statOut);
|
||||||
|
}
|
||||||
|
return _wstat(path, statOut);
|
||||||
|
#else
|
||||||
|
return stat(path, statOut);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __UTIL_HPP__
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace kabufuda
|
||||||
|
{
|
||||||
|
std::string WideToUTF8(const std::wstring& src);
|
||||||
|
std::wstring UTF8ToWide(const std::string& src);
|
||||||
|
}
|
|
@ -0,0 +1,293 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009 Public Software Group e. V., Berlin, Germany
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mainpage
|
||||||
|
*
|
||||||
|
* utf8proc is a free/open-source (MIT/expat licensed) C library
|
||||||
|
* providing Unicode normalization, case-folding, and other operations
|
||||||
|
* for strings in the UTF-8 encoding, supporting Unicode version
|
||||||
|
* 7.0.0. See the utf8proc home page (http://julialang.org/utf8proc/)
|
||||||
|
* for downloads and other information, or the source code on github
|
||||||
|
* (https://github.com/JuliaLang/utf8proc).
|
||||||
|
*
|
||||||
|
* For the utf8proc API documentation, see: @ref utf8proc.h
|
||||||
|
*
|
||||||
|
* The features of utf8proc include:
|
||||||
|
*
|
||||||
|
* - Transformation of strings (@ref utf8proc_map) to:
|
||||||
|
* - decompose (@ref UTF8PROC_DECOMPOSE) or compose (@ref UTF8PROC_COMPOSE) Unicode combining characters (http://en.wikipedia.org/wiki/Combining_character)
|
||||||
|
* - canonicalize Unicode compatibility characters (@ref UTF8PROC_COMPAT)
|
||||||
|
* - strip "ignorable" (@ref UTF8PROC_IGNORE) characters, control characters (@ref UTF8PROC_STRIPCC), or combining characters such as accents (@ref UTF8PROC_STRIPMARK)
|
||||||
|
* - case-folding (@ref UTF8PROC_CASEFOLD)
|
||||||
|
* - Unicode normalization: @ref utf8proc_NFD, @ref utf8proc_NFC, @ref utf8proc_NFKD, @ref utf8proc_NFKC
|
||||||
|
* - Detecting grapheme boundaries (@ref utf8proc_grapheme_break and @ref UTF8PROC_CHARBOUND)
|
||||||
|
* - Character-width computation: @ref utf8proc_charwidth
|
||||||
|
* - Classification of characters by Unicode category: @ref utf8proc_category and @ref utf8proc_category_string
|
||||||
|
* - Encode (@ref utf8proc_encode_char) and decode (@ref utf8proc_iterate) Unicode codepoints to/from UTF-8.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file */
|
||||||
|
|
||||||
|
#ifndef UTF8PROC_H
|
||||||
|
#define UTF8PROC_H
|
||||||
|
|
||||||
|
/** @name API version
|
||||||
|
*
|
||||||
|
* The utf8proc API version MAJOR.MINOR.PATCH, following
|
||||||
|
* semantic-versioning rules (http://semver.org) based on API
|
||||||
|
* compatibility.
|
||||||
|
*
|
||||||
|
* This is also returned at runtime by @ref utf8proc_version; however, the
|
||||||
|
* runtime version may append a string like "-dev" to the version number
|
||||||
|
* for prerelease versions.
|
||||||
|
*
|
||||||
|
* @note The shared-library version number in the Makefile may be different,
|
||||||
|
* being based on ABI compatibility rather than API compatibility.
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
/** The MAJOR version number (increased when backwards API compatibility is broken). */
|
||||||
|
#define UTF8PROC_VERSION_MAJOR 1
|
||||||
|
/** The MINOR version number (increased when new functionality is added in a backwards-compatible manner). */
|
||||||
|
#define UTF8PROC_VERSION_MINOR 3
|
||||||
|
/** The PATCH version (increased for fixes that do not change the API). */
|
||||||
|
#define UTF8PROC_VERSION_PATCH 0
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef signed char utf8proc_int8_t;
|
||||||
|
typedef unsigned char utf8proc_uint8_t;
|
||||||
|
typedef short utf8proc_int16_t;
|
||||||
|
typedef unsigned short utf8proc_uint16_t;
|
||||||
|
typedef int utf8proc_int32_t;
|
||||||
|
typedef unsigned int utf8proc_uint32_t;
|
||||||
|
# ifdef _WIN64
|
||||||
|
typedef __int64 utf8proc_ssize_t;
|
||||||
|
typedef unsigned __int64 utf8proc_size_t;
|
||||||
|
# else
|
||||||
|
typedef int utf8proc_ssize_t;
|
||||||
|
typedef unsigned int utf8proc_size_t;
|
||||||
|
# endif
|
||||||
|
# ifndef __cplusplus
|
||||||
|
typedef unsigned char utf8proc_bool;
|
||||||
|
enum {false, true};
|
||||||
|
# else
|
||||||
|
typedef bool utf8proc_bool;
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# include <stdbool.h>
|
||||||
|
# include <inttypes.h>
|
||||||
|
typedef int8_t utf8proc_int8_t;
|
||||||
|
typedef uint8_t utf8proc_uint8_t;
|
||||||
|
typedef int16_t utf8proc_int16_t;
|
||||||
|
typedef uint16_t utf8proc_uint16_t;
|
||||||
|
typedef int32_t utf8proc_int32_t;
|
||||||
|
typedef uint32_t utf8proc_uint32_t;
|
||||||
|
typedef size_t utf8proc_size_t;
|
||||||
|
typedef ssize_t utf8proc_ssize_t;
|
||||||
|
typedef bool utf8proc_bool;
|
||||||
|
#endif
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
/** @name Error codes
|
||||||
|
* Error codes being returned by almost all functions.
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
/** Memory could not be allocated. */
|
||||||
|
#define UTF8PROC_ERROR_NOMEM -1
|
||||||
|
/** The given string is too long to be processed. */
|
||||||
|
#define UTF8PROC_ERROR_OVERFLOW -2
|
||||||
|
/** The given string is not a legal UTF-8 string. */
|
||||||
|
#define UTF8PROC_ERROR_INVALIDUTF8 -3
|
||||||
|
/** The @ref UTF8PROC_REJECTNA flag was set and an unassigned codepoint was found. */
|
||||||
|
#define UTF8PROC_ERROR_NOTASSIGNED -4
|
||||||
|
/** Invalid options have been used. */
|
||||||
|
#define UTF8PROC_ERROR_INVALIDOPTS -5
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#define UTF8PROC_cont(ch) (((ch) & 0xc0) == 0x80)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a single codepoint from the UTF-8 sequence being pointed to by `str`.
|
||||||
|
* The maximum number of bytes read is `strlen`, unless `strlen` is
|
||||||
|
* negative (in which case up to 4 bytes are read).
|
||||||
|
*
|
||||||
|
* If a valid codepoint could be read, it is stored in the variable
|
||||||
|
* pointed to by `codepoint_ref`, otherwise that variable will be set to -1.
|
||||||
|
* In case of success, the number of bytes read is returned; otherwise, a
|
||||||
|
* negative error code is returned.
|
||||||
|
*/
|
||||||
|
static inline utf8proc_ssize_t utf8proc_iterate(
|
||||||
|
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_int32_t *dst
|
||||||
|
) {
|
||||||
|
utf8proc_uint32_t uc;
|
||||||
|
const utf8proc_uint8_t *end;
|
||||||
|
|
||||||
|
*dst = -1;
|
||||||
|
if (!strlen) return 0;
|
||||||
|
end = str + ((strlen < 0) ? 4 : strlen);
|
||||||
|
uc = *str++;
|
||||||
|
if (uc < 0x80) {
|
||||||
|
*dst = uc;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Must be between 0xc2 and 0xf4 inclusive to be valid
|
||||||
|
if ((uc - 0xc2) > (0xf4-0xc2)) return UTF8PROC_ERROR_INVALIDUTF8;
|
||||||
|
if (uc < 0xe0) { // 2-byte sequence
|
||||||
|
// Must have valid continuation character
|
||||||
|
if (!UTF8PROC_cont(*str)) return UTF8PROC_ERROR_INVALIDUTF8;
|
||||||
|
*dst = ((uc & 0x1f)<<6) | (*str & 0x3f);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (uc < 0xf0) { // 3-byte sequence
|
||||||
|
if ((str + 1 >= end) || !UTF8PROC_cont(*str) || !UTF8PROC_cont(str[1]))
|
||||||
|
return UTF8PROC_ERROR_INVALIDUTF8;
|
||||||
|
// Check for surrogate chars
|
||||||
|
if (uc == 0xed && *str > 0x9f)
|
||||||
|
return UTF8PROC_ERROR_INVALIDUTF8;
|
||||||
|
uc = ((uc & 0xf)<<12) | ((*str & 0x3f)<<6) | (str[1] & 0x3f);
|
||||||
|
if (uc < 0x800)
|
||||||
|
return UTF8PROC_ERROR_INVALIDUTF8;
|
||||||
|
*dst = uc;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
// 4-byte sequence
|
||||||
|
// Must have 3 valid continuation characters
|
||||||
|
if ((str + 2 >= end) || !UTF8PROC_cont(*str) || !UTF8PROC_cont(str[1]) || !UTF8PROC_cont(str[2]))
|
||||||
|
return UTF8PROC_ERROR_INVALIDUTF8;
|
||||||
|
// Make sure in correct range (0x10000 - 0x10ffff)
|
||||||
|
if (uc == 0xf0) {
|
||||||
|
if (*str < 0x90) return UTF8PROC_ERROR_INVALIDUTF8;
|
||||||
|
} else if (uc == 0xf4) {
|
||||||
|
if (*str > 0x8f) return UTF8PROC_ERROR_INVALIDUTF8;
|
||||||
|
}
|
||||||
|
*dst = ((uc & 7)<<18) | ((*str & 0x3f)<<12) | ((str[1] & 0x3f)<<6) | (str[2] & 0x3f);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes the codepoint as an UTF-8 string in the byte array pointed
|
||||||
|
* to by `dst`. This array must be at least 4 bytes long.
|
||||||
|
*
|
||||||
|
* In case of success the number of bytes written is returned, and
|
||||||
|
* otherwise 0 is returned.
|
||||||
|
*
|
||||||
|
* This function does not check whether `codepoint` is valid Unicode.
|
||||||
|
*/
|
||||||
|
static inline utf8proc_ssize_t utf8proc_encode_char(utf8proc_int32_t uc, utf8proc_uint8_t *dst) {
|
||||||
|
if (uc < 0x00) {
|
||||||
|
return 0;
|
||||||
|
} else if (uc < 0x80) {
|
||||||
|
dst[0] = uc;
|
||||||
|
return 1;
|
||||||
|
} else if (uc < 0x800) {
|
||||||
|
dst[0] = 0xC0 + (uc >> 6);
|
||||||
|
dst[1] = 0x80 + (uc & 0x3F);
|
||||||
|
return 2;
|
||||||
|
// Note: we allow encoding 0xd800-0xdfff here, so as not to change
|
||||||
|
// the API, however, these are actually invalid in UTF-8
|
||||||
|
} else if (uc < 0x10000) {
|
||||||
|
dst[0] = 0xE0 + (uc >> 12);
|
||||||
|
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
|
||||||
|
dst[2] = 0x80 + (uc & 0x3F);
|
||||||
|
return 3;
|
||||||
|
} else if (uc < 0x110000) {
|
||||||
|
dst[0] = 0xF0 + (uc >> 18);
|
||||||
|
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
|
||||||
|
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
|
||||||
|
dst[3] = 0x80 + (uc & 0x3F);
|
||||||
|
return 4;
|
||||||
|
} else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <iterator>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class UTF8Iterator : public std::iterator<std::forward_iterator_tag, uint32_t>
|
||||||
|
{
|
||||||
|
std::string::const_iterator m_it;
|
||||||
|
public:
|
||||||
|
UTF8Iterator(const std::string::const_iterator& it) : m_it(it) {}
|
||||||
|
UTF8Iterator& operator+=(size_t v)
|
||||||
|
{
|
||||||
|
for (size_t i=0 ; i<v ; ++i)
|
||||||
|
{
|
||||||
|
utf8proc_int32_t dummy;
|
||||||
|
utf8proc_ssize_t sz = utf8proc_iterate(reinterpret_cast<const utf8proc_uint8_t*>(&*m_it), -1, &dummy);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
if (*m_it == '\0')
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR! UTF8-iterator null-term fail\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
else if (sz > 0)
|
||||||
|
m_it += sz;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR! UTF8Iterator character fail");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (sz > 0)
|
||||||
|
m_it += sz;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
UTF8Iterator& operator++()
|
||||||
|
{
|
||||||
|
return this->operator+=(1);
|
||||||
|
}
|
||||||
|
UTF8Iterator operator+(size_t v) const
|
||||||
|
{
|
||||||
|
UTF8Iterator ret(m_it);
|
||||||
|
ret += v;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
uint32_t operator*() const
|
||||||
|
{
|
||||||
|
utf8proc_int32_t ret;
|
||||||
|
utf8proc_iterate(reinterpret_cast<const utf8proc_uint8_t*>(&*m_it), -1, &ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
std::string::const_iterator iter() const {return m_it;}
|
||||||
|
size_t countTo(std::string::const_iterator end) const
|
||||||
|
{
|
||||||
|
UTF8Iterator it(m_it);
|
||||||
|
size_t ret = 0;
|
||||||
|
while (it.iter() < end)
|
||||||
|
{
|
||||||
|
++ret;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
125
src/Card.cpp
125
src/Card.cpp
|
@ -1,22 +1,43 @@
|
||||||
#include "Card.hpp"
|
#include "Card.hpp"
|
||||||
|
#include "SRAM.hpp"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace card
|
namespace kabufuda
|
||||||
{
|
{
|
||||||
Card::Card()
|
Card::Card()
|
||||||
{
|
{
|
||||||
memset(__raw, 0xFF, BlockSize);
|
memset(__raw, 0xFF, BlockSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
Card::Card(const std::string &filepath, const char* game, const char* maker)
|
Card::Card(const SystemString& filename, const char* game, const char* maker)
|
||||||
: m_filepath(filepath)
|
: m_filename(filename)
|
||||||
{
|
{
|
||||||
memset(__raw, 0xFF, BlockSize);
|
memset(__raw, 0xFF, BlockSize);
|
||||||
if (game && strlen(game) == 4)
|
if (game && strlen(game) == 4)
|
||||||
memcpy(m_game, game, 4);
|
memcpy(m_game, game, 4);
|
||||||
if (maker && strlen(maker) == 2)
|
if (maker && strlen(maker) == 2)
|
||||||
memcpy(m_maker, maker, 2);
|
memcpy(m_maker, maker, 2);
|
||||||
|
|
||||||
|
m_fileHandle = Fopen(m_filename.c_str(), _S("rb"));
|
||||||
|
if (m_fileHandle)
|
||||||
|
{
|
||||||
|
fread(__raw, 1, BlockSize, m_fileHandle);
|
||||||
|
fread(m_dir.__raw, 1, BlockSize, m_fileHandle);
|
||||||
|
fread(m_dirBackup.__raw, 1, BlockSize, m_fileHandle);
|
||||||
|
fread(m_bat.__raw, 1, BlockSize, m_fileHandle);
|
||||||
|
fread(m_batBackup.__raw, 1, BlockSize, m_fileHandle);
|
||||||
|
if (m_dir.m_updateCounter < m_dirBackup.m_updateCounter)
|
||||||
|
m_dirInUse = &m_dirBackup;
|
||||||
|
else
|
||||||
|
m_dirInUse = &m_dir;
|
||||||
|
|
||||||
|
if (m_bat.m_updateCounter < m_batBackup.m_updateCounter)
|
||||||
|
m_batInUse = &m_batBackup;
|
||||||
|
else
|
||||||
|
m_batInUse = &m_bat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Card::~Card()
|
Card::~Card()
|
||||||
|
@ -86,23 +107,105 @@ void Card::getChecksum(uint16_t* checksum, uint16_t* inverse)
|
||||||
*inverse = m_checksumInv;
|
*inverse = m_checksumInv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::format(ECardSize size)
|
void Card::format(EDeviceId id, ECardSize size, EEncoding encoding)
|
||||||
{
|
{
|
||||||
|
memset(__raw, 0xFF, BlockSize);
|
||||||
|
uint64_t rand = uint64_t(getGCTime());
|
||||||
|
m_formatTime = SBig(rand);
|
||||||
|
for (int i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
rand = (((rand * (uint64_t)0x41c64e6d) + (uint64_t)0x3039) >> 16);
|
||||||
|
m_serial[i] = (uint8_t)(g_SRAM.flash_id[uint32_t(id)][i] + (uint32_t)rand);
|
||||||
|
rand = (((rand * (uint64_t)0x41c64e6d) + (uint64_t)0x3039) >> 16);
|
||||||
|
rand &= (uint64_t)0x7fffULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sramBias = g_SRAM.counter_bias;
|
||||||
|
m_sramLanguage = SBig(g_SRAM.lang);
|
||||||
|
m_unknown = 0; /* 1 works for slot A, 0 both */
|
||||||
|
m_deviceId = 0;
|
||||||
|
m_sizeMb = SBig(uint16_t(size));
|
||||||
|
m_encoding = SBig(uint16_t(encoding));
|
||||||
|
calculateChecksum((uint16_t*)__raw, 0xFE, &m_checksum, &m_checksumInv);
|
||||||
|
m_dir = Directory();
|
||||||
|
m_dirBackup = m_dir;
|
||||||
|
m_dirInUse = &m_dir;
|
||||||
|
m_bat = BlockAllocationTable(uint32_t(size) * MbitToBlocks);
|
||||||
|
m_batBackup = m_bat;
|
||||||
|
m_batInUse = &m_bat;
|
||||||
|
m_sizeMb = SBig(uint16_t(size));
|
||||||
|
m_encoding = SBig(uint16_t(encoding));
|
||||||
|
|
||||||
|
FILE* f = Fopen(m_filename.c_str(), _S("wb"));
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
fwrite(__raw, 1, BlockSize, f);
|
||||||
|
fwrite(m_dir.__raw, 1, BlockSize, f);
|
||||||
|
fwrite(m_dirBackup.__raw, 1, BlockSize, f);
|
||||||
|
fwrite(m_bat.__raw, 1, BlockSize, f);
|
||||||
|
fwrite(m_batBackup.__raw, 1, BlockSize, f);
|
||||||
|
uint32_t dataLen = ((uint32_t(size) * MbitToBlocks) - 5) * BlockSize;
|
||||||
|
std::unique_ptr<char[]> data(new char[dataLen]);
|
||||||
|
memset(data.get(), 0xFF, dataLen);
|
||||||
|
fwrite(data.get(), 1, dataLen, f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::format()
|
uint32_t Card::getSizeMbitFromFile(const SystemString& filename)
|
||||||
{
|
{
|
||||||
FILE* file = fopen(m_filename.c_str(), "wb");
|
Sstat stat;
|
||||||
|
Stat(filename.c_str(), &stat);
|
||||||
|
return (stat.st_size / BlockSize) / MbitToBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t calculateChecksum(void* data, size_t len)
|
File::File(char data[])
|
||||||
{
|
{
|
||||||
uint16_t ret = 0;
|
memcpy(__raw, data, 0x40);
|
||||||
for (size_t i = 0; i < len; ++i)
|
}
|
||||||
ret += *(uint8_t*)(reinterpret_cast<uint8_t*>(data) + i);
|
|
||||||
|
|
||||||
return ret;
|
File::File(const char* filename)
|
||||||
|
{
|
||||||
|
memset(m_filename, 0, 0x20);
|
||||||
|
memcpy(m_filename, filename, 32 - strlen(filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockAllocationTable::BlockAllocationTable(uint32_t blockCount)
|
||||||
|
{
|
||||||
|
memset(__raw, 0, BlockSize);
|
||||||
|
m_freeBlocks = SBig(uint16_t(blockCount - 5));
|
||||||
|
m_lastAllocated = SBig(uint16_t(4));
|
||||||
|
calculateChecksum((uint16_t*)(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory::Directory()
|
||||||
|
{
|
||||||
|
memset(__raw, 0xFF, BlockSize);
|
||||||
|
m_updateCounter = 0;
|
||||||
|
calculateChecksum((uint16_t*)__raw, 0xFFE, &m_checksum, &m_checksumInv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory::Directory(uint8_t data[])
|
||||||
|
{
|
||||||
|
memcpy((uint16_t*)__raw, data, BlockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void calculateChecksum(uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv)
|
||||||
|
{
|
||||||
|
*checksum = 0;
|
||||||
|
*checksumInv = 0;
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
*checksum += SBig(data[i]);
|
||||||
|
*checksumInv += SBig(uint16_t(data[i] ^ 0xFFFF));
|
||||||
|
}
|
||||||
|
*checksum = SBig(uint16_t(*checksum));
|
||||||
|
*checksumInv = SBig(uint16_t(*checksumInv));
|
||||||
|
if (*checksum == 0xFFFF)
|
||||||
|
*checksum = 0;
|
||||||
|
if (*checksumInv == 0xFFFF)
|
||||||
|
*checksumInv = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
#include "SRAM.hpp"
|
||||||
|
|
||||||
|
namespace kabufuda
|
||||||
|
{
|
||||||
|
const SRAM g_SRAM =
|
||||||
|
{{
|
||||||
|
0xFF, 0x6B,
|
||||||
|
0x00, 0x91,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xFF, 0xFF, 0xFF, 0x40,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x2C,
|
||||||
|
0x41, 0x58, 0x49, 0x4F, 0x44, 0x4C, 0x5F, 0x53, 0x4C, 0x4F, 0x54, 0x41,
|
||||||
|
0x41, 0x58, 0x49, 0x4F, 0x44, 0x4C, 0x5F, 0x53, 0x4C, 0x4F, 0x54, 0x42,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x6E, 0x6D,
|
||||||
|
0x00, 0x00,
|
||||||
|
0x00, 0x00
|
||||||
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#include "Util.hpp"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
namespace kabufuda
|
||||||
|
{
|
||||||
|
uint64_t getGCTime()
|
||||||
|
{
|
||||||
|
time_t sysTime, tzDiff, tzDST;
|
||||||
|
struct tm * gmTime;
|
||||||
|
|
||||||
|
time(&sysTime);
|
||||||
|
|
||||||
|
// Account for DST where needed
|
||||||
|
gmTime = localtime(&sysTime);
|
||||||
|
if (gmTime->tm_isdst == 1)
|
||||||
|
tzDST = 3600;
|
||||||
|
else
|
||||||
|
tzDST = 0;
|
||||||
|
|
||||||
|
// Lazy way to get local time in sec
|
||||||
|
gmTime = gmtime(&sysTime);
|
||||||
|
tzDiff = sysTime - mktime(gmTime);
|
||||||
|
|
||||||
|
return (uint64_t)(sysTime + tzDiff + tzDST) - 0x386D4380;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#include "WideStringConvert.hpp"
|
||||||
|
#include "utf8proc.h"
|
||||||
|
|
||||||
|
namespace kabufuda
|
||||||
|
{
|
||||||
|
std::string WideToUTF8(const std::wstring& src)
|
||||||
|
{
|
||||||
|
std::string retval;
|
||||||
|
retval.reserve(src.length());
|
||||||
|
for (wchar_t ch : src)
|
||||||
|
{
|
||||||
|
utf8proc_uint8_t mb[4];
|
||||||
|
utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb);
|
||||||
|
if (c < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "invalid UTF-8 character while encoding");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
retval.append(reinterpret_cast<char*>(mb), c);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring UTF8ToWide(const std::string& src)
|
||||||
|
{
|
||||||
|
std::wstring retval;
|
||||||
|
retval.reserve(src.length());
|
||||||
|
const utf8proc_uint8_t* buf = reinterpret_cast<const utf8proc_uint8_t*>(src.c_str());
|
||||||
|
while (*buf)
|
||||||
|
{
|
||||||
|
utf8proc_int32_t wc;
|
||||||
|
utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc);
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "invalid UTF-8 character while decoding");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
buf += len;
|
||||||
|
retval += wchar_t(wc);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,4 +3,4 @@ add_executable(cardtest
|
||||||
main.cpp)
|
main.cpp)
|
||||||
|
|
||||||
target_link_libraries(cardtest
|
target_link_libraries(cardtest
|
||||||
card)
|
kabufuda)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
card::Card card{"test.mc"};
|
kabufuda::Card mc{_S("test.USA.raw")};
|
||||||
|
mc.format(kabufuda::EDeviceId::SlotA, kabufuda::ECardSize::Card123Mb);
|
||||||
|
printf("File Mbit %x\n", kabufuda::Card::getSizeMbitFromFile(_S("test.USA.raw")));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue